Merge pull request #3021 from mthom/rebis-dev
Merge rebis-dev to master
This commit is contained in:
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@@ -2,7 +2,9 @@ name: CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches:
|
||||||
|
- master
|
||||||
|
- rebis-dev
|
||||||
tags:
|
tags:
|
||||||
- "v**"
|
- "v**"
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -47,8 +49,7 @@ jobs:
|
|||||||
# FIXME(issue #2138): run wasm tests, failing to run since https://github.com/mthom/scryer-prolog/pull/2137 removed wasm-pack
|
# FIXME(issue #2138): run wasm tests, failing to run since https://github.com/mthom/scryer-prolog/pull/2137 removed wasm-pack
|
||||||
- { os: ubuntu-22.04, rust-version: nightly, target: 'wasm32-unknown-unknown', publish: true, args: '--no-default-features' , test-args: '--no-run --no-default-features', use_swap: true }
|
- { os: ubuntu-22.04, rust-version: nightly, target: 'wasm32-unknown-unknown', publish: true, args: '--no-default-features' , test-args: '--no-run --no-default-features', use_swap: true }
|
||||||
# Cargo.toml rust-version
|
# Cargo.toml rust-version
|
||||||
- { os: ubuntu-22.04, rust-version: "1.85", target: 'x86_64-unknown-linux-gnu'}
|
- { os: ubuntu-22.04, rust-version: "1.87", target: 'x86_64-unknown-linux-gnu'}
|
||||||
# rust versions
|
|
||||||
- { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'}
|
- { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'}
|
||||||
- { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu', miri: true, components: "miri"}
|
- { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu', miri: true, components: "miri"}
|
||||||
defaults:
|
defaults:
|
||||||
|
|||||||
13
Cargo.lock
generated
13
Cargo.lock
generated
@@ -1673,9 +1673,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.12"
|
version = "0.4.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
@@ -2011,9 +2011,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.3"
|
version = "0.12.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
@@ -2021,9 +2021,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot_core"
|
name = "parking_lot_core"
|
||||||
version = "0.9.10"
|
version = "0.9.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -2712,6 +2712,7 @@ dependencies = [
|
|||||||
"num-order",
|
"num-order",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
"ouroboros",
|
"ouroboros",
|
||||||
|
"parking_lot",
|
||||||
"phf",
|
"phf",
|
||||||
"pprof",
|
"pprof",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ keywords = ["prolog", "prolog-interpreter", "prolog-system"]
|
|||||||
categories = ["command-line-utilities"]
|
categories = ["command-line-utilities"]
|
||||||
build = "build/main.rs"
|
build = "build/main.rs"
|
||||||
# Remember to check CI
|
# Remember to check CI
|
||||||
rust-version = "1.85"
|
rust-version = "1.87"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
@@ -79,6 +79,7 @@ ego-tree = "0.10.0"
|
|||||||
|
|
||||||
serde_json = "1.0.122"
|
serde_json = "1.0.122"
|
||||||
serde = "1.0.204"
|
serde = "1.0.204"
|
||||||
|
parking_lot = "0.12.4"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
crossterm = { version = "0.28.1", optional = true }
|
crossterm = { version = "0.28.1", optional = true }
|
||||||
@@ -136,6 +137,7 @@ opt-level = 3
|
|||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
debug = 2
|
||||||
|
|
||||||
[profile.wasm-dev]
|
[profile.wasm-dev]
|
||||||
inherits = "dev"
|
inherits = "dev"
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
(`atom`, `var`, etc) with if/else ladders. (_in progress_)
|
(`atom`, `var`, etc) with if/else ladders. (_in progress_)
|
||||||
- [ ] Inlining all built-ins and system call instructions.
|
- [ ] Inlining all built-ins and system call instructions.
|
||||||
- [x] Greatly reducing the number of instructions used to compile disjunctives.
|
- [x] Greatly reducing the number of instructions used to compile disjunctives.
|
||||||
- [ ] Storing short atoms to heap cells without writing them to the atom table.
|
- [x] Storing short atoms to heap cells without writing them to the atom table.
|
||||||
- [ ] A compacting garbage collector satisfying the five properties of
|
- [ ] A compacting garbage collector satisfying the five properties of
|
||||||
"[Precise Garbage Collection in Prolog](https://www.complang.tuwien.ac.at/ulrich/papers/PDF/2008-ciclops.pdf)." (_in progress_)
|
"[Precise Garbage Collection in Prolog](https://www.complang.tuwien.ac.at/ulrich/papers/PDF/2008-ciclops.pdf)." (_in progress_)
|
||||||
- [ ] Mode declarations.
|
- [ ] Mode declarations.
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use to_syn_value_derive::ToDeriveInput;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use std::any::*;
|
use std::any::*;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
struct ArithmeticTerm;
|
struct ArithmeticTerm;
|
||||||
@@ -28,6 +29,7 @@ struct Death;
|
|||||||
struct HeapCellValue;
|
struct HeapCellValue;
|
||||||
struct IndexingLine;
|
struct IndexingLine;
|
||||||
struct Level;
|
struct Level;
|
||||||
|
// struct Literal;
|
||||||
struct NextOrFail;
|
struct NextOrFail;
|
||||||
struct RegType;
|
struct RegType;
|
||||||
|
|
||||||
@@ -535,6 +537,16 @@ enum SystemClauseType {
|
|||||||
UnsetEnv,
|
UnsetEnv,
|
||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$shell")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$shell")))]
|
||||||
Shell,
|
Shell,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "8", Name = "$process_create")))]
|
||||||
|
ProcessCreate,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$process_id")))]
|
||||||
|
ProcessId,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$process_wait")))]
|
||||||
|
ProcessWait,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$process_kill")))]
|
||||||
|
ProcessKill,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$process_release")))]
|
||||||
|
ProcessRelease,
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$pid")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$pid")))]
|
||||||
Pid,
|
Pid,
|
||||||
#[strum_discriminants(strum(props(Arity = "4", Name = "$chars_base64")))]
|
#[strum_discriminants(strum(props(Arity = "4", Name = "$chars_base64")))]
|
||||||
@@ -622,7 +634,7 @@ enum InstructionTemplate {
|
|||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "get_list")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "get_list")))]
|
||||||
GetList(Level, RegType),
|
GetList(Level, RegType),
|
||||||
#[strum_discriminants(strum(props(Arity = "4", Name = "get_partial_string")))]
|
#[strum_discriminants(strum(props(Arity = "4", Name = "get_partial_string")))]
|
||||||
GetPartialString(Level, Atom, RegType, bool),
|
GetPartialString(Level, Rc<String>, RegType),
|
||||||
#[strum_discriminants(strum(props(Arity = "3", Name = "get_structure")))]
|
#[strum_discriminants(strum(props(Arity = "3", Name = "get_structure")))]
|
||||||
GetStructure(Level, Atom, usize, RegType),
|
GetStructure(Level, Atom, usize, RegType),
|
||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))]
|
||||||
@@ -645,7 +657,7 @@ enum InstructionTemplate {
|
|||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "put_list")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "put_list")))]
|
||||||
PutList(Level, RegType),
|
PutList(Level, RegType),
|
||||||
#[strum_discriminants(strum(props(Arity = "4", Name = "put_partial_string")))]
|
#[strum_discriminants(strum(props(Arity = "4", Name = "put_partial_string")))]
|
||||||
PutPartialString(Level, Atom, RegType, bool),
|
PutPartialString(Level, Rc<String>, RegType),
|
||||||
#[strum_discriminants(strum(props(Arity = "3", Name = "put_structure")))]
|
#[strum_discriminants(strum(props(Arity = "3", Name = "put_structure")))]
|
||||||
PutStructure(Atom, usize, RegType),
|
PutStructure(Atom, usize, RegType),
|
||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "put_unsafe_value")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "put_unsafe_value")))]
|
||||||
@@ -875,6 +887,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
use crate::arithmetic::*;
|
use crate::arithmetic::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
|
use crate::functor_macro::*;
|
||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
use crate::machine::machine_errors::MachineStub;
|
use crate::machine::machine_errors::MachineStub;
|
||||||
use crate::machine::machine_indices::CodeIndex;
|
use crate::machine::machine_indices::CodeIndex;
|
||||||
@@ -885,6 +898,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn reg_type_into_functor(r: RegType) -> MachineStub {
|
fn reg_type_into_functor(r: RegType) -> MachineStub {
|
||||||
match r {
|
match r {
|
||||||
@@ -896,9 +910,9 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
impl Level {
|
impl Level {
|
||||||
fn into_functor(self) -> MachineStub {
|
fn into_functor(self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
Level::Root => functor!(atom!("level"), [atom(atom!("root"))]),
|
Level::Root => functor!(atom!("level"), [atom_as_cell((atom!("root")))]),
|
||||||
Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]),
|
Level::Shallow => functor!(atom!("level"), [atom_as_cell((atom!("shallow")))]),
|
||||||
Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]),
|
Level::Deep => functor!(atom!("level"), [atom_as_cell((atom!("deep")))]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -911,7 +925,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
functor!(atom!("intermediate"), [fixnum(i)])
|
functor!(atom!("intermediate"), [fixnum(i)])
|
||||||
}
|
}
|
||||||
ArithmeticTerm::Number(n) => {
|
ArithmeticTerm::Number(n) => {
|
||||||
vec![HeapCellValue::from((n, arena))]
|
functor!(atom!("number"), [number(n, arena)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -996,7 +1010,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
IndexingCodePtr,
|
IndexingCodePtr,
|
||||||
IndexingCodePtr,
|
IndexingCodePtr,
|
||||||
),
|
),
|
||||||
SwitchOnConstant(IndexMap<Literal, IndexingCodePtr, FxBuildHasher>),
|
SwitchOnConstant(IndexMap<HeapCellValue, IndexingCodePtr, FxBuildHasher>),
|
||||||
SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>),
|
SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,7 +1030,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]),
|
IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]),
|
||||||
IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]),
|
IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]),
|
||||||
IndexingCodePtr::Fail => {
|
IndexingCodePtr::Fail => {
|
||||||
vec![atom_as_cell!(atom!("fail"))]
|
functor!(atom!("fail"))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1030,80 +1044,43 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IndexingInstruction {
|
impl IndexingInstruction {
|
||||||
pub fn to_functor(&self, mut h: usize) -> MachineStub {
|
pub fn to_functor(&self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
|
&IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
|
||||||
functor!(
|
functor!(
|
||||||
atom!("switch_on_term"),
|
atom!("switch_on_term"),
|
||||||
[
|
[
|
||||||
fixnum(arg),
|
fixnum(arg),
|
||||||
indexing_code_ptr(h, vars),
|
indexing_code_ptr(vars),
|
||||||
indexing_code_ptr(h, constants),
|
indexing_code_ptr(constants),
|
||||||
indexing_code_ptr(h, lists),
|
indexing_code_ptr(lists),
|
||||||
indexing_code_ptr(h, structures)
|
indexing_code_ptr(structures)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
IndexingInstruction::SwitchOnConstant(constants) => {
|
IndexingInstruction::SwitchOnConstant(constants) => {
|
||||||
let mut key_value_list_stub = vec![];
|
variadic_functor(
|
||||||
let orig_h = h;
|
atom!("switch_on_constants"),
|
||||||
|
1,
|
||||||
h += 2; // skip the 2-cell "switch_on_constant" functor.
|
constants.iter().map(|(c, ptr)| {
|
||||||
|
functor!(
|
||||||
for (c, ptr) in constants.iter() {
|
atom!(":"),
|
||||||
let key_value_pair = functor!(
|
[cell((*c)), indexing_code_ptr((*ptr))]
|
||||||
atom!(":"),
|
)
|
||||||
[literal(*c), indexing_code_ptr(h + 3, *ptr)]
|
}),
|
||||||
);
|
|
||||||
|
|
||||||
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(empty_list_as_cell!());
|
|
||||||
|
|
||||||
functor!(
|
|
||||||
atom!("switch_on_constant"),
|
|
||||||
[str(orig_h, 0)],
|
|
||||||
[key_value_list_stub]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
IndexingInstruction::SwitchOnStructure(structures) => {
|
IndexingInstruction::SwitchOnStructure(structures) => {
|
||||||
let mut key_value_list_stub = vec![];
|
variadic_functor(
|
||||||
let orig_h = h;
|
|
||||||
|
|
||||||
h += 2; // skip the 2-cell "switch_on_constant" functor.
|
|
||||||
|
|
||||||
for ((name, arity), ptr) in structures.iter() {
|
|
||||||
let predicate_indicator_stub = functor!(
|
|
||||||
atom!("/"),
|
|
||||||
[atom(name), fixnum(*arity)]
|
|
||||||
);
|
|
||||||
|
|
||||||
let key_value_pair = functor!(
|
|
||||||
atom!(":"),
|
|
||||||
[str(h + 3, 0), indexing_code_ptr(h + 3, *ptr)],
|
|
||||||
[predicate_indicator_stub]
|
|
||||||
);
|
|
||||||
|
|
||||||
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(empty_list_as_cell!());
|
|
||||||
|
|
||||||
functor!(
|
|
||||||
atom!("switch_on_structure"),
|
atom!("switch_on_structure"),
|
||||||
[str(orig_h, 0)],
|
1,
|
||||||
[key_value_list_stub]
|
structures.iter().map(|((name, arity), ptr)| {
|
||||||
|
functor!(
|
||||||
|
atom!(":"),
|
||||||
|
[functor((atom!("/")), [atom_as_cell(name), fixnum((*arity))]),
|
||||||
|
indexing_code_ptr((*ptr))]
|
||||||
|
)
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1133,18 +1110,16 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn arith_instr_unary_functor(
|
fn arith_instr_unary_functor(
|
||||||
h: usize,
|
|
||||||
name: Atom,
|
name: Atom,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
at: &ArithmeticTerm,
|
at: &ArithmeticTerm,
|
||||||
t: usize,
|
t: usize,
|
||||||
) -> MachineStub {
|
) -> MachineStub {
|
||||||
let at_stub = at.into_functor(arena);
|
let at_stub = at.into_functor(arena);
|
||||||
functor!(name, [str(h, 0), fixnum(t)], [at_stub])
|
functor!(name, [functor(at_stub), fixnum(t)])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arith_instr_bin_functor(
|
fn arith_instr_bin_functor(
|
||||||
h: usize,
|
|
||||||
name: Atom,
|
name: Atom,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
at_1: &ArithmeticTerm,
|
at_1: &ArithmeticTerm,
|
||||||
@@ -1154,11 +1129,9 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
let at_1_stub = at_1.into_functor(arena);
|
let at_1_stub = at_1.into_functor(arena);
|
||||||
let at_2_stub = at_2.into_functor(arena);
|
let at_2_stub = at_2.into_functor(arena);
|
||||||
|
|
||||||
functor!(
|
functor!(name, [functor(at_1_stub),
|
||||||
name,
|
functor(at_2_stub),
|
||||||
[str(h, 0), str(h, 1), fixnum(t)],
|
fixnum(t)])
|
||||||
[at_1_stub, at_2_stub]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Code = Vec<Instruction>;
|
pub type Code = Vec<Instruction>;
|
||||||
@@ -1170,7 +1143,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
match *self {
|
match *self {
|
||||||
Instruction::GetConstant(_, _, r) => vec![r],
|
Instruction::GetConstant(_, _, r) => vec![r],
|
||||||
Instruction::GetList(_, r) => vec![r],
|
Instruction::GetList(_, r) => vec![r],
|
||||||
Instruction::GetPartialString(_, _, r, _) => vec![r],
|
Instruction::GetPartialString(_, _, r) => vec![r],
|
||||||
Instruction::GetStructure(_, _, _, r) => vec![r],
|
Instruction::GetStructure(_, _, _, r) => vec![r],
|
||||||
Instruction::GetVariable(r, t) => vec![r, temp_v!(t)],
|
Instruction::GetVariable(r, t) => vec![r, temp_v!(t)],
|
||||||
Instruction::GetValue(r, t) => vec![r, temp_v!(t)],
|
Instruction::GetValue(r, t) => vec![r, temp_v!(t)],
|
||||||
@@ -1178,7 +1151,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
Instruction::UnifyVariable(r) => vec![r],
|
Instruction::UnifyVariable(r) => vec![r],
|
||||||
Instruction::PutConstant(_, _, r) => vec![r],
|
Instruction::PutConstant(_, _, r) => vec![r],
|
||||||
Instruction::PutList(_, r) => vec![r],
|
Instruction::PutList(_, r) => vec![r],
|
||||||
Instruction::PutPartialString(_, _, r, _) => vec![r],
|
Instruction::PutPartialString(_, _, r) => vec![r],
|
||||||
Instruction::PutStructure(_, _, r) => vec![r],
|
Instruction::PutStructure(_, _, r) => vec![r],
|
||||||
Instruction::PutValue(r, t) => vec![r, temp_v!(t)],
|
Instruction::PutValue(r, t) => vec![r, temp_v!(t)],
|
||||||
Instruction::PutVariable(r, t) => vec![r, temp_v!(t)],
|
Instruction::PutVariable(r, t) => vec![r, temp_v!(t)],
|
||||||
@@ -1242,7 +1215,6 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
|
|
||||||
pub fn enqueue_functors(
|
pub fn enqueue_functors(
|
||||||
&self,
|
&self,
|
||||||
mut h: usize,
|
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
functors: &mut Vec<MachineStub>,
|
functors: &mut Vec<MachineStub>,
|
||||||
) {
|
) {
|
||||||
@@ -1251,33 +1223,30 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
for indexing_instr in indexing_instrs {
|
for indexing_instr in indexing_instrs {
|
||||||
match indexing_instr {
|
match indexing_instr {
|
||||||
IndexingLine::Indexing(indexing_instr) => {
|
IndexingLine::Indexing(indexing_instr) => {
|
||||||
let section = indexing_instr.to_functor(h);
|
let section = indexing_instr.to_functor();
|
||||||
h += section.len();
|
|
||||||
functors.push(section);
|
functors.push(section);
|
||||||
}
|
}
|
||||||
IndexingLine::IndexedChoice(indexed_choice_instrs) => {
|
IndexingLine::IndexedChoice(indexed_choice_instrs) => {
|
||||||
for indexed_choice_instr in indexed_choice_instrs {
|
for indexed_choice_instr in indexed_choice_instrs {
|
||||||
let section = indexed_choice_instr.to_functor();
|
let section = indexed_choice_instr.to_functor();
|
||||||
h += section.len();
|
|
||||||
functors.push(section);
|
functors.push(section);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
|
IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
|
||||||
for indexed_choice_instr in indexed_choice_instrs {
|
for indexed_choice_instr in indexed_choice_instrs {
|
||||||
let section = functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]);
|
let section = functor!(atom!("dynamic"),
|
||||||
|
[fixnum((*indexed_choice_instr))]);
|
||||||
h += section.len();
|
|
||||||
functors.push(section);
|
functors.push(section);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instr => functors.push(instr.to_functor(h, arena)),
|
instr => functors.push(instr.to_functor(arena)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_functor(&self, h: usize, arena: &mut Arena) -> MachineStub {
|
fn to_functor(&self, arena: &mut Arena) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&Instruction::InstallVerifyAttr => {
|
&Instruction::InstallVerifyAttr => {
|
||||||
functor!(atom!("install_verify_attr"))
|
functor!(atom!("install_verify_attr"))
|
||||||
@@ -1290,25 +1259,23 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
(Death::Infinity, NextOrFail::Next(i)) => {
|
(Death::Infinity, NextOrFail::Next(i)) => {
|
||||||
functor!(
|
functor!(
|
||||||
atom!("dynamic_else"),
|
atom!("dynamic_else"),
|
||||||
[fixnum(birth), atom(atom!("inf")), fixnum(i)]
|
[fixnum(birth), atom_as_cell((atom!("inf"))), fixnum(i)]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Death::Infinity, NextOrFail::Fail(i)) => {
|
(Death::Infinity, NextOrFail::Fail(i)) => {
|
||||||
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
|
|
||||||
|
|
||||||
functor!(
|
functor!(
|
||||||
atom!("dynamic_else"),
|
atom!("dynamic_else"),
|
||||||
[fixnum(birth), atom(atom!("inf")), str(h, 0)],
|
[fixnum(birth),
|
||||||
[next_functor]
|
atom_as_cell((atom!("inf"))),
|
||||||
|
functor((atom!("fail")), [fixnum(i)])]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Death::Finite(d), NextOrFail::Fail(i)) => {
|
(Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||||
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
|
|
||||||
|
|
||||||
functor!(
|
functor!(
|
||||||
atom!("dynamic_else"),
|
atom!("dynamic_else"),
|
||||||
[fixnum(birth), fixnum(d), str(h, 0)],
|
[fixnum(birth),
|
||||||
[next_functor]
|
fixnum(d),
|
||||||
|
functor((atom!("fail")), [fixnum(i)])]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Death::Finite(d), NextOrFail::Next(i)) => {
|
(Death::Finite(d), NextOrFail::Next(i)) => {
|
||||||
@@ -1321,25 +1288,23 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
(Death::Infinity, NextOrFail::Next(i)) => {
|
(Death::Infinity, NextOrFail::Next(i)) => {
|
||||||
functor!(
|
functor!(
|
||||||
atom!("dynamic_internal_else"),
|
atom!("dynamic_internal_else"),
|
||||||
[fixnum(birth), atom(atom!("inf")), fixnum(i)]
|
[fixnum(birth), atom_as_cell((atom!("inf"))), fixnum(i)]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Death::Infinity, NextOrFail::Fail(i)) => {
|
(Death::Infinity, NextOrFail::Fail(i)) => {
|
||||||
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
|
|
||||||
|
|
||||||
functor!(
|
functor!(
|
||||||
atom!("dynamic_internal_else"),
|
atom!("dynamic_internal_else"),
|
||||||
[fixnum(birth), atom(atom!("inf")), str(h, 0)],
|
[fixnum(birth),
|
||||||
[next_functor]
|
atom_as_cell((atom!("inf"))),
|
||||||
|
functor((atom!("fail")), [fixnum(i)])]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Death::Finite(d), NextOrFail::Fail(i)) => {
|
(Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||||
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
|
|
||||||
|
|
||||||
functor!(
|
functor!(
|
||||||
atom!("dynamic_internal_else"),
|
atom!("dynamic_internal_else"),
|
||||||
[fixnum(birth), fixnum(d), str(h, 0)],
|
[fixnum(birth),
|
||||||
[next_functor]
|
fixnum(d),
|
||||||
|
functor((atom!("fail")), [fixnum(i)])]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Death::Finite(d), NextOrFail::Next(i)) => {
|
(Death::Finite(d), NextOrFail::Next(i)) => {
|
||||||
@@ -1367,157 +1332,154 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
}
|
}
|
||||||
&Instruction::Cut(r) => {
|
&Instruction::Cut(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("cut"), [str(h, 0)], [rt_stub])
|
functor!(atom!("cut"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::CutPrev(r) => {
|
&Instruction::CutPrev(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("cut_prev"), [str(h, 0)], [rt_stub])
|
functor!(atom!("cut_prev"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::GetLevel(r) => {
|
&Instruction::GetLevel(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("get_level"), [str(h, 0)], [rt_stub])
|
functor!(atom!("get_level"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::GetPrevLevel(r) => {
|
&Instruction::GetPrevLevel(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("get_prev_level"), [str(h, 0)], [rt_stub])
|
functor!(atom!("get_prev_level"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::GetCutPoint(r) => {
|
&Instruction::GetCutPoint(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("get_cut_point"), [str(h, 0)], [rt_stub])
|
functor!(atom!("get_cut_point"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::NeckCut => {
|
&Instruction::NeckCut => {
|
||||||
functor!(atom!("neck_cut"))
|
functor!(atom!("neck_cut"))
|
||||||
}
|
}
|
||||||
&Instruction::Add(ref at_1, ref at_2, t) => {
|
&Instruction::Add(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("add"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("add"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Sub(ref at_1, ref at_2, t) => {
|
&Instruction::Sub(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("sub"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("sub"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Mul(ref at_1, ref at_2, t) => {
|
&Instruction::Mul(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("mul"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("mul"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::IntPow(ref at_1, ref at_2, t) => {
|
&Instruction::IntPow(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("int_pow"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("int_pow"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Pow(ref at_1, ref at_2, t) => {
|
&Instruction::Pow(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("pow"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("pow"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::IDiv(ref at_1, ref at_2, t) => {
|
&Instruction::IDiv(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("idiv"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("idiv"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Max(ref at_1, ref at_2, t) => {
|
&Instruction::Max(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("max"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("max"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Min(ref at_1, ref at_2, t) => {
|
&Instruction::Min(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("min"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("min"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::IntFloorDiv(ref at_1, ref at_2, t) => {
|
&Instruction::IntFloorDiv(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("int_floor_div"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("int_floor_div"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::RDiv(ref at_1, ref at_2, t) => {
|
&Instruction::RDiv(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("rdiv"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("rdiv"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Div(ref at_1, ref at_2, t) => {
|
&Instruction::Div(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("div"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("div"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Shl(ref at_1, ref at_2, t) => {
|
&Instruction::Shl(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("shl"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("shl"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Shr(ref at_1, ref at_2, t) => {
|
&Instruction::Shr(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("shr"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("shr"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Xor(ref at_1, ref at_2, t) => {
|
&Instruction::Xor(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("xor"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("xor"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::And(ref at_1, ref at_2, t) => {
|
&Instruction::And(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("and"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("and"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Or(ref at_1, ref at_2, t) => {
|
&Instruction::Or(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("or"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("or"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Mod(ref at_1, ref at_2, t) => {
|
&Instruction::Mod(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("mod"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("mod"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Rem(ref at_1, ref at_2, t) => {
|
&Instruction::Rem(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("rem"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::ATan2(ref at_1, ref at_2, t) => {
|
&Instruction::ATan2(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("rem"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Gcd(ref at_1, ref at_2, t) => {
|
&Instruction::Gcd(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t)
|
arith_instr_bin_functor(atom!("gcd"), arena, at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&Instruction::Sign(ref at, t) => {
|
&Instruction::Sign(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("sign"), arena, at, t)
|
arith_instr_unary_functor(atom!("sign"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Cos(ref at, t) => {
|
&Instruction::Cos(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("cos"), arena, at, t)
|
arith_instr_unary_functor(atom!("cos"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Sin(ref at, t) => {
|
&Instruction::Sin(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("sin"), arena, at, t)
|
arith_instr_unary_functor(atom!("sin"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Tan(ref at, t) => {
|
&Instruction::Tan(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("tan"), arena, at, t)
|
arith_instr_unary_functor(atom!("tan"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Log(ref at, t) => {
|
&Instruction::Log(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("log"), arena, at, t)
|
arith_instr_unary_functor(atom!("log"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Exp(ref at, t) => {
|
&Instruction::Exp(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("exp"), arena, at, t)
|
arith_instr_unary_functor(atom!("exp"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::ACos(ref at, t) => {
|
&Instruction::ACos(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("acos"), arena, at, t)
|
arith_instr_unary_functor(atom!("acos"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::ASin(ref at, t) => {
|
&Instruction::ASin(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("asin"), arena, at, t)
|
arith_instr_unary_functor(atom!("asin"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::ATan(ref at, t) => {
|
&Instruction::ATan(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("atan"), arena, at, t)
|
arith_instr_unary_functor(atom!("atan"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Sqrt(ref at, t) => {
|
&Instruction::Sqrt(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t)
|
arith_instr_unary_functor(atom!("sqrt"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Abs(ref at, t) => {
|
&Instruction::Abs(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("abs"), arena, at, t)
|
arith_instr_unary_functor(atom!("abs"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Float(ref at, t) => {
|
&Instruction::Float(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("float"), arena, at, t)
|
arith_instr_unary_functor(atom!("float"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Truncate(ref at, t) => {
|
&Instruction::Truncate(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("truncate"), arena, at, t)
|
arith_instr_unary_functor(atom!("truncate"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Round(ref at, t) => {
|
&Instruction::Round(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("round"), arena, at, t)
|
arith_instr_unary_functor(atom!("round"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Ceiling(ref at, t) => {
|
&Instruction::Ceiling(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t)
|
arith_instr_unary_functor(atom!("ceiling"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Floor(ref at, t) => {
|
&Instruction::Floor(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("floor"), arena, at, t)
|
arith_instr_unary_functor(atom!("floor"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::FloatFractionalPart(ref at, t) => {
|
&Instruction::FloatFractionalPart(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("float_fractional_part"), arena, at, t)
|
arith_instr_unary_functor(atom!("float_fractional_part"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::FloatIntegerPart(ref at, t) => {
|
&Instruction::FloatIntegerPart(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, atom!("float_integer_part"), arena, at, t)
|
arith_instr_unary_functor(atom!("float_integer_part"), arena, at, t)
|
||||||
}
|
}
|
||||||
&Instruction::Neg(ref at, t) => arith_instr_unary_functor(
|
&Instruction::Neg(ref at, t) => arith_instr_unary_functor(
|
||||||
h,
|
|
||||||
atom!("-"),
|
atom!("-"),
|
||||||
arena,
|
arena,
|
||||||
at,
|
at,
|
||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
&Instruction::Plus(ref at, t) => arith_instr_unary_functor(
|
&Instruction::Plus(ref at, t) => arith_instr_unary_functor(
|
||||||
h,
|
|
||||||
atom!("+"),
|
atom!("+"),
|
||||||
arena,
|
arena,
|
||||||
at,
|
at,
|
||||||
t,
|
t,
|
||||||
),
|
),
|
||||||
&Instruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor(
|
&Instruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor(
|
||||||
h,
|
|
||||||
atom!("\\"),
|
atom!("\\"),
|
||||||
arena,
|
arena,
|
||||||
at,
|
at,
|
||||||
@@ -1533,16 +1495,16 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
functor!(atom!("allocate"), [fixnum(num_frames)])
|
functor!(atom!("allocate"), [fixnum(num_frames)])
|
||||||
}
|
}
|
||||||
&Instruction::CallNamed(arity, name, ..) => {
|
&Instruction::CallNamed(arity, name, ..) => {
|
||||||
functor!(atom!("call"), [atom(name), fixnum(arity)])
|
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
&Instruction::ExecuteNamed(arity, name, ..) => {
|
&Instruction::ExecuteNamed(arity, name, ..) => {
|
||||||
functor!(atom!("execute"), [atom(name), fixnum(arity)])
|
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
&Instruction::DefaultCallNamed(arity, name, ..) => {
|
&Instruction::DefaultCallNamed(arity, name, ..) => {
|
||||||
functor!(atom!("call_default"), [atom(name), fixnum(arity)])
|
functor!(atom!("call_default"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
&Instruction::DefaultExecuteNamed(arity, name, ..) => {
|
&Instruction::DefaultExecuteNamed(arity, name, ..) => {
|
||||||
functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
|
functor!(atom!("execute_default"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
&Instruction::CallN(arity) => {
|
&Instruction::CallN(arity) => {
|
||||||
functor!(atom!("call_n"), [fixnum(arity)])
|
functor!(atom!("call_n"), [fixnum(arity)])
|
||||||
@@ -1585,7 +1547,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallSort |
|
&Instruction::CallSort |
|
||||||
&Instruction::CallGetNumber(_) => {
|
&Instruction::CallGetNumber(_) => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("call"), [atom(name), fixnum(arity)])
|
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
&Instruction::ExecuteTermGreaterThan |
|
&Instruction::ExecuteTermGreaterThan |
|
||||||
@@ -1611,7 +1573,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteSort |
|
&Instruction::ExecuteSort |
|
||||||
&Instruction::ExecuteGetNumber(_) => {
|
&Instruction::ExecuteGetNumber(_) => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("execute"), [atom(name), fixnum(arity)])
|
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
&Instruction::DefaultCallTermGreaterThan |
|
&Instruction::DefaultCallTermGreaterThan |
|
||||||
@@ -1637,7 +1599,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::DefaultCallSort |
|
&Instruction::DefaultCallSort |
|
||||||
&Instruction::DefaultCallGetNumber(_) => {
|
&Instruction::DefaultCallGetNumber(_) => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("call_default"), [atom(name), fixnum(arity)])
|
functor!(atom!("call_default"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
&Instruction::DefaultExecuteTermGreaterThan |
|
&Instruction::DefaultExecuteTermGreaterThan |
|
||||||
@@ -1663,7 +1625,7 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::DefaultExecuteSort |
|
&Instruction::DefaultExecuteSort |
|
||||||
&Instruction::DefaultExecuteGetNumber(_) => {
|
&Instruction::DefaultExecuteGetNumber(_) => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
|
functor!(atom!("execute_default"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
&Instruction::CallIsAtom(r) |
|
&Instruction::CallIsAtom(r) |
|
||||||
&Instruction::CallIsAtomic(r) |
|
&Instruction::CallIsAtomic(r) |
|
||||||
@@ -1676,7 +1638,8 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallIsVar(r) => {
|
&Instruction::CallIsVar(r) => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("call"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub])
|
|
||||||
|
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity), functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::ExecuteIsAtom(r) |
|
&Instruction::ExecuteIsAtom(r) |
|
||||||
&Instruction::ExecuteIsAtomic(r) |
|
&Instruction::ExecuteIsAtomic(r) |
|
||||||
@@ -1689,7 +1652,8 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteIsVar(r) => {
|
&Instruction::ExecuteIsVar(r) => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("execute"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub])
|
|
||||||
|
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity), functor(rt_stub)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
&Instruction::CallAtomChars |
|
&Instruction::CallAtomChars |
|
||||||
@@ -1871,6 +1835,11 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallSetEnv |
|
&Instruction::CallSetEnv |
|
||||||
&Instruction::CallUnsetEnv |
|
&Instruction::CallUnsetEnv |
|
||||||
&Instruction::CallShell |
|
&Instruction::CallShell |
|
||||||
|
&Instruction::CallProcessCreate |
|
||||||
|
&Instruction::CallProcessId |
|
||||||
|
&Instruction::CallProcessWait |
|
||||||
|
&Instruction::CallProcessKill |
|
||||||
|
&Instruction::CallProcessRelease |
|
||||||
&Instruction::CallPid |
|
&Instruction::CallPid |
|
||||||
&Instruction::CallCharsBase64 |
|
&Instruction::CallCharsBase64 |
|
||||||
&Instruction::CallDevourWhitespace |
|
&Instruction::CallDevourWhitespace |
|
||||||
@@ -1920,14 +1889,14 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallEd25519VerifyRaw |
|
&Instruction::CallEd25519VerifyRaw |
|
||||||
&Instruction::CallEd25519SeedToPublicKey => {
|
&Instruction::CallEd25519SeedToPublicKey => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("call"), [atom(name), fixnum(arity)])
|
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
#[cfg(feature = "crypto-full")]
|
#[cfg(feature = "crypto-full")]
|
||||||
&Instruction::CallCryptoDataEncrypt |
|
&Instruction::CallCryptoDataEncrypt |
|
||||||
&Instruction::CallCryptoDataDecrypt => {
|
&Instruction::CallCryptoDataDecrypt => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("call"), [atom(name), fixnum(arity)])
|
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
&Instruction::ExecuteAtomChars |
|
&Instruction::ExecuteAtomChars |
|
||||||
@@ -2109,6 +2078,11 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteSetEnv |
|
&Instruction::ExecuteSetEnv |
|
||||||
&Instruction::ExecuteUnsetEnv |
|
&Instruction::ExecuteUnsetEnv |
|
||||||
&Instruction::ExecuteShell |
|
&Instruction::ExecuteShell |
|
||||||
|
&Instruction::ExecuteProcessCreate |
|
||||||
|
&Instruction::ExecuteProcessId |
|
||||||
|
&Instruction::ExecuteProcessWait |
|
||||||
|
&Instruction::ExecuteProcessKill |
|
||||||
|
&Instruction::ExecuteProcessRelease |
|
||||||
&Instruction::ExecutePid |
|
&Instruction::ExecutePid |
|
||||||
&Instruction::ExecuteCharsBase64 |
|
&Instruction::ExecuteCharsBase64 |
|
||||||
&Instruction::ExecuteDevourWhitespace |
|
&Instruction::ExecuteDevourWhitespace |
|
||||||
@@ -2158,14 +2132,14 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteEd25519VerifyRaw |
|
&Instruction::ExecuteEd25519VerifyRaw |
|
||||||
&Instruction::ExecuteEd25519SeedToPublicKey => {
|
&Instruction::ExecuteEd25519SeedToPublicKey => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("execute"), [atom(name), fixnum(arity)])
|
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
#[cfg(feature = "crypto-full")]
|
#[cfg(feature = "crypto-full")]
|
||||||
&Instruction::ExecuteCryptoDataEncrypt |
|
&Instruction::ExecuteCryptoDataEncrypt |
|
||||||
&Instruction::ExecuteCryptoDataDecrypt => {
|
&Instruction::ExecuteCryptoDataDecrypt => {
|
||||||
let (name, arity) = self.to_name_and_arity();
|
let (name, arity) = self.to_name_and_arity();
|
||||||
functor!(atom!("execute"), [atom(name), fixnum(arity)])
|
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)])
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
&Instruction::Deallocate => {
|
&Instruction::Deallocate => {
|
||||||
@@ -2180,73 +2154,60 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::Proceed => {
|
&Instruction::Proceed => {
|
||||||
functor!(atom!("proceed"))
|
functor!(atom!("proceed"))
|
||||||
}
|
}
|
||||||
&Instruction::GetConstant(lvl, c, r) => {
|
&Instruction::GetConstant(lvl, lit, r) => {
|
||||||
let lvl_stub = lvl.into_functor();
|
let lvl_stub = lvl.into_functor();
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
functor!(
|
functor!(atom!("get_constant"), [functor(lvl_stub),
|
||||||
atom!("get_constant"),
|
cell(lit),
|
||||||
[str(h, 0), cell(c), str(h, 1)],
|
functor(rt_stub)])
|
||||||
[lvl_stub, rt_stub]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
&Instruction::GetList(lvl, r) => {
|
&Instruction::GetList(lvl, r) => {
|
||||||
let lvl_stub = lvl.into_functor();
|
let lvl_stub = lvl.into_functor();
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
functor!(
|
functor!(atom!("get_list"), [functor(lvl_stub), functor(rt_stub)])
|
||||||
atom!("get_list"),
|
|
||||||
[str(h, 0), str(h, 1)],
|
|
||||||
[lvl_stub, rt_stub]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
&Instruction::GetPartialString(lvl, s, r, has_tail) => {
|
&Instruction::GetPartialString(lvl, ref s, r) => {
|
||||||
let lvl_stub = lvl.into_functor();
|
let lvl_stub = lvl.into_functor();
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
functor!(
|
functor!(atom!("get_partial_string"), [functor(lvl_stub),
|
||||||
atom!("get_partial_string"),
|
string((s.to_string())),
|
||||||
[
|
functor(rt_stub)])
|
||||||
str(h, 0),
|
|
||||||
string(h, s),
|
|
||||||
str(h, 1),
|
|
||||||
boolean(has_tail)
|
|
||||||
],
|
|
||||||
[lvl_stub, rt_stub]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
&Instruction::GetStructure(lvl, name, arity, r) => {
|
&Instruction::GetStructure(lvl, name, arity, r) => {
|
||||||
let lvl_stub = lvl.into_functor();
|
let lvl_stub = lvl.into_functor();
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
functor!(
|
functor!(atom!("get_structure"), [functor(lvl_stub),
|
||||||
atom!("get_structure"),
|
atom_as_cell(name),
|
||||||
[str(h, 0), atom(name), fixnum(arity), str(h, 1)],
|
fixnum(arity),
|
||||||
[lvl_stub, rt_stub]
|
functor(rt_stub)])
|
||||||
)
|
|
||||||
}
|
}
|
||||||
&Instruction::GetValue(r, arg) => {
|
&Instruction::GetValue(r, arg) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub])
|
functor!(atom!("get_value"), [functor(rt_stub),
|
||||||
|
fixnum(arg)])
|
||||||
}
|
}
|
||||||
&Instruction::GetVariable(r, arg) => {
|
&Instruction::GetVariable(r, arg) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
|
functor!(atom!("get_variable"), [functor(rt_stub), fixnum(arg)])
|
||||||
}
|
}
|
||||||
&Instruction::UnifyConstant(c) => {
|
&Instruction::UnifyConstant(c) => {
|
||||||
functor!(atom!("unify_constant"), [cell(c)])
|
functor!(atom!("unify_constant"), [cell(c)])
|
||||||
}
|
}
|
||||||
&Instruction::UnifyLocalValue(r) => {
|
&Instruction::UnifyLocalValue(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub])
|
functor!(atom!("unify_local_value"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::UnifyVariable(r) => {
|
&Instruction::UnifyVariable(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub])
|
functor!(atom!("unify_variable"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::UnifyValue(r) => {
|
&Instruction::UnifyValue(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("unify_value"), [str(h, 0)], [rt_stub])
|
functor!(atom!("unify_value"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::UnifyVoid(vars) => {
|
&Instruction::UnifyVoid(vars) => {
|
||||||
functor!(atom!("unify_void"), [fixnum(vars)])
|
functor!(atom!("unify_void"), [fixnum(vars)])
|
||||||
@@ -2258,68 +2219,55 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
let lvl_stub = lvl.into_functor();
|
let lvl_stub = lvl.into_functor();
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
functor!(
|
functor!(atom!("put_constant"), [functor(rt_stub), cell(c), functor(lvl_stub)])
|
||||||
atom!("put_constant"),
|
|
||||||
[str(h, 0), cell(c), str(h, 1)],
|
|
||||||
[lvl_stub, rt_stub]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
&Instruction::PutList(lvl, r) => {
|
&Instruction::PutList(lvl, r) => {
|
||||||
let lvl_stub = lvl.into_functor();
|
let lvl_stub = lvl.into_functor();
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
functor!(
|
functor!(atom!("put_list"), [functor(lvl_stub), functor(rt_stub)])
|
||||||
atom!("put_list"),
|
|
||||||
[str(h, 0), str(h, 1)],
|
|
||||||
[lvl_stub, rt_stub]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
&Instruction::PutPartialString(lvl, s, r, has_tail) => {
|
&Instruction::PutPartialString(lvl, ref s, r) => {
|
||||||
let lvl_stub = lvl.into_functor();
|
let lvl_stub = lvl.into_functor();
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
functor!(
|
functor!(atom!("put_partial_string"), [functor(lvl_stub),
|
||||||
atom!("put_partial_string"),
|
string((s.to_string())),
|
||||||
[
|
functor(rt_stub)])
|
||||||
str(h, 0),
|
|
||||||
string(h, s),
|
|
||||||
str(h, 1),
|
|
||||||
boolean(has_tail)
|
|
||||||
],
|
|
||||||
[lvl_stub, rt_stub]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
&Instruction::PutStructure(name, arity, r) => {
|
&Instruction::PutStructure(name, arity, r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
functor!(
|
functor!(atom!("put_structure"), [atom_as_cell(name),
|
||||||
atom!("put_structure"),
|
fixnum(arity),
|
||||||
[atom(name), fixnum(arity), str(h, 0)],
|
functor(rt_stub)])
|
||||||
[rt_stub]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
&Instruction::PutValue(r, arg) => {
|
&Instruction::PutValue(r, arg) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub])
|
|
||||||
|
functor!(atom!("put_value"), [functor(rt_stub),
|
||||||
|
fixnum(arg)])
|
||||||
}
|
}
|
||||||
&Instruction::PutVariable(r, arg) => {
|
&Instruction::PutVariable(r, arg) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
|
|
||||||
|
functor!(atom!("put_variable"), [functor(rt_stub),
|
||||||
|
fixnum(arg)])
|
||||||
}
|
}
|
||||||
&Instruction::SetConstant(c) => {
|
&Instruction::SetConstant(c) => {
|
||||||
functor!(atom!("set_constant"), [cell(c)])
|
functor!(atom!("set_constant"), [cell(c)])
|
||||||
}
|
}
|
||||||
&Instruction::SetLocalValue(r) => {
|
&Instruction::SetLocalValue(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub])
|
functor!(atom!("set_local_value"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::SetVariable(r) => {
|
&Instruction::SetVariable(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("set_variable"), [str(h, 0)], [rt_stub])
|
functor!(atom!("set_variable"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::SetValue(r) => {
|
&Instruction::SetValue(r) => {
|
||||||
let rt_stub = reg_type_into_functor(r);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
functor!(atom!("set_value"), [str(h, 0)], [rt_stub])
|
functor!(atom!("set_value"), [functor(rt_stub)])
|
||||||
}
|
}
|
||||||
&Instruction::SetVoid(vars) => {
|
&Instruction::SetVoid(vars) => {
|
||||||
functor!(atom!("set_void"), [fixnum(vars)])
|
functor!(atom!("set_void"), [fixnum(vars)])
|
||||||
@@ -2770,7 +2718,7 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
|
|
||||||
if ident == "Named" {
|
if ident == "Named" {
|
||||||
clause_type_from_name_and_arity_arms.push(quote! {
|
clause_type_from_name_and_arity_arms.push(quote! {
|
||||||
(name, arity) => ClauseType::Named(arity, name, CodeIndex::default(arena))
|
(name, arity) => ClauseType::Named(arity, name, CodeIndex::default(&mut arena.code_index_tbl))
|
||||||
});
|
});
|
||||||
|
|
||||||
clause_type_to_instr_arms.push(quote! {
|
clause_type_to_instr_arms.push(quote! {
|
||||||
@@ -3198,12 +3146,6 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
|
|
||||||
matches!((name, arity),
|
|
||||||
#(#is_inbuilt_arms)|*
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> Atom {
|
pub fn name(&self) -> Atom {
|
||||||
match self {
|
match self {
|
||||||
#(
|
#(
|
||||||
@@ -3212,6 +3154,12 @@ pub fn generate_instructions_rs() -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
|
||||||
|
matches!((name, arity),
|
||||||
|
#(#is_inbuilt_arms)|*
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_inlined(name: Atom, arity: usize) -> bool {
|
pub fn is_inlined(name: Atom, arity: usize) -> bool {
|
||||||
matches!((name, arity),
|
matches!((name, arity),
|
||||||
#(#is_inlined_arms)|*
|
#(#is_inlined_arms)|*
|
||||||
@@ -3334,14 +3282,14 @@ where
|
|||||||
let disc = match DiscriminantT::from_str(id.to_string().as_str()) {
|
let disc = match DiscriminantT::from_str(id.to_string().as_str()) {
|
||||||
Ok(disc) => disc,
|
Ok(disc) => disc,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
panic!("can't generate discriminant {}", id);
|
panic!("can't generate discriminant {id}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match disc.get_str(key) {
|
match disc.get_str(key) {
|
||||||
Some(prop) => prop,
|
Some(prop) => prop,
|
||||||
None => {
|
None => {
|
||||||
panic!("can't find property {} of discriminant {:?}", key, disc);
|
panic!("can't find property {key} of discriminant {disc:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3459,7 +3407,7 @@ impl InstructionData {
|
|||||||
|
|
||||||
(name, arity, CountableInference::HasDefault)
|
(name, arity, CountableInference::HasDefault)
|
||||||
} else {
|
} else {
|
||||||
panic!("type ID is: {}", id);
|
panic!("type ID is: {id}");
|
||||||
};
|
};
|
||||||
|
|
||||||
let v_ident = variant
|
let v_ident = variant
|
||||||
|
|||||||
@@ -84,6 +84,18 @@ impl<'ast> Visit<'ast> for StaticStrVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const INLINED_ATOM_MAX_LEN: usize = 6;
|
||||||
|
|
||||||
|
fn static_string_index(string: &str, index: usize) -> u64 {
|
||||||
|
if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') {
|
||||||
|
let mut string_buf: [u8; 8] = [0u8; 8];
|
||||||
|
string_buf[..string.len()].copy_from_slice(string.as_bytes());
|
||||||
|
(u64::from_le_bytes(string_buf) << 1) | 1
|
||||||
|
} else {
|
||||||
|
(index << 1) as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStream {
|
pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStream {
|
||||||
use quote::*;
|
use quote::*;
|
||||||
|
|
||||||
@@ -114,14 +126,14 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
|
|||||||
match file.read_to_string(&mut src) {
|
match file.read_to_string(&mut src) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("error reading file: {:?}", e);
|
panic!("error reading file: {e:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let syntax = match syn::parse_file(&src) {
|
let syntax = match syn::parse_file(&src) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("parse error: {} in file {:?}", e, path);
|
panic!("parse error: {e} in file {path:?}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(syntax)
|
Ok(syntax)
|
||||||
@@ -149,11 +161,29 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
|
|||||||
visitor.visit_file(&syntax)
|
visitor.visit_file(&syntax)
|
||||||
}
|
}
|
||||||
|
|
||||||
let indices = (0..visitor.static_strs.len()).map(|i| (i << 3) as u64);
|
let mut static_str_keys = vec![];
|
||||||
let indices_iter = indices.clone();
|
let mut static_strs = vec![];
|
||||||
|
let mut static_str_indices = vec![];
|
||||||
|
|
||||||
let static_strs_len = visitor.static_strs.len();
|
let indices: Vec<u64> = visitor
|
||||||
let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect();
|
.static_strs
|
||||||
|
.iter()
|
||||||
|
.map(|string| {
|
||||||
|
let index = static_string_index(string, static_strs.len());
|
||||||
|
|
||||||
|
static_str_keys.push(string);
|
||||||
|
|
||||||
|
if index & 1 == 1 {
|
||||||
|
index
|
||||||
|
} else {
|
||||||
|
static_str_indices.push(index);
|
||||||
|
static_strs.push(string);
|
||||||
|
index
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let static_strs_len = static_strs.len();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
static STRINGS: [&str; #static_strs_len] = [
|
static STRINGS: [&str; #static_strs_len] = [
|
||||||
@@ -163,11 +193,12 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
|
|||||||
];
|
];
|
||||||
|
|
||||||
macro_rules! atom {
|
macro_rules! atom {
|
||||||
#((#static_strs) => { Atom { index: #indices_iter } };)*
|
#((#static_str_keys) => { Atom { index: #indices } };)*
|
||||||
|
($name:literal) => {compile_error!(concat!("unknown static atom ", $name))};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
|
pub static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
|
||||||
#(#static_strs => { Atom { index: #indices } },)*
|
#(#static_strs => { Atom { index: #static_str_indices } },)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ pub(crate) trait Allocator {
|
|||||||
lvl: Level,
|
lvl: Level,
|
||||||
context: GenContext,
|
context: GenContext,
|
||||||
code: &mut CodeDeque,
|
code: &mut CodeDeque,
|
||||||
);
|
) -> RegType;
|
||||||
|
|
||||||
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
470
src/arena.rs
470
src/arena.rs
@@ -3,31 +3,27 @@
|
|||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
use crate::http::{HttpListener, HttpResponse};
|
use crate::http::{HttpListener, HttpResponse};
|
||||||
use crate::machine::loader::LiveLoadState;
|
use crate::machine::loader::LiveLoadState;
|
||||||
use crate::machine::machine_indices::*;
|
|
||||||
use crate::machine::streams::*;
|
use crate::machine::streams::*;
|
||||||
use crate::raw_block::*;
|
use crate::offset_table::*;
|
||||||
use crate::read::*;
|
use crate::read::*;
|
||||||
use crate::types::UntypedArenaPtr;
|
use crate::types::UntypedArenaPtr;
|
||||||
|
|
||||||
use crate::parser::dashu::{Integer, Rational};
|
use crate::parser::dashu::{Integer, Rational};
|
||||||
use arcu::atomic::Arcu;
|
|
||||||
use arcu::epoch_counters::GlobalEpochCounterPool;
|
|
||||||
use arcu::rcu_ref::RcuRef;
|
|
||||||
use arcu::Rcu;
|
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use std::cell::UnsafeCell;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::io::PipeReader;
|
||||||
|
use std::io::PipeWriter;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::mem::ManuallyDrop;
|
use std::mem::ManuallyDrop;
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::process::Child;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::ptr::addr_of_mut;
|
use std::ptr::addr_of_mut;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use std::sync::RwLock;
|
|
||||||
|
|
||||||
macro_rules! arena_alloc {
|
macro_rules! arena_alloc {
|
||||||
($e:expr, $arena:expr) => {{
|
($e:expr, $arena:expr) => {{
|
||||||
@@ -38,8 +34,7 @@ macro_rules! arena_alloc {
|
|||||||
|
|
||||||
macro_rules! float_alloc {
|
macro_rules! float_alloc {
|
||||||
($e:expr, $arena:expr) => {{
|
($e:expr, $arena:expr) => {{
|
||||||
let result = $e;
|
$arena.f64_tbl.build_with(OrderedFloat($e))
|
||||||
unsafe { $arena.f64_tbl.build_with(result).as_ptr() }
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,120 +50,6 @@ where
|
|||||||
payload_offset - header_offset
|
payload_offset - header_offset
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::sync::Weak;
|
|
||||||
|
|
||||||
const F64_TABLE_INIT_SIZE: usize = 1 << 16;
|
|
||||||
const F64_TABLE_ALIGN: usize = 8;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn global_f64table() -> &'static RwLock<Weak<F64Table>> {
|
|
||||||
static GLOBAL_ATOM_TABLE: RwLock<Weak<F64Table>> = RwLock::new(Weak::new());
|
|
||||||
&GLOBAL_ATOM_TABLE
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RawBlockTraits for F64Table {
|
|
||||||
#[inline]
|
|
||||||
fn init_size() -> usize {
|
|
||||||
F64_TABLE_INIT_SIZE
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn align() -> usize {
|
|
||||||
F64_TABLE_ALIGN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct F64Table {
|
|
||||||
block: Arcu<RawBlock<F64Table>, GlobalEpochCounterPool>,
|
|
||||||
update: Mutex<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Actually prove this, as it's probably unsound right now
|
|
||||||
unsafe impl Send for F64Table {}
|
|
||||||
unsafe impl Sync for F64Table {}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn lookup_float(
|
|
||||||
offset: F64Offset,
|
|
||||||
) -> RcuRef<RawBlock<F64Table>, UnsafeCell<OrderedFloat<f64>>> {
|
|
||||||
let f64table = global_f64table()
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.upgrade()
|
|
||||||
.expect("We should only be looking up floats while there is a float table");
|
|
||||||
|
|
||||||
RcuRef::try_map(f64table.block.read(), |raw_block| unsafe {
|
|
||||||
raw_block
|
|
||||||
.base
|
|
||||||
.add(offset.0)
|
|
||||||
.cast_mut()
|
|
||||||
.cast::<UnsafeCell<OrderedFloat<f64>>>()
|
|
||||||
.as_ref()
|
|
||||||
})
|
|
||||||
.expect("The offset should result in a non-null pointer")
|
|
||||||
}
|
|
||||||
|
|
||||||
impl F64Table {
|
|
||||||
#[inline]
|
|
||||||
pub fn new() -> Arc<Self> {
|
|
||||||
let upgraded = global_f64table().read().unwrap().upgrade();
|
|
||||||
// don't inline upgraded, otherwise temporary will be dropped too late in case of None
|
|
||||||
if let Some(atom_table) = upgraded {
|
|
||||||
atom_table
|
|
||||||
} else {
|
|
||||||
let mut guard = global_f64table().write().unwrap();
|
|
||||||
// try to upgrade again in case we lost the race on the write lock
|
|
||||||
if let Some(atom_table) = guard.upgrade() {
|
|
||||||
atom_table
|
|
||||||
} else {
|
|
||||||
let atom_table = Arc::new(Self {
|
|
||||||
block: Arcu::new(RawBlock::new(), GlobalEpochCounterPool),
|
|
||||||
update: Mutex::new(()),
|
|
||||||
});
|
|
||||||
*guard = Arc::downgrade(&atom_table);
|
|
||||||
atom_table
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::missing_safety_doc)]
|
|
||||||
pub unsafe fn build_with(&self, value: f64) -> F64Offset {
|
|
||||||
let update_guard = self.update.lock();
|
|
||||||
|
|
||||||
// we don't have an index table for lookups as AtomTable does so
|
|
||||||
// just get the epoch after we take the upgrade lock
|
|
||||||
let mut block_epoch = self.block.read();
|
|
||||||
|
|
||||||
let mut ptr;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
ptr = block_epoch.alloc(mem::size_of::<f64>());
|
|
||||||
|
|
||||||
if ptr.is_null() {
|
|
||||||
let new_block = block_epoch.grow_new().unwrap();
|
|
||||||
self.block.replace(new_block);
|
|
||||||
block_epoch = self.block.read();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr::write(ptr as *mut OrderedFloat<f64>, OrderedFloat(value));
|
|
||||||
|
|
||||||
let float = F64Offset(ptr as usize - block_epoch.base as usize);
|
|
||||||
|
|
||||||
// atometable would have to update the index table at this point
|
|
||||||
|
|
||||||
// expicit drop to ensure we don't accidentally drop it early
|
|
||||||
drop(update_guard);
|
|
||||||
|
|
||||||
float
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
|
||||||
#[bits = 7]
|
#[bits = 7]
|
||||||
pub enum ArenaHeaderTag {
|
pub enum ArenaHeaderTag {
|
||||||
@@ -193,11 +74,10 @@ pub enum ArenaHeaderTag {
|
|||||||
TcpListener = 0b1000000,
|
TcpListener = 0b1000000,
|
||||||
HttpListener = 0b1000001,
|
HttpListener = 0b1000001,
|
||||||
HttpResponse = 0b1000010,
|
HttpResponse = 0b1000010,
|
||||||
|
PipeWriter = 0b1000011,
|
||||||
Dropped = 0b1000100,
|
Dropped = 0b1000100,
|
||||||
IndexPtrDynamicUndefined = 0b1000101,
|
PipeReader = 0b1001001,
|
||||||
IndexPtrDynamicIndex = 0b1000110,
|
ChildProcess = 0b1001010,
|
||||||
IndexPtrIndex = 0b1000111,
|
|
||||||
IndexPtrUndefined = 0b1001000,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
@@ -436,137 +316,6 @@ pub trait ArenaAllocated {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct F64Ptr(RcuRef<RawBlock<F64Table>, UnsafeCell<OrderedFloat<f64>>>);
|
|
||||||
|
|
||||||
impl Clone for F64Ptr {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self(RcuRef::clone(&self.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for F64Ptr {
|
|
||||||
fn eq(&self, other: &F64Ptr) -> bool {
|
|
||||||
RcuRef::ptr_eq(&self.0, &other.0) || self.deref() == other.deref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for F64Ptr {}
|
|
||||||
|
|
||||||
impl PartialOrd for F64Ptr {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for F64Ptr {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
(**self).cmp(&**other)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for F64Ptr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
|
||||||
(self as &OrderedFloat<f64>).hash(hasher)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for F64Ptr {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self as &OrderedFloat<f64>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for F64Ptr {
|
|
||||||
type Target = OrderedFloat<f64>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
unsafe { self.0.get().as_ref().unwrap() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for F64Ptr {
|
|
||||||
#[inline]
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
unsafe { &mut *self.0.get().as_mut().unwrap() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl F64Ptr {
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_offset(offset: F64Offset) -> Self {
|
|
||||||
Self(lookup_float(offset))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn as_offset(&self) -> F64Offset {
|
|
||||||
F64Offset(self.0.get() as usize - RcuRef::get_root(&self.0).base as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct F64Offset(usize);
|
|
||||||
|
|
||||||
impl F64Offset {
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn new(offset: usize) -> Self {
|
|
||||||
Self(offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn from_ptr(ptr: F64Ptr) -> Self {
|
|
||||||
ptr.as_offset()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn as_ptr(self) -> F64Ptr {
|
|
||||||
F64Ptr::from_offset(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn to_u64(self) -> u64 {
|
|
||||||
self.0 as u64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for F64Offset {
|
|
||||||
#[inline(always)]
|
|
||||||
fn eq(&self, other: &F64Offset) -> bool {
|
|
||||||
self.as_ptr() == other.as_ptr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for F64Offset {}
|
|
||||||
|
|
||||||
impl PartialOrd for F64Offset {
|
|
||||||
#[inline(always)]
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for F64Offset {
|
|
||||||
#[inline(always)]
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.as_ptr().cmp(&other.as_ptr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for F64Offset {
|
|
||||||
#[inline(always)]
|
|
||||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
|
||||||
self.as_ptr().hash(hasher)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for F64Offset {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "F64Offset({})", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArenaAllocated for Integer {
|
impl ArenaAllocated for Integer {
|
||||||
type Payload = Self;
|
type Payload = Self;
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -644,43 +393,16 @@ impl ArenaAllocated for HttpResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArenaAllocated for IndexPtr {
|
impl ArenaAllocated for Child {
|
||||||
type Payload = Self;
|
type Payload = ManuallyDrop<Self>;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn tag() -> ArenaHeaderTag {
|
fn tag() -> ArenaHeaderTag {
|
||||||
ArenaHeaderTag::IndexPtrUndefined
|
ArenaHeaderTag::ChildProcess
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#[inline]
|
impl AllocateInArena<Child> for Child {
|
||||||
fn header_offset_from_payload() -> usize {
|
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<Child> {
|
||||||
0
|
Child::alloc(arena, ManuallyDrop::new(self))
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// - the caller must guarantee that the pointee type of UntypedArenaPtr is T
|
|
||||||
/// - the pointer must be non-null
|
|
||||||
unsafe fn typed_ptr(ptr: UntypedArenaPtr) -> TypedArenaPtr<Self> {
|
|
||||||
TypedArenaPtr(NonNull::new_unchecked(
|
|
||||||
ptr.get_ptr().cast_mut().cast::<IndexPtr>(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn alloc(arena: &mut Arena, value: Self) -> TypedArenaPtr<Self> {
|
|
||||||
let slab = Box::new(IndexPtrSlab {
|
|
||||||
next: arena.base.take(),
|
|
||||||
index_ptr: value,
|
|
||||||
});
|
|
||||||
|
|
||||||
let (allocated_ptr, untyped_slab) = slab.to_untyped();
|
|
||||||
arena.base = Some(untyped_slab);
|
|
||||||
allocated_ptr
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
/// - ptr points to an allocated slab of the correct kind
|
|
||||||
unsafe fn dealloc(ptr: NonNull<TypedAllocSlab<Self>>) {
|
|
||||||
drop(unsafe { Box::from_raw(ptr.as_ptr().cast::<IndexPtrSlab>()) });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,13 +413,6 @@ pub struct AllocSlab {
|
|||||||
header: ArenaHeader,
|
header: ArenaHeader,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct IndexPtrSlab {
|
|
||||||
next: Option<UntypedArenaSlab>,
|
|
||||||
index_ptr: IndexPtr,
|
|
||||||
}
|
|
||||||
|
|
||||||
const _: () = {
|
const _: () = {
|
||||||
if std::mem::align_of::<AllocSlab>() < std::mem::align_of::<*const ()>() {
|
if std::mem::align_of::<AllocSlab>() < std::mem::align_of::<*const ()>() {
|
||||||
panic!("alignment of AllocSlab is too low");
|
panic!("alignment of AllocSlab is too low");
|
||||||
@@ -706,34 +421,8 @@ const _: () = {
|
|||||||
if std::mem::offset_of!(AllocSlab, header) % std::mem::align_of::<*const ()>() != 0 {
|
if std::mem::offset_of!(AllocSlab, header) % std::mem::align_of::<*const ()>() != 0 {
|
||||||
panic!("alignment of header not a multiple of pointers alignment");
|
panic!("alignment of header not a multiple of pointers alignment");
|
||||||
}
|
}
|
||||||
|
|
||||||
if std::mem::offset_of!(AllocSlab, header) != std::mem::offset_of!(IndexPtrSlab, index_ptr) {
|
|
||||||
panic!("IndexPtrSlab.index_ptr and AllocSlab.header are at different offsets");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl IndexPtrSlab {
|
|
||||||
#[inline]
|
|
||||||
pub fn to_untyped(self: Box<Self>) -> (TypedArenaPtr<IndexPtr>, UntypedArenaSlab) {
|
|
||||||
let raw_box = Box::into_raw(self);
|
|
||||||
|
|
||||||
// safety: the pointer from Box::into_raw fullfills addr_of_mut's saftey requirements
|
|
||||||
let index_ptr_ptr = unsafe { ptr::addr_of_mut!((*raw_box).index_ptr) };
|
|
||||||
let allocated_ptr = TypedArenaPtr(
|
|
||||||
// safety: the pointer points into a valid allocation so it is non null
|
|
||||||
unsafe { NonNull::new_unchecked(index_ptr_ptr) },
|
|
||||||
);
|
|
||||||
|
|
||||||
let untyped_arena = UntypedArenaSlab {
|
|
||||||
// safety: pointer from Box::into_raw is never null
|
|
||||||
slab: unsafe { NonNull::new_unchecked(raw_box.cast::<AllocSlab>()) },
|
|
||||||
tag: <IndexPtr as ArenaAllocated>::tag(),
|
|
||||||
};
|
|
||||||
|
|
||||||
(allocated_ptr, untyped_arena)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TypedAllocSlab<T: ?Sized + ArenaAllocated> {
|
pub struct TypedAllocSlab<T: ?Sized + ArenaAllocated> {
|
||||||
@@ -786,7 +475,8 @@ impl Drop for UntypedArenaSlab {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Arena {
|
pub struct Arena {
|
||||||
base: Option<UntypedArenaSlab>,
|
base: Option<UntypedArenaSlab>,
|
||||||
pub f64_tbl: Arc<F64Table>,
|
pub f64_tbl: F64Table,
|
||||||
|
pub code_index_tbl: CodeIndexTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for Arena {}
|
unsafe impl Send for Arena {}
|
||||||
@@ -799,6 +489,7 @@ impl Arena {
|
|||||||
Arena {
|
Arena {
|
||||||
base: None,
|
base: None,
|
||||||
f64_tbl: F64Table::new(),
|
f64_tbl: F64Table::new(),
|
||||||
|
code_index_tbl: CodeIndexTable::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -874,11 +565,14 @@ unsafe fn drop_slab_in_place(value: NonNull<AllocSlab>, tag: ArenaHeaderTag) {
|
|||||||
ArenaHeaderTag::StandardErrorStream => {
|
ArenaHeaderTag::StandardErrorStream => {
|
||||||
drop_typed_slab_in_place!(StandardErrorStream, value);
|
drop_typed_slab_in_place!(StandardErrorStream, value);
|
||||||
}
|
}
|
||||||
ArenaHeaderTag::IndexPtrUndefined
|
ArenaHeaderTag::PipeReader => {
|
||||||
| ArenaHeaderTag::IndexPtrDynamicUndefined
|
drop_typed_slab_in_place!(PipeReader, value);
|
||||||
| ArenaHeaderTag::IndexPtrDynamicIndex
|
}
|
||||||
| ArenaHeaderTag::IndexPtrIndex => {
|
ArenaHeaderTag::PipeWriter => {
|
||||||
drop_typed_slab_in_place!(IndexPtr, value);
|
drop_typed_slab_in_place!(PipeWriter, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::ChildProcess => {
|
||||||
|
drop_typed_slab_in_place!(Child, value);
|
||||||
}
|
}
|
||||||
ArenaHeaderTag::NullStream => {
|
ArenaHeaderTag::NullStream => {
|
||||||
unreachable!("NullStream is never arena allocated!");
|
unreachable!("NullStream is never arena allocated!");
|
||||||
@@ -904,35 +598,34 @@ const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8);
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
use crate::machine::partial_string::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use crate::parser::dashu::{Integer, Rational};
|
use crate::parser::dashu::{Integer, Rational};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn float_ptr_cast() {
|
fn float_ptr_cast() {
|
||||||
let wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
let f = 0f64;
|
let f = 0f64;
|
||||||
let fp = float_alloc!(f, wam.machine_st.arena);
|
let fp = float_alloc!(f, wam.machine_st.arena);
|
||||||
let mut cell = HeapCellValue::from(fp.clone());
|
let mut cell = HeapCellValue::from(fp);
|
||||||
|
|
||||||
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
|
assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset);
|
||||||
assert!(!cell.get_mark_bit());
|
assert!(!cell.get_mark_bit());
|
||||||
assert_eq!(fp.deref(), &OrderedFloat(f));
|
assert_eq!(wam.machine_st.arena.f64_tbl.get_entry(fp), OrderedFloat(f));
|
||||||
|
|
||||||
cell.set_mark_bit(true);
|
cell.set_mark_bit(true);
|
||||||
|
|
||||||
assert!(cell.get_mark_bit());
|
assert!(cell.get_mark_bit());
|
||||||
|
|
||||||
read_heap_cell!(cell,
|
read_heap_cell!(cell,
|
||||||
(HeapCellValueTag::F64, ptr) => {
|
(HeapCellValueTag::F64Offset, offset) => {
|
||||||
assert_eq!(OrderedFloat(*ptr), OrderedFloat(f))
|
let fp = wam.machine_st.arena.f64_tbl.get_entry(offset);
|
||||||
|
assert_eq!(fp, OrderedFloat(0f64))
|
||||||
}
|
}
|
||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
);
|
);
|
||||||
@@ -943,12 +636,12 @@ mod tests {
|
|||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
let const_value = HeapCellValue::from(ConsPtr::build_with(
|
let const_value = HeapCellValue::from(ConsPtr::build_with(
|
||||||
0x0000_0431 as *const _,
|
std::ptr::without_provenance(0x0000_0431),
|
||||||
ConsPtrMaskTag::Cons,
|
ConsPtrMaskTag::Cons,
|
||||||
));
|
));
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
let const_value = HeapCellValue::from(ConsPtr::build_with(
|
let const_value = HeapCellValue::from(ConsPtr::build_with(
|
||||||
0x0000_5555_ff00_0431 as *const _,
|
std::ptr::without_provenance(0x0000_5555_ff00_0431),
|
||||||
ConsPtrMaskTag::Cons,
|
ConsPtrMaskTag::Cons,
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -992,7 +685,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(!big_int_ptr.as_ptr().is_null());
|
assert!(!big_int_ptr.as_ptr().is_null());
|
||||||
|
|
||||||
let cell = HeapCellValue::from(Literal::Integer(big_int_ptr));
|
let cell = HeapCellValue::from(big_int_ptr);
|
||||||
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
|
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
|
||||||
|
|
||||||
let untyped_arena_ptr = match cell.to_untyped_arena_ptr() {
|
let untyped_arena_ptr = match cell.to_untyped_arena_ptr() {
|
||||||
@@ -1098,31 +791,6 @@ mod tests {
|
|||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
);
|
);
|
||||||
|
|
||||||
// complete string
|
|
||||||
|
|
||||||
let pstr_var_cell =
|
|
||||||
put_partial_string(&mut wam.machine_st.heap, "ronan", &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 => {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// fixnum
|
||||||
|
|
||||||
let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3));
|
let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3));
|
||||||
@@ -1141,7 +809,9 @@ mod tests {
|
|||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
);
|
);
|
||||||
|
|
||||||
let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 54));
|
let fixnum_b_cell = fixnum_as_cell!(
|
||||||
|
Fixnum::build_with_checked(1i64 << 54).expect("1 << 54 fits in Fixnum")
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
|
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
|
||||||
|
|
||||||
@@ -1150,41 +820,29 @@ mod tests {
|
|||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if Fixnum::build_with_checked(1 << 56).is_ok() {
|
Fixnum::build_with_checked(1i64 << 56).expect_err("1 << 56 is too large for fixnum");
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
if Fixnum::build_with_checked(i64::MAX).is_ok() {
|
Fixnum::build_with_checked(i64::MAX).expect_err("i64::MAX is too large for Fixnum");
|
||||||
unreachable!()
|
Fixnum::build_with_checked(i64::MIN).expect_err("i64::MIN is too small for Fixnum");
|
||||||
}
|
assert_eq!(
|
||||||
|
Fixnum::build_with_checked(-1i64)
|
||||||
|
.expect("-1 fits in fixnum")
|
||||||
|
.get_num(),
|
||||||
|
-1
|
||||||
|
);
|
||||||
|
|
||||||
if Fixnum::build_with_checked(i64::MIN).is_ok() {
|
Fixnum::build_with_checked((1i64 << 55) - 1)
|
||||||
unreachable!()
|
.expect("(1 << 55) - 1 is the largest value that fits in Fixnum");
|
||||||
}
|
|
||||||
|
|
||||||
match Fixnum::build_with_checked(-1) {
|
Fixnum::build_with_checked(-(1i64 << 55))
|
||||||
Ok(n) => assert_eq!(n.get_num(), -1),
|
.expect("-(1 << 55) is the smallest value that fits in fixnum");
|
||||||
_ => unreachable!(),
|
Fixnum::build_with_checked(-(1i64 << 55) - 1)
|
||||||
}
|
.expect_err("-(1<<55) - 1 is too small for Fixnum");
|
||||||
|
|
||||||
match Fixnum::build_with_checked((1 << 55) - 1) {
|
assert_eq!(
|
||||||
Ok(n) => assert_eq!(n.get_num(), (1 << 55) - 1),
|
-Fixnum::build_with_checked(-1i64).expect("-1 fits in Fixnum"),
|
||||||
_ => unreachable!(),
|
Fixnum::build_with(1)
|
||||||
}
|
);
|
||||||
|
|
||||||
match Fixnum::build_with_checked(-(1 << 55)) {
|
|
||||||
Ok(n) => assert_eq!(n.get_num(), -(1 << 55)),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if Fixnum::build_with_checked(-(1 << 55) - 1).is_ok() {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
match Fixnum::build_with_checked(-1) {
|
|
||||||
Ok(n) => assert_eq!(-n, Fixnum::build_with(1)),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// float
|
// float
|
||||||
|
|
||||||
@@ -1192,7 +850,7 @@ mod tests {
|
|||||||
let float_ptr = float_alloc!(float, wam.machine_st.arena);
|
let float_ptr = float_alloc!(float, wam.machine_st.arena);
|
||||||
let cell = HeapCellValue::from(float_ptr);
|
let cell = HeapCellValue::from(float_ptr);
|
||||||
|
|
||||||
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
|
assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset);
|
||||||
|
|
||||||
// char
|
// char
|
||||||
|
|
||||||
@@ -1200,8 +858,8 @@ mod tests {
|
|||||||
let char_cell = char_as_cell!(c);
|
let char_cell = char_as_cell!(c);
|
||||||
|
|
||||||
read_heap_cell!(char_cell,
|
read_heap_cell!(char_cell,
|
||||||
(HeapCellValueTag::Char, c) => {
|
(HeapCellValueTag::Atom, (c, _arity)) => {
|
||||||
assert_eq!(c, 'c');
|
assert_eq!(&*c.as_str(), "c");
|
||||||
}
|
}
|
||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
);
|
);
|
||||||
@@ -1210,8 +868,8 @@ mod tests {
|
|||||||
let cyrillic_char_cell = char_as_cell!(c);
|
let cyrillic_char_cell = char_as_cell!(c);
|
||||||
|
|
||||||
read_heap_cell!(cyrillic_char_cell,
|
read_heap_cell!(cyrillic_char_cell,
|
||||||
(HeapCellValueTag::Char, c) => {
|
(HeapCellValueTag::Atom, (c, _arity)) => {
|
||||||
assert_eq!(c, 'Ћ');
|
assert_eq!(&*c.as_str(), "Ћ");
|
||||||
}
|
}
|
||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use crate::debray_allocator::*;
|
|||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::iterators::*;
|
use crate::iterators::*;
|
||||||
|
use crate::offset_table::*;
|
||||||
use crate::targets::QueryInstruction;
|
use crate::targets::QueryInstruction;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ impl<'a> ArithInstructionIterator<'a> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum ArithTermRef<'a> {
|
pub(crate) enum ArithTermRef<'a> {
|
||||||
Literal(&'a Literal),
|
Literal(Literal),
|
||||||
Op(Atom, usize), // name, arity.
|
Op(Atom, usize), // name, arity.
|
||||||
Var(Level, &'a Cell<VarReg>, VarPtr),
|
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||||
}
|
}
|
||||||
@@ -117,7 +118,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
|||||||
self.push_subterm(lvl.child_level(), &subterms[child_num]);
|
self.push_subterm(lvl.child_level(), &subterms[child_num]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
|
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(*c))),
|
||||||
TermIterState::Var(lvl, cell, var_ptr) => {
|
TermIterState::Var(lvl, cell, var_ptr) => {
|
||||||
return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr)));
|
return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr)));
|
||||||
}
|
}
|
||||||
@@ -137,6 +138,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct ArithmeticEvaluator<'a> {
|
pub(crate) struct ArithmeticEvaluator<'a> {
|
||||||
marker: &'a mut DebrayAllocator,
|
marker: &'a mut DebrayAllocator,
|
||||||
|
f64_tbl: &'a F64Table,
|
||||||
interm: Vec<ArithmeticTerm>,
|
interm: Vec<ArithmeticTerm>,
|
||||||
interm_c: usize,
|
interm_c: usize,
|
||||||
}
|
}
|
||||||
@@ -155,11 +157,18 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
|
fn push_literal(
|
||||||
|
f64_tbl: &F64Table,
|
||||||
|
interm: &mut Vec<ArithmeticTerm>,
|
||||||
|
c: &Literal,
|
||||||
|
) -> Result<(), ArithmeticError> {
|
||||||
match c {
|
match c {
|
||||||
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
|
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
|
||||||
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
|
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
|
||||||
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))),
|
&Literal::F64Offset(offset) => {
|
||||||
|
let n = f64_tbl.get_entry(offset);
|
||||||
|
interm.push(ArithmeticTerm::Number(Number::Float(n)));
|
||||||
|
}
|
||||||
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
|
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
|
||||||
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
|
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
|
||||||
Number::Float(OrderedFloat(std::f64::consts::E)),
|
Number::Float(OrderedFloat(std::f64::consts::E)),
|
||||||
@@ -177,9 +186,14 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), Ari
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ArithmeticEvaluator<'a> {
|
impl<'a> ArithmeticEvaluator<'a> {
|
||||||
pub(crate) fn new(marker: &'a mut DebrayAllocator, target_int: usize) -> Self {
|
pub(crate) fn new(
|
||||||
|
marker: &'a mut DebrayAllocator,
|
||||||
|
f64_tbl: &'a F64Table,
|
||||||
|
target_int: usize,
|
||||||
|
) -> Self {
|
||||||
ArithmeticEvaluator {
|
ArithmeticEvaluator {
|
||||||
marker,
|
marker,
|
||||||
|
f64_tbl,
|
||||||
interm: Vec::new(),
|
interm: Vec::new(),
|
||||||
interm_c: target_int,
|
interm_c: target_int,
|
||||||
}
|
}
|
||||||
@@ -317,7 +331,7 @@ impl<'a> ArithmeticEvaluator<'a> {
|
|||||||
|
|
||||||
for term_ref in src.iter()? {
|
for term_ref in src.iter()? {
|
||||||
match term_ref? {
|
match term_ref? {
|
||||||
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
|
ArithTermRef::Literal(c) => push_literal(self.f64_tbl, &mut self.interm, &c)?,
|
||||||
ArithTermRef::Var(lvl, cell, name) => {
|
ArithTermRef::Var(lvl, cell, name) => {
|
||||||
let var_num = name.to_var_num().unwrap();
|
let var_num = name.to_var_num().unwrap();
|
||||||
|
|
||||||
@@ -357,9 +371,8 @@ impl<'a> ArithmeticEvaluator<'a> {
|
|||||||
pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalError> {
|
pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalError> {
|
||||||
match n {
|
match n {
|
||||||
&Number::Integer(i) => {
|
&Number::Integer(i) => {
|
||||||
let result = (&*i).try_into();
|
if let Ok(value) = Fixnum::build_with_checked(&*i) {
|
||||||
if let Ok(value) = result {
|
Ok(Number::Fixnum(value))
|
||||||
Ok(fixnum!(Number, value, arena))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(*n)
|
Ok(*n)
|
||||||
}
|
}
|
||||||
@@ -368,11 +381,14 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalErro
|
|||||||
&Number::Float(f) => {
|
&Number::Float(f) => {
|
||||||
let f = f.floor();
|
let f = f.floor();
|
||||||
|
|
||||||
const I64_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MIN as f64);
|
const FIXNUM_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MIN as f64);
|
||||||
const I64_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MAX as f64);
|
const FIXNUM_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MAX as f64);
|
||||||
|
|
||||||
if I64_MIN_TO_F <= f && f <= I64_MAX_TO_F {
|
if (FIXNUM_MIN_TO_F..=FIXNUM_MAX_TO_F).contains(&f) {
|
||||||
Ok(fixnum!(Number, f.into_inner() as i64, arena))
|
Ok(Number::Fixnum(
|
||||||
|
// Safety: We checked that the value is in range
|
||||||
|
unsafe { Fixnum::build_with_unchecked(f.into_inner() as i64) },
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(Number::Integer(arena_alloc!(
|
Ok(Number::Integer(arena_alloc!(
|
||||||
Integer::try_from(classify_float(f.0)?).unwrap_or_else(|_| {
|
Integer::try_from(classify_float(f.0)?).unwrap_or_else(|_| {
|
||||||
@@ -385,8 +401,8 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalErro
|
|||||||
Number::Rational(ref r) => {
|
Number::Rational(ref r) => {
|
||||||
let floor = r.floor();
|
let floor = r.floor();
|
||||||
|
|
||||||
if let Ok(value) = (&floor).try_into() {
|
if let Ok(value) = Fixnum::build_with_checked(&floor) {
|
||||||
Ok(fixnum!(Number, value, arena))
|
Ok(Number::Fixnum(value))
|
||||||
} else {
|
} else {
|
||||||
Ok(Number::Integer(arena_alloc!(floor, arena)))
|
Ok(Number::Integer(arena_alloc!(floor, arena)))
|
||||||
}
|
}
|
||||||
@@ -649,11 +665,11 @@ impl Ord for Number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<HeapCellValue> for Number {
|
impl TryFrom<(HeapCellValue, &'_ F64Table)> for Number {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_from(value: HeapCellValue) -> Result<Number, Self::Error> {
|
fn try_from((value, f64_tbl): (HeapCellValue, &F64Table)) -> Result<Number, Self::Error> {
|
||||||
read_heap_cell!(value,
|
read_heap_cell!(value,
|
||||||
(HeapCellValueTag::Cons, c) => {
|
(HeapCellValueTag::Cons, c) => {
|
||||||
match_untyped_arena_ptr!(c,
|
match_untyped_arena_ptr!(c,
|
||||||
@@ -668,8 +684,9 @@ impl TryFrom<HeapCellValue> for Number {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::F64, n) => {
|
(HeapCellValueTag::F64Offset, offset) => {
|
||||||
Ok(Number::Float(*n))
|
let n = f64_tbl.get_entry(offset);
|
||||||
|
Ok(Number::Float(n))
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
|
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
|
||||||
Ok(Number::Fixnum(n))
|
Ok(Number::Fixnum(n))
|
||||||
|
|||||||
@@ -23,15 +23,124 @@ use indexmap::IndexSet;
|
|||||||
|
|
||||||
use scryer_modular_bitfield::prelude::*;
|
use scryer_modular_bitfield::prelude::*;
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct AtomCell {
|
||||||
|
name: B48,
|
||||||
|
arity: B8,
|
||||||
|
#[allow(unused)]
|
||||||
|
f: bool,
|
||||||
|
#[allow(unused)]
|
||||||
|
m: bool,
|
||||||
|
#[allow(unused)]
|
||||||
|
is_inlined: bool,
|
||||||
|
#[allow(unused)]
|
||||||
|
tag: B5,
|
||||||
|
}
|
||||||
|
|
||||||
|
const INLINED_ATOM_MAX_LEN: usize = 6;
|
||||||
|
|
||||||
|
const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::<AtomCell>());
|
||||||
|
const_assert!(mem::size_of::<AtomCell>() == 8);
|
||||||
|
|
||||||
|
const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::<Atom>());
|
||||||
|
const_assert!(mem::size_of::<Atom>() == 8);
|
||||||
|
|
||||||
|
impl AtomCell {
|
||||||
|
#[inline]
|
||||||
|
fn new_static(index: u64) -> Self {
|
||||||
|
// upper 23 bits of index must be 0
|
||||||
|
debug_assert_eq!(index & !((1 << 49) - 1), 0);
|
||||||
|
AtomCell::new()
|
||||||
|
.with_name(index)
|
||||||
|
.with_arity(0u8)
|
||||||
|
.with_m(false)
|
||||||
|
.with_f(false)
|
||||||
|
.with_is_inlined(false)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn new_inlined(string: &str, arity: u8) -> Self {
|
||||||
|
debug_assert!(string.len() <= INLINED_ATOM_MAX_LEN);
|
||||||
|
|
||||||
|
let mut string_buf: [u8; 8] = [0u8; 8];
|
||||||
|
string_buf[..string.len()].copy_from_slice(string.as_bytes());
|
||||||
|
let encoding = u64::from_le_bytes(string_buf);
|
||||||
|
|
||||||
|
AtomCell::new()
|
||||||
|
.with_name(encoding)
|
||||||
|
.with_arity(arity)
|
||||||
|
.with_m(false)
|
||||||
|
.with_f(false)
|
||||||
|
.with_is_inlined(true)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new_char_inlined(c: char) -> Self {
|
||||||
|
if c == '\u{0}' {
|
||||||
|
return Self::new_static(NULL_ATOM.flat_index());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut char_buf = [0u8; 8];
|
||||||
|
c.encode_utf8(&mut char_buf);
|
||||||
|
|
||||||
|
let encoding = u64::from_le_bytes(char_buf);
|
||||||
|
|
||||||
|
AtomCell::new()
|
||||||
|
.with_name(encoding)
|
||||||
|
.with_arity(0u8)
|
||||||
|
.with_m(false)
|
||||||
|
.with_f(false)
|
||||||
|
.with_is_inlined(true)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn build_with(atom_index: u64, arity: u8) -> Self {
|
||||||
|
debug_assert!((arity as usize) <= MAX_ARITY);
|
||||||
|
|
||||||
|
AtomCell::new()
|
||||||
|
.with_name(atom_index >> 1)
|
||||||
|
.with_arity(arity)
|
||||||
|
.with_f(false)
|
||||||
|
.with_m(false)
|
||||||
|
.with_is_inlined(atom_index & 1 == 1)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_name(self) -> Atom {
|
||||||
|
Atom {
|
||||||
|
index: (self.name() << 1) | self.is_inlined() as u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_arity(self) -> usize {
|
||||||
|
self.arity() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_name_and_arity(self) -> (Atom, usize) {
|
||||||
|
(self.get_name(), self.get_arity())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Atom {
|
pub struct Atom {
|
||||||
pub index: u64,
|
pub index: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
const_assert!(mem::size_of::<Atom>() == 8);
|
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/static_atoms.rs"));
|
include!(concat!(env!("OUT_DIR"), "/static_atoms.rs"));
|
||||||
|
|
||||||
|
// populate these in STRINGS so they can be used from build_functor
|
||||||
|
const _: Atom = atom!(".");
|
||||||
|
const _: Atom = atom!("[]");
|
||||||
|
const NULL_ATOM: Atom = atom!("\0");
|
||||||
|
|
||||||
impl<'a> From<&'a Atom> for Atom {
|
impl<'a> From<&'a Atom> for Atom {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(atom: &'a Atom) -> Self {
|
fn from(atom: &'a Atom) -> Self {
|
||||||
@@ -39,17 +148,6 @@ impl<'a> From<&'a Atom> for Atom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<bool> for Atom {
|
|
||||||
#[inline]
|
|
||||||
fn from(value: bool) -> Self {
|
|
||||||
if value {
|
|
||||||
atom!("true")
|
|
||||||
} else {
|
|
||||||
atom!("false")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl indexmap::Equivalent<Atom> for str {
|
impl indexmap::Equivalent<Atom> for str {
|
||||||
fn equivalent(&self, key: &Atom) -> bool {
|
fn equivalent(&self, key: &Atom) -> bool {
|
||||||
&*key.as_str() == self
|
&*key.as_str() == self
|
||||||
@@ -120,25 +218,23 @@ impl Hash for Atom {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
self.as_str().hash(hasher)
|
self.as_str().hash(hasher)
|
||||||
// hasher.write_usize(self.index)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum AtomString<'a> {
|
pub enum AtomString<'a> {
|
||||||
Static(&'a str),
|
Static(&'a str),
|
||||||
|
Inlined([u8; 8]),
|
||||||
Dynamic(AtomTableRef<str>),
|
Dynamic(AtomTableRef<str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AtomString<'_> {
|
#[inline(always)]
|
||||||
pub fn map<F>(self, f: F) -> Self
|
fn inlined_to_str(bytes: &[u8; 8]) -> &str {
|
||||||
where
|
let slice_len = bytes
|
||||||
for<'a> F: FnOnce(&'a str) -> &'a str,
|
.iter()
|
||||||
{
|
.position(|&b| b == 0u8)
|
||||||
match self {
|
.unwrap_or(INLINED_ATOM_MAX_LEN);
|
||||||
Self::Static(reference) => Self::Static(f(reference)),
|
|
||||||
Self::Dynamic(guard) => Self::Dynamic(AtomTableRef::map(guard, f)),
|
unsafe { str::from_utf8_unchecked(&bytes[..slice_len]) }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for AtomString<'_> {
|
impl std::fmt::Debug for AtomString<'_> {
|
||||||
@@ -158,6 +254,7 @@ impl std::ops::Deref for AtomString<'_> {
|
|||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
match self {
|
match self {
|
||||||
Self::Static(reference) => reference,
|
Self::Static(reference) => reference,
|
||||||
|
Self::Inlined(inlined) => inlined_to_str(inlined),
|
||||||
Self::Dynamic(guard) => guard.deref(),
|
Self::Dynamic(guard) => guard.deref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,13 +272,32 @@ impl rustyline::completion::Candidate for AtomString<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Atom {
|
impl Atom {
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn is_static(self) -> bool {
|
fn new_inlined(string: &str) -> Self {
|
||||||
(self.index as usize) < STRINGS.len() << 3
|
AtomCell::new_inlined(string, 0).get_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn as_ptr(self) -> Option<AtomTableRef<AtomData>> {
|
fn is_static(self) -> bool {
|
||||||
|
if self.is_inlined() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
(self.flat_index() as usize) < STRINGS.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn flat_index(self) -> u64 {
|
||||||
|
self.index >> 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn is_inlined(self) -> bool {
|
||||||
|
self.index & 1 == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_ptr(self) -> Option<AtomTableRef<AtomData>> {
|
||||||
if self.is_static() {
|
if self.is_static() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@@ -192,7 +308,7 @@ impl Atom {
|
|||||||
let ptr = buf
|
let ptr = buf
|
||||||
.block
|
.block
|
||||||
.base
|
.base
|
||||||
.add((self.index as usize) - (STRINGS.len() << 3));
|
.add(self.flat_index() as usize - STRINGS.len());
|
||||||
// TODO use std::ptr::from_raw_parts instead when feature ptr_metadata is stable rust-lang/rust#81513
|
// TODO use std::ptr::from_raw_parts instead when feature ptr_metadata is stable rust-lang/rust#81513
|
||||||
let atom_data = &*(std::ptr::slice_from_raw_parts(ptr, 0) as *const AtomData);
|
let atom_data = &*(std::ptr::slice_from_raw_parts(ptr, 0) as *const AtomData);
|
||||||
let len = atom_data.header.len();
|
let len = atom_data.header.len();
|
||||||
@@ -208,8 +324,11 @@ impl Atom {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn len(self) -> usize {
|
pub fn len(self) -> usize {
|
||||||
if self.is_static() {
|
if let Some(s) = self.inlined_str() {
|
||||||
STRINGS[(self.index >> 3) as usize].len()
|
s.len()
|
||||||
|
} else if self.is_static() {
|
||||||
|
let index = self.flat_index();
|
||||||
|
STRINGS[index as usize].len()
|
||||||
} else {
|
} else {
|
||||||
let len: u64 = self.as_ptr().unwrap().header.len();
|
let len: u64 = self.as_ptr().unwrap().header.len();
|
||||||
len as usize
|
len as usize
|
||||||
@@ -220,11 +339,6 @@ impl Atom {
|
|||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn flat_index(self) -> u64 {
|
|
||||||
self.index >> 3
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_char(self) -> Option<char> {
|
pub fn as_char(self) -> Option<char> {
|
||||||
let s = self.as_str();
|
let s = self.as_str();
|
||||||
let mut it = s.chars();
|
let mut it = s.chars();
|
||||||
@@ -239,14 +353,26 @@ impl Atom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn inlined_str<'a>(&self) -> Option<AtomString<'a>> {
|
||||||
|
if self.is_inlined() {
|
||||||
|
Some(AtomString::Inlined(self.flat_index().to_le_bytes()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_str(&self) -> AtomString<'static> {
|
pub fn as_str(&self) -> AtomString<'static> {
|
||||||
if self.is_static() {
|
if let Some(s) = self.inlined_str() {
|
||||||
AtomString::Static(STRINGS[(self.index >> 3) as usize])
|
s
|
||||||
|
} else if self.is_static() {
|
||||||
|
let index = self.flat_index() as usize;
|
||||||
|
AtomString::Static(STRINGS[index])
|
||||||
} else if let Some(ptr) = self.as_ptr() {
|
} else if let Some(ptr) = self.as_ptr() {
|
||||||
AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| &ptr.data))
|
AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| &ptr.data))
|
||||||
} else {
|
} else {
|
||||||
AtomString::Static(STRINGS[(self.index >> 3) as usize])
|
AtomString::Static(STRINGS[(self.index >> 1) as usize])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,6 +468,10 @@ impl AtomTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom {
|
pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom {
|
||||||
|
if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') {
|
||||||
|
return Atom::new_inlined(string);
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut block_epoch = atom_table.inner.read();
|
let mut block_epoch = atom_table.inner.read();
|
||||||
let mut table_epoch = block_epoch.table.read();
|
let mut table_epoch = block_epoch.table.read();
|
||||||
@@ -386,13 +516,18 @@ impl AtomTable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ptr_base = block_epoch.block.base as usize;
|
let ptr_base = block_epoch.block.base.addr();
|
||||||
|
|
||||||
write_to_ptr(string, len_ptr);
|
write_to_ptr(string, len_ptr);
|
||||||
|
|
||||||
let atom = Atom {
|
let atom = AtomCell::new()
|
||||||
index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64,
|
.with_name((STRINGS.len() + len_ptr.addr() - ptr_base) as u64)
|
||||||
};
|
.with_arity(0)
|
||||||
|
.with_f(false)
|
||||||
|
.with_m(false)
|
||||||
|
.with_is_inlined(false)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
.get_name();
|
||||||
|
|
||||||
let mut table = table_epoch.clone();
|
let mut table = table_epoch.clone();
|
||||||
table.insert(atom);
|
table.insert(atom);
|
||||||
@@ -409,57 +544,3 @@ impl AtomTable {
|
|||||||
|
|
||||||
unsafe impl Send for AtomTable {}
|
unsafe impl Send for AtomTable {}
|
||||||
unsafe impl Sync for AtomTable {}
|
unsafe impl Sync for AtomTable {}
|
||||||
|
|
||||||
#[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() as u64) << 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() as u64) << 3), self.get_arity())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
171
src/codegen.rs
171
src/codegen.rs
@@ -6,6 +6,7 @@ use crate::forms::*;
|
|||||||
use crate::indexing::*;
|
use crate::indexing::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::iterators::*;
|
use crate::iterators::*;
|
||||||
|
use crate::offset_table::F64Table;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::targets::*;
|
use crate::targets::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
@@ -269,10 +270,10 @@ impl CodeGenSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct CodeGenerator<'a> {
|
pub(crate) struct CodeGenerator<'f64_tbl> {
|
||||||
pub(crate) atom_tbl: &'a AtomTable,
|
|
||||||
marker: DebrayAllocator,
|
marker: DebrayAllocator,
|
||||||
settings: CodeGenSettings,
|
settings: CodeGenSettings,
|
||||||
|
f64_tbl: &'f64_tbl F64Table,
|
||||||
pub(crate) skeleton: PredicateSkeleton,
|
pub(crate) skeleton: PredicateSkeleton,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,33 +320,12 @@ impl DebrayAllocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the final argument of the structure is a Literal::Index,
|
|
||||||
// decrement the arity of the PutStructure instruction by 1.
|
|
||||||
fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) {
|
|
||||||
match instr {
|
|
||||||
Instruction::PutStructure(_, ref mut arity, _)
|
|
||||||
| Instruction::GetStructure(.., ref mut arity, _) => {
|
|
||||||
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
|
|
||||||
// it is acceptable if arity == 0 is the result of
|
|
||||||
// this decrement. call/N will have to read the index
|
|
||||||
// constant for '$call_inline' to succeed. to find it,
|
|
||||||
// it must know the heap location of the index.
|
|
||||||
// self.store must stop before reading the atom into a
|
|
||||||
// register.
|
|
||||||
|
|
||||||
*arity -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait AddToFreeList<'a, Target: CompilationTarget<'a>> {
|
trait AddToFreeList<'a, Target: CompilationTarget<'a>> {
|
||||||
fn add_term_to_free_list(&mut self, r: RegType);
|
fn add_term_to_free_list(&mut self, r: RegType);
|
||||||
fn add_subterm_to_free_list(&mut self, term: &Term);
|
fn add_subterm_to_free_list(&mut self, term: &Term);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> {
|
impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator<'_> {
|
||||||
fn add_term_to_free_list(&mut self, r: RegType) {
|
fn add_term_to_free_list(&mut self, r: RegType) {
|
||||||
self.marker.add_reg_to_free_list(r);
|
self.marker.add_reg_to_free_list(r);
|
||||||
}
|
}
|
||||||
@@ -353,7 +333,7 @@ impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> {
|
|||||||
fn add_subterm_to_free_list(&mut self, _term: &Term) {}
|
fn add_subterm_to_free_list(&mut self, _term: &Term) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> {
|
impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'_> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn add_term_to_free_list(&mut self, _r: RegType) {}
|
fn add_term_to_free_list(&mut self, _r: RegType) {}
|
||||||
|
|
||||||
@@ -375,12 +355,12 @@ fn structure_cell(term: &Term) -> Option<&Cell<RegType>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> CodeGenerator<'b> {
|
impl<'f64_tbl> CodeGenerator<'f64_tbl> {
|
||||||
pub(crate) fn new(atom_tbl: &'b AtomTable, settings: CodeGenSettings) -> Self {
|
pub(crate) fn new(f64_tbl: &'f64_tbl F64Table, settings: CodeGenSettings) -> Self {
|
||||||
CodeGenerator {
|
CodeGenerator {
|
||||||
atom_tbl,
|
|
||||||
marker: DebrayAllocator::new(),
|
marker: DebrayAllocator::new(),
|
||||||
settings,
|
settings,
|
||||||
|
f64_tbl,
|
||||||
skeleton: PredicateSkeleton::new(),
|
skeleton: PredicateSkeleton::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,99 +426,99 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, term_loc: GenContext) -> CodeDeque
|
fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, context: GenContext) -> CodeDeque
|
||||||
where
|
where
|
||||||
Target: crate::targets::CompilationTarget<'a>,
|
Target: crate::targets::CompilationTarget<'a>,
|
||||||
Iter: Iterator<Item = TermRef<'a>>,
|
Iter: Iterator<Item = TermRef<'a>>,
|
||||||
CodeGenerator<'b>: AddToFreeList<'a, Target>,
|
CodeGenerator<'f64_tbl>: AddToFreeList<'a, Target>,
|
||||||
{
|
{
|
||||||
let mut target = CodeDeque::new();
|
let mut target = CodeDeque::new();
|
||||||
|
|
||||||
for term in iter {
|
for term in iter {
|
||||||
match term {
|
match term {
|
||||||
TermRef::AnonVar(lvl @ Level::Shallow) => {
|
TermRef::AnonVar(lvl @ Level::Shallow) => {
|
||||||
if let GenContext::Head = term_loc {
|
if let GenContext::Head = context {
|
||||||
self.marker.advance_arg();
|
self.marker.advance_arg();
|
||||||
} else {
|
} else {
|
||||||
self.marker
|
self.marker
|
||||||
.mark_anon_var::<Target>(lvl, term_loc, &mut target);
|
.mark_anon_var::<Target>(lvl, context, &mut target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermRef::Clause(lvl, cell, name, terms) => {
|
TermRef::Clause(lvl, cell, name, terms) => {
|
||||||
self.marker
|
let terms_range =
|
||||||
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
if let Some(subterm @ Term::Literal(_, Literal::CodeIndexOffset(_))) =
|
||||||
target.push_back(Target::to_structure(lvl, name, terms.len(), cell.get()));
|
terms.last()
|
||||||
|
{
|
||||||
|
self.subterm_to_instr::<Target>(subterm, context, &mut target);
|
||||||
|
0..terms.len() - 1
|
||||||
|
} else {
|
||||||
|
0..terms.len()
|
||||||
|
};
|
||||||
|
|
||||||
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
|
self.marker
|
||||||
|
.mark_non_var::<Target>(lvl, context, cell, &mut target);
|
||||||
|
target.push_back(Target::to_structure(lvl, name, terms_range.end, cell.get()));
|
||||||
|
|
||||||
|
<CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
|
||||||
self,
|
self,
|
||||||
cell.get(),
|
cell.get(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(instr) = target.back_mut() {
|
for subterm in &terms[terms_range.clone()] {
|
||||||
if let Some(term) = terms.last() {
|
self.subterm_to_instr::<Target>(subterm, context, &mut target);
|
||||||
trim_structure_by_last_arg(instr, term);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for subterm in terms {
|
for subterm in &terms[terms_range] {
|
||||||
self.subterm_to_instr::<Target>(subterm, term_loc, &mut target);
|
<CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
|
||||||
}
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
|
|
||||||
self, subterm,
|
self, subterm,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermRef::Cons(lvl, cell, head, tail) => {
|
TermRef::Cons(lvl, cell, head, tail) => {
|
||||||
self.marker
|
self.marker
|
||||||
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
.mark_non_var::<Target>(lvl, context, cell, &mut target);
|
||||||
target.push_back(Target::to_list(lvl, cell.get()));
|
target.push_back(Target::to_list(lvl, cell.get()));
|
||||||
|
|
||||||
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
|
<CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
|
||||||
self,
|
self,
|
||||||
cell.get(),
|
cell.get(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.subterm_to_instr::<Target>(head, term_loc, &mut target);
|
self.subterm_to_instr::<Target>(head, context, &mut target);
|
||||||
self.subterm_to_instr::<Target>(tail, term_loc, &mut target);
|
self.subterm_to_instr::<Target>(tail, context, &mut target);
|
||||||
|
|
||||||
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
|
<CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
|
||||||
self, head,
|
self, head,
|
||||||
);
|
);
|
||||||
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
|
<CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
|
||||||
self, tail,
|
self, tail,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => {
|
|
||||||
self.marker
|
|
||||||
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
|
||||||
target.push_back(Target::to_pstr(lvl, *string, cell.get(), false));
|
|
||||||
}
|
|
||||||
TermRef::Literal(lvl @ Level::Shallow, cell, constant) => {
|
TermRef::Literal(lvl @ Level::Shallow, cell, constant) => {
|
||||||
self.marker
|
self.marker
|
||||||
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
.mark_non_var::<Target>(lvl, context, cell, &mut target);
|
||||||
target.push_back(Target::to_constant(lvl, *constant, cell.get()));
|
target.push_back(Target::to_constant(lvl, *constant, cell.get()));
|
||||||
}
|
}
|
||||||
TermRef::PartialString(lvl, cell, string, tail) => {
|
TermRef::PartialString(lvl, cell, string, tail) => {
|
||||||
self.marker
|
self.marker
|
||||||
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
.mark_non_var::<Target>(lvl, context, cell, &mut target);
|
||||||
let atom = AtomTable::build_with(self.atom_tbl, string);
|
|
||||||
|
|
||||||
target.push_back(Target::to_pstr(lvl, atom, cell.get(), true));
|
target.push_back(Target::to_pstr(lvl, string.clone(), cell.get()));
|
||||||
self.subterm_to_instr::<Target>(tail, term_loc, &mut target);
|
self.subterm_to_instr::<Target>(tail, context, &mut target);
|
||||||
}
|
}
|
||||||
TermRef::CompleteString(lvl, cell, atom) => {
|
TermRef::CompleteString(lvl, cell, string) => {
|
||||||
self.marker
|
self.marker
|
||||||
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
|
.mark_non_var::<Target>(lvl, context, cell, &mut target);
|
||||||
target.push_back(Target::to_pstr(lvl, atom, cell.get(), false));
|
|
||||||
|
target.push_back(Target::to_pstr(lvl, string.clone(), cell.get()));
|
||||||
|
target.push_back(Target::constant_subterm(Literal::Atom(atom!("[]"))));
|
||||||
}
|
}
|
||||||
TermRef::Var(lvl @ Level::Shallow, cell, var) => {
|
TermRef::Var(lvl @ Level::Shallow, cell, var) => {
|
||||||
self.marker.mark_var::<Target>(
|
self.marker.mark_var::<Target>(
|
||||||
var.to_var_num().unwrap(),
|
var.to_var_num().unwrap(),
|
||||||
lvl,
|
lvl,
|
||||||
cell,
|
cell,
|
||||||
term_loc,
|
context,
|
||||||
&mut target,
|
&mut target,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -600,9 +580,7 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
compare_number_instr!(cmp, at_1, at_2)
|
compare_number_instr!(cmp, at_1, at_2)
|
||||||
}
|
}
|
||||||
InlinedClauseType::IsAtom(..) => match &terms[0] {
|
InlinedClauseType::IsAtom(..) => match &terms[0] {
|
||||||
Term::Literal(_, Literal::Char(_))
|
Term::Literal(_, Literal::Atom(..)) => {
|
||||||
| Term::Literal(_, Literal::Atom(atom!("[]")))
|
|
||||||
| Term::Literal(_, Literal::Atom(..)) => {
|
|
||||||
instr!("$succeed")
|
instr!("$succeed")
|
||||||
}
|
}
|
||||||
Term::Var(ref vr, ref name) => {
|
Term::Var(ref vr, ref name) => {
|
||||||
@@ -630,9 +608,6 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
| Term::CompleteString(..) => {
|
| Term::CompleteString(..) => {
|
||||||
instr!("$fail")
|
instr!("$fail")
|
||||||
}
|
}
|
||||||
Term::Literal(_, Literal::String(_)) => {
|
|
||||||
instr!("$fail")
|
|
||||||
}
|
|
||||||
Term::Literal(..) => {
|
Term::Literal(..) => {
|
||||||
instr!("$succeed")
|
instr!("$succeed")
|
||||||
}
|
}
|
||||||
@@ -654,8 +629,7 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
Term::Clause(..)
|
Term::Clause(..)
|
||||||
| Term::Cons(..)
|
| Term::Cons(..)
|
||||||
| Term::PartialString(..)
|
| Term::PartialString(..)
|
||||||
| Term::CompleteString(..)
|
| Term::CompleteString(..) => {
|
||||||
| Term::Literal(_, Literal::String(..)) => {
|
|
||||||
instr!("$succeed")
|
instr!("$succeed")
|
||||||
}
|
}
|
||||||
Term::Var(ref vr, ref name) => {
|
Term::Var(ref vr, ref name) => {
|
||||||
@@ -695,7 +669,7 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
InlinedClauseType::IsFloat(..) => match terms[0] {
|
InlinedClauseType::IsFloat(..) => match terms[0] {
|
||||||
Term::Literal(_, Literal::Float(_)) => {
|
Term::Literal(_, Literal::F64Offset(_)) => {
|
||||||
instr!("$succeed")
|
instr!("$succeed")
|
||||||
}
|
}
|
||||||
Term::Var(ref vr, ref name) => {
|
Term::Var(ref vr, ref name) => {
|
||||||
@@ -716,7 +690,7 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
InlinedClauseType::IsNumber(..) => match terms[0] {
|
InlinedClauseType::IsNumber(..) => match terms[0] {
|
||||||
Term::Literal(_, Literal::Float(_))
|
Term::Literal(_, Literal::F64Offset(_))
|
||||||
| Term::Literal(_, Literal::Rational(_))
|
| Term::Literal(_, Literal::Rational(_))
|
||||||
| Term::Literal(_, Literal::Integer(_))
|
| Term::Literal(_, Literal::Integer(_))
|
||||||
| Term::Literal(_, Literal::Fixnum(_)) => {
|
| Term::Literal(_, Literal::Fixnum(_)) => {
|
||||||
@@ -810,7 +784,6 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
|
|
||||||
// inlined predicates are never counted, so this overrides nothing.
|
// inlined predicates are never counted, so this overrides nothing.
|
||||||
self.add_call(code, call_instr, CallPolicy::Counted);
|
self.add_call(code, call_instr, CallPolicy::Counted);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,7 +794,7 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
arg: usize,
|
arg: usize,
|
||||||
) -> Result<ArithCont, ArithmeticError> {
|
) -> Result<ArithCont, ArithmeticError> {
|
||||||
let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int);
|
let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, self.f64_tbl, target_int);
|
||||||
evaluator.compile_is(term, term_loc, arg)
|
evaluator.compile_is(term, term_loc, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,7 +864,7 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
Term::Literal(
|
Term::Literal(
|
||||||
_,
|
_,
|
||||||
c @ Literal::Integer(_)
|
c @ Literal::Integer(_)
|
||||||
| c @ Literal::Float(_)
|
| c @ Literal::F64Offset(_)
|
||||||
| c @ Literal::Rational(_)
|
| c @ Literal::Rational(_)
|
||||||
| c @ Literal::Fixnum(_),
|
| c @ Literal::Fixnum(_),
|
||||||
) => {
|
) => {
|
||||||
@@ -909,7 +882,6 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
|
|
||||||
let at = at.unwrap_or(interm!(1));
|
let at = at.unwrap_or(interm!(1));
|
||||||
self.add_call(code, instr!("is", temp_v!(1), at), call_policy);
|
self.add_call(code, instr!("is", temp_v!(1), at), call_policy);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,9 +896,9 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
|
|
||||||
while let Some(clause_item) = clause_iter.next() {
|
while let Some(clause_item) = clause_iter.next() {
|
||||||
match clause_item {
|
match clause_item {
|
||||||
ClauseItem::Chunk(chunk) => {
|
ClauseItem::Chunk { terms } => {
|
||||||
for (idx, term) in chunk.iter().enumerate() {
|
for (idx, term) in terms.iter().enumerate() {
|
||||||
let term_loc = if idx + 1 < chunk.len() {
|
let term_loc = if idx + 1 < terms.len() {
|
||||||
GenContext::Mid(chunk_num)
|
GenContext::Mid(chunk_num)
|
||||||
} else {
|
} else {
|
||||||
self.marker.in_tail_position = clause_iter.in_tail_position();
|
self.marker.in_tail_position = clause_iter.in_tail_position();
|
||||||
@@ -1147,27 +1119,24 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
'outer: for (right, clause) in clauses.iter().enumerate() {
|
'outer: for (right, clause) in clauses.iter().enumerate() {
|
||||||
if let Some(args) = clause.args() {
|
if let Some(args) = clause.args() {
|
||||||
for (instantiated_arg_index, arg) in args.iter().enumerate() {
|
for (instantiated_arg_index, arg) in args.iter().enumerate() {
|
||||||
match arg {
|
if !matches!(arg, Term::Var(..) | Term::AnonVar) {
|
||||||
Term::Var(..) | Term::AnonVar => {}
|
if optimal_index != instantiated_arg_index {
|
||||||
_ => {
|
if left >= right {
|
||||||
if optimal_index != instantiated_arg_index {
|
|
||||||
if left >= right {
|
|
||||||
optimal_index = instantiated_arg_index;
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
|
|
||||||
subseqs.push(ClauseSpan {
|
|
||||||
left,
|
|
||||||
right,
|
|
||||||
instantiated_arg_index: optimal_index,
|
|
||||||
});
|
|
||||||
|
|
||||||
optimal_index = instantiated_arg_index;
|
optimal_index = instantiated_arg_index;
|
||||||
left = right;
|
continue 'outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue 'outer;
|
subseqs.push(ClauseSpan {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
instantiated_arg_index: optimal_index,
|
||||||
|
});
|
||||||
|
|
||||||
|
optimal_index = instantiated_arg_index;
|
||||||
|
left = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continue 'outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1260,7 +1229,7 @@ impl<'b> CodeGenerator<'b> {
|
|||||||
let index = code.len();
|
let index = code.len();
|
||||||
|
|
||||||
if clauses_len > 1 || self.settings.is_extensible {
|
if clauses_len > 1 || self.settings.is_extensible {
|
||||||
code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl);
|
code_offsets.index_term(arg, index, &mut clause_index_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::allocator::*;
|
use crate::allocator::*;
|
||||||
use crate::codegen::SubsumedBranchHits;
|
use crate::codegen::SubsumedBranchHits;
|
||||||
use crate::forms::Level;
|
use crate::forms::{GenContext, Level};
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::machine::disjuncts::VarData;
|
use crate::machine::disjuncts::VarData;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
@@ -251,7 +251,7 @@ impl DebrayAllocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.branch_stack.len() > 0 {
|
if !self.branch_stack.is_empty() {
|
||||||
for var_num in subsumed_hits {
|
for var_num in subsumed_hits {
|
||||||
self.branch_stack.add_branch_occurrence(var_num);
|
self.branch_stack.add_branch_occurrence(var_num);
|
||||||
}
|
}
|
||||||
@@ -534,7 +534,9 @@ impl DebrayAllocator {
|
|||||||
VarAlloc::Temp { safety, .. } => {
|
VarAlloc::Temp { safety, .. } => {
|
||||||
*safety = VarSafetyStatus::unneeded(branch_designator);
|
*safety = VarSafetyStatus::unneeded(branch_designator);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,7 +681,7 @@ impl Allocator for DebrayAllocator {
|
|||||||
lvl: Level,
|
lvl: Level,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
code: &mut CodeDeque,
|
code: &mut CodeDeque,
|
||||||
) {
|
) -> RegType {
|
||||||
let r = RegType::Temp(self.alloc_reg_to_non_var());
|
let r = RegType::Temp(self.alloc_reg_to_non_var());
|
||||||
|
|
||||||
match lvl {
|
match lvl {
|
||||||
@@ -696,6 +698,8 @@ impl Allocator for DebrayAllocator {
|
|||||||
code.push_back(Target::argument_to_variable(r, k));
|
code.push_back(Target::argument_to_variable(r, k));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ impl ForeignFunctionTable {
|
|||||||
let mut pointer_args =
|
let mut pointer_args =
|
||||||
Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?;
|
Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?;
|
||||||
|
|
||||||
return unsafe {
|
unsafe {
|
||||||
macro_rules! call_and_return {
|
macro_rules! call_and_return {
|
||||||
($type:ty) => {{
|
($type:ty) => {{
|
||||||
let mut n: Box<u8> = Box::new(0);
|
let mut n: Box<u8> = Box::new(0);
|
||||||
@@ -410,7 +410,7 @@ impl ForeignFunctionTable {
|
|||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_struct(
|
fn read_struct(
|
||||||
@@ -517,7 +517,7 @@ impl Value {
|
|||||||
fn as_ptr(&mut self) -> Result<*mut c_void, FFIError> {
|
fn as_ptr(&mut self) -> Result<*mut c_void, FFIError> {
|
||||||
match self {
|
match self {
|
||||||
Value::CString(ref mut cstr) => Ok(&mut *cstr as *mut _ as *mut c_void),
|
Value::CString(ref mut cstr) => Ok(&mut *cstr as *mut _ as *mut c_void),
|
||||||
Value::Int(n) => Ok(*n as *mut c_void),
|
Value::Int(n) => Ok(std::ptr::with_exposed_provenance_mut(*n as usize)),
|
||||||
_ => Err(FFIError::ValueCast),
|
_ => Err(FFIError::ValueCast),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
101
src/forms.rs
101
src/forms.rs
@@ -1,11 +1,12 @@
|
|||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
|
use crate::functor_macro::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::machine::disjuncts::VarData;
|
use crate::machine::disjuncts::VarData;
|
||||||
use crate::machine::heap::*;
|
|
||||||
use crate::machine::loader::PredicateQueue;
|
use crate::machine::loader::PredicateQueue;
|
||||||
use crate::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
|
use crate::offset_table::OffsetTable;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::dashu::{Integer, Rational};
|
use crate::parser::dashu::{Integer, Rational};
|
||||||
use crate::parser::parser::CompositeOpDesc;
|
use crate::parser::parser::CompositeOpDesc;
|
||||||
@@ -26,18 +27,6 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
pub type PredicateKey = (Atom, usize); // name, arity.
|
pub type PredicateKey = (Atom, usize); // name, arity.
|
||||||
|
|
||||||
/*
|
|
||||||
// vars of predicate, toplevel offset. Vec<Term> is always a vector
|
|
||||||
// of vars (we get their adjoining cells this way).
|
|
||||||
pub type JumpStub = Vec<Term>;
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Fact, VarData), // Term, line_num, col_num
|
|
||||||
Rule(Rule, VarData), // Rule, line_num, col_num
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum AppendOrPrepend {
|
pub enum AppendOrPrepend {
|
||||||
Append,
|
Append,
|
||||||
@@ -82,6 +71,28 @@ pub enum CallPolicy {
|
|||||||
Counted,
|
Counted,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub enum GenContext {
|
||||||
|
Head,
|
||||||
|
Mid(usize),
|
||||||
|
Last(usize), // Mid & Last: chunk_num
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenContext {
|
||||||
|
#[inline]
|
||||||
|
pub fn chunk_num(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
GenContext::Head => 0,
|
||||||
|
&GenContext::Mid(cn) | &GenContext::Last(cn) => cn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_last(self) -> bool {
|
||||||
|
matches!(self, GenContext::Last(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum ChunkType {
|
pub enum ChunkType {
|
||||||
Head,
|
Head,
|
||||||
@@ -121,7 +132,7 @@ impl ChunkType {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ChunkedTerms {
|
pub enum ChunkedTerms {
|
||||||
Branch(Vec<VecDeque<ChunkedTerms>>),
|
Branch(Vec<VecDeque<ChunkedTerms>>),
|
||||||
Chunk(VecDeque<QueryTerm>),
|
Chunk { terms: VecDeque<QueryTerm> },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -161,22 +172,30 @@ impl ChunkedTermVec {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn add_chunk(&mut self) {
|
pub fn add_chunk(&mut self) {
|
||||||
self.chunk_vec
|
let chunk = ChunkedTerms::Chunk {
|
||||||
.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![])));
|
terms: VecDeque::from(vec![]),
|
||||||
|
};
|
||||||
|
self.chunk_vec.push_back(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_chunk_term(&mut self, term: QueryTerm) {
|
pub fn push_chunk_term(&mut self, term: QueryTerm) {
|
||||||
match self.chunk_vec.back_mut() {
|
match self.chunk_vec.back_mut() {
|
||||||
Some(ChunkedTerms::Branch(_)) => {
|
Some(ChunkedTerms::Branch(_)) => {
|
||||||
self.chunk_vec
|
let chunk = ChunkedTerms::Chunk {
|
||||||
.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
|
terms: VecDeque::from(vec![term]),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.chunk_vec.push_back(chunk);
|
||||||
}
|
}
|
||||||
Some(ChunkedTerms::Chunk(chunk)) => {
|
Some(ChunkedTerms::Chunk { terms, .. }) => {
|
||||||
chunk.push_back(term);
|
terms.push_back(term);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.chunk_vec
|
let chunk = ChunkedTerms::Chunk {
|
||||||
.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
|
terms: VecDeque::from(vec![term]),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.chunk_vec.push_back(chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,9 +372,9 @@ pub enum ModuleSource {
|
|||||||
|
|
||||||
impl ModuleSource {
|
impl ModuleSource {
|
||||||
pub(crate) fn as_functor_stub(&self) -> MachineStub {
|
pub(crate) fn as_functor_stub(&self) -> MachineStub {
|
||||||
match self {
|
match *self {
|
||||||
ModuleSource::Library(name) => {
|
ModuleSource::Library(name) => {
|
||||||
functor!(atom!("library"), [atom(name)])
|
functor!(atom!("library"), [atom_as_cell(name)])
|
||||||
}
|
}
|
||||||
ModuleSource::File(name) => {
|
ModuleSource::File(name) => {
|
||||||
functor!(name)
|
functor!(name)
|
||||||
@@ -608,9 +627,9 @@ impl Default for Number {
|
|||||||
impl fmt::Display for Number {
|
impl fmt::Display for Number {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Number::Float(fl) => write!(f, "{}", fl),
|
Number::Float(fl) => write!(f, "{fl}"),
|
||||||
Number::Integer(n) => write!(f, "{}", n),
|
Number::Integer(n) => write!(f, "{n}"),
|
||||||
Number::Rational(r) => write!(f, "{}", r),
|
Number::Rational(r) => write!(f, "{r}"),
|
||||||
Number::Fixnum(n) => write!(f, "{}", n.get_num()),
|
Number::Fixnum(n) => write!(f, "{}", n.get_num()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -679,17 +698,18 @@ impl ArenaFrom<isize> for Number {
|
|||||||
impl ArenaFrom<u32> for Number {
|
impl ArenaFrom<u32> for Number {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arena_from(value: u32, _arena: &mut Arena) -> Number {
|
fn arena_from(value: u32, _arena: &mut Arena) -> Number {
|
||||||
Number::Fixnum(Fixnum::build_with(value as i64))
|
Number::Fixnum(Fixnum::build_with(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArenaFrom<i32> for Number {
|
impl ArenaFrom<i32> for Number {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arena_from(value: i32, _arena: &mut Arena) -> Number {
|
fn arena_from(value: i32, _arena: &mut Arena) -> Number {
|
||||||
Number::Fixnum(Fixnum::build_with(value as i64))
|
Number::Fixnum(Fixnum::build_with(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
impl ArenaFrom<Number> for Literal {
|
impl ArenaFrom<Number> for Literal {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn arena_from(value: Number, arena: &mut Arena) -> Literal {
|
fn arena_from(value: Number, arena: &mut Arena) -> Literal {
|
||||||
@@ -701,6 +721,21 @@ impl ArenaFrom<Number> for Literal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl ArenaFrom<u64> for HeapCellValue {
|
||||||
|
#[inline]
|
||||||
|
fn arena_from(value: u64, arena: &mut Arena) -> HeapCellValue {
|
||||||
|
HeapCellValue::from(fixnum!(Literal, value as i64, arena))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArenaFrom<usize> for HeapCellValue {
|
||||||
|
#[inline]
|
||||||
|
fn arena_from(value: usize, arena: &mut Arena) -> HeapCellValue {
|
||||||
|
HeapCellValue::arena_from(value as u64, arena)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ArenaFrom<Number> for HeapCellValue {
|
impl ArenaFrom<Number> for HeapCellValue {
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -708,7 +743,7 @@ impl ArenaFrom<Number> for HeapCellValue {
|
|||||||
match value {
|
match value {
|
||||||
Number::Fixnum(n) => fixnum_as_cell!(n),
|
Number::Fixnum(n) => fixnum_as_cell!(n),
|
||||||
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
|
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
|
||||||
Number::Float(OrderedFloat(n)) => HeapCellValue::from(float_alloc!(n, arena)),
|
Number::Float(n) => HeapCellValue::from(arena.f64_tbl.build_with(n)),
|
||||||
Number::Rational(n) => typed_arena_ptr_as_cell!(n),
|
Number::Rational(n) => typed_arena_ptr_as_cell!(n),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -771,10 +806,10 @@ impl Number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub(crate) enum OptArgIndexKey {
|
pub(crate) enum OptArgIndexKey {
|
||||||
Literal(usize, usize, Literal, Vec<Literal>), // index, IndexingCode location, opt arg, alternatives
|
Literal(usize, usize, Literal, Option<Literal>), // index, IndexingCode location, opt arg, alternatives
|
||||||
List(usize, usize), // index, IndexingCode location
|
List(usize, usize), // index, IndexingCode location
|
||||||
None,
|
None,
|
||||||
Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
|
Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
|
||||||
}
|
}
|
||||||
|
|||||||
798
src/functor_macro.rs
Normal file
798
src/functor_macro.rs
Normal file
@@ -0,0 +1,798 @@
|
|||||||
|
//! A macro to construct functor terms ready to be written to the WAM
|
||||||
|
//! heap.
|
||||||
|
|
||||||
|
use crate::atom_table::*;
|
||||||
|
use crate::instructions::IndexingCodePtr;
|
||||||
|
use crate::machine::heap::Heap;
|
||||||
|
use crate::parser::ast::Fixnum;
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub(crate) enum FunctorElement {
|
||||||
|
AbsoluteCell(HeapCellValue),
|
||||||
|
Cell(HeapCellValue),
|
||||||
|
InnerFunctor(u64, Vec<FunctorElement>),
|
||||||
|
String(u64, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper macros
|
||||||
|
macro_rules! count {
|
||||||
|
() => (0);
|
||||||
|
( $x:tt $($xs:tt)* ) => (1 + count!($($xs)*));
|
||||||
|
}
|
||||||
|
|
||||||
|
// core macros
|
||||||
|
|
||||||
|
/*
|
||||||
|
* functor! is more declarative now, with fewer effects and more
|
||||||
|
* work done at compile time using const functions. With these
|
||||||
|
* advantages come new quirks: expressions must generally be wrapped
|
||||||
|
* in round parentheses for rustc to parse them. See the tests module
|
||||||
|
* below for examples, especially those involving atom!
|
||||||
|
* subexpressions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
macro_rules! functor {
|
||||||
|
($name:expr) => ({
|
||||||
|
vec![FunctorElement::Cell(atom_as_cell!($name))]
|
||||||
|
});
|
||||||
|
($name:expr, [$($dt:ident($($value:tt),*)),+]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))],
|
||||||
|
1,
|
||||||
|
[])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! inner_functor {
|
||||||
|
($name:expr, $res_len:expr, [$($dt:ident($($value:tt),*)),+]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))],
|
||||||
|
1 + $res_len,
|
||||||
|
[])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! build_functor {
|
||||||
|
([], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
vec![$($res,)* $($subfunctor),*]
|
||||||
|
});
|
||||||
|
([indexing_code_ptr($e:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
let (inner_functor, cell_size) = indexing_code_ptr($e);
|
||||||
|
let referent = if cell_size == 1 {
|
||||||
|
heap_loc_as_cell!(1u64 + count!($($dt)*) + $res_len)
|
||||||
|
} else {
|
||||||
|
str_loc_as_cell!(1u64 + count!($($dt)*) + $res_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(referent)],
|
||||||
|
1 + cell_size + $res_len,
|
||||||
|
[$($subfunctor, )* FunctorElement::InnerFunctor(cell_size, inner_functor)])
|
||||||
|
});
|
||||||
|
([fixnum($e:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(fixnum_as_cell!(/*FIXME this is not safe*/ unsafe{Fixnum::build_with_unchecked($e as i64)}))],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([cell($e:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::AbsoluteCell($e)],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([literal($e:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::AbsoluteCell(HeapCellValue::from($e))],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([number($n:expr, $arena:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
let number_cell = HeapCellValue::arena_from($n, $arena);
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(number_cell)],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([list([]) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(empty_list_as_cell!())],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([list([$id:ident($($id_value:tt),*) $(, $in_dt:ident($($in_value:tt),*))*]) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([functor((atom!(".")), [$id($($id_value),*), list([$($in_dt($($in_value),*)),*])])
|
||||||
|
$(, $dt($($value),*))*],
|
||||||
|
[$($res),*],
|
||||||
|
$res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([string($s:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
#[allow(unused_parens)]
|
||||||
|
let string = $s;
|
||||||
|
let pstr_len = cell_index!(Heap::compute_pstr_size(&string)) as u64;
|
||||||
|
let result_len = 1 + count!($($dt)*) + $res_len;
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(pstr_loc_as_cell!(heap_index!(result_len as usize) as u64))],
|
||||||
|
1 + $res_len + pstr_len,
|
||||||
|
[$($subfunctor, )* FunctorElement::String(pstr_len, string)])
|
||||||
|
});
|
||||||
|
([atom_as_cell($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(atom_as_cell!($n))],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([functor($stub:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
let result_len = 1u64 + count!($($dt)*) + $res_len;
|
||||||
|
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&$stub)) as u64;
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))],
|
||||||
|
1 + $res_len + inner_functor_size,
|
||||||
|
[$($subfunctor, )*
|
||||||
|
FunctorElement::InnerFunctor(inner_functor_size, $stub)])
|
||||||
|
});
|
||||||
|
([$id:ident($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell($id!($n))],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([functor($name:expr, [$($in_dt:ident($($in_value:tt),*)),+]) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
let result_len = 1u64 + count!($($dt)*) + $res_len;
|
||||||
|
let inner_functor = inner_functor!($name, 0, [$($in_dt($($in_value),*)),*]);
|
||||||
|
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&inner_functor)) as u64;
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))],
|
||||||
|
1 + $res_len + inner_functor_size,
|
||||||
|
[$($subfunctor, )*
|
||||||
|
FunctorElement::InnerFunctor(inner_functor_size, inner_functor)])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn indexing_code_ptr(code_ptr: IndexingCodePtr) -> (Vec<FunctorElement>, u64) {
|
||||||
|
match code_ptr {
|
||||||
|
IndexingCodePtr::DynamicExternal(o) => {
|
||||||
|
(functor!(atom!("dynamic_external"), [fixnum(o)]), 2)
|
||||||
|
}
|
||||||
|
IndexingCodePtr::External(o) => (functor!(atom!("external"), [fixnum(o)]), 2),
|
||||||
|
IndexingCodePtr::Internal(o) => (functor!(atom!("internal"), [fixnum(o)]), 2),
|
||||||
|
IndexingCodePtr::Fail => (vec![FunctorElement::Cell(atom_as_cell!(atom!("fail")))], 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn variadic_functor(
|
||||||
|
name: Atom,
|
||||||
|
arity: usize,
|
||||||
|
iter: impl Iterator<Item = Vec<FunctorElement>>,
|
||||||
|
) -> Vec<FunctorElement> {
|
||||||
|
let mut arg_vec = vec![
|
||||||
|
FunctorElement::Cell(atom_as_cell!(name, arity)),
|
||||||
|
FunctorElement::Cell(list_loc_as_cell!(2)),
|
||||||
|
];
|
||||||
|
|
||||||
|
let key_value_pairs: Vec<_> = iter.collect();
|
||||||
|
let num_items = key_value_pairs.len();
|
||||||
|
let mut functor_offset = 0;
|
||||||
|
|
||||||
|
for (idx, kv_func) in key_value_pairs.iter().enumerate() {
|
||||||
|
let functor_size = cell_index!(Heap::compute_functor_byte_size(kv_func));
|
||||||
|
|
||||||
|
arg_vec.push(FunctorElement::Cell(str_loc_as_cell!(
|
||||||
|
2 + num_items * 2 + functor_offset
|
||||||
|
)));
|
||||||
|
arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(4 + 2 * idx)));
|
||||||
|
|
||||||
|
functor_offset += functor_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_vec.pop();
|
||||||
|
arg_vec.push(FunctorElement::Cell(empty_list_as_cell!()));
|
||||||
|
|
||||||
|
arg_vec.extend(key_value_pairs.into_iter().map(|kv_func| {
|
||||||
|
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&kv_func));
|
||||||
|
FunctorElement::InnerFunctor(inner_functor_size as u64, kv_func)
|
||||||
|
}));
|
||||||
|
|
||||||
|
arg_vec
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[allow(unused_parens)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use indexmap::indexmap;
|
||||||
|
use std::string::String;
|
||||||
|
use FunctorElement::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_terms() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[atom_as_cell((atom!("a"))), char_as_cell('c')]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 3);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 2)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(char_as_cell!('c')));
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("second"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor((atom!("b")), [fixnum(1), fixnum(2)]),
|
||||||
|
char_as_cell('c')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 5);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("second"), 3)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(str_loc_as_cell!(4)));
|
||||||
|
assert_eq!(functor[3], Cell(char_as_cell!('c')));
|
||||||
|
assert_eq!(
|
||||||
|
functor[4],
|
||||||
|
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
|
||||||
|
);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("third"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor((atom!("b")), [fixnum(1), fixnum(2)]),
|
||||||
|
functor((atom!("c")), [fixnum(1), fixnum(2)]),
|
||||||
|
char_as_cell('c')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 7);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("third"), 4)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(str_loc_as_cell!(5)));
|
||||||
|
assert_eq!(functor[3], Cell(str_loc_as_cell!(8)));
|
||||||
|
assert_eq!(functor[4], Cell(char_as_cell!('c')));
|
||||||
|
assert_eq!(
|
||||||
|
functor[5],
|
||||||
|
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
functor[6],
|
||||||
|
InnerFunctor(3, functor!(atom!("c"), [fixnum(1), fixnum(2)]))
|
||||||
|
);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("fourth"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor((atom!("b")), [fixnum(1), fixnum(2)]),
|
||||||
|
functor((atom!("c")), [fixnum(1)]),
|
||||||
|
functor((atom!("d")), [fixnum(453), fixnum(2)]),
|
||||||
|
char_as_cell('c')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 9);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("fourth"), 5)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(str_loc_as_cell!(6)));
|
||||||
|
assert_eq!(functor[3], Cell(str_loc_as_cell!(9)));
|
||||||
|
assert_eq!(functor[4], Cell(str_loc_as_cell!(11)));
|
||||||
|
assert_eq!(functor[5], Cell(char_as_cell!('c')));
|
||||||
|
assert_eq!(
|
||||||
|
functor[6],
|
||||||
|
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
functor[7],
|
||||||
|
InnerFunctor(2, functor!(atom!("c"), [fixnum(1)]))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
functor[8],
|
||||||
|
InnerFunctor(3, functor!(atom!("d"), [fixnum(453), fixnum(2)]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_terms_in_heap() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[atom_as_cell((atom!("a"))), char_as_cell('b')]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 3);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, str_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2));
|
||||||
|
assert_eq!(heap[1], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[2], char_as_cell!('b'));
|
||||||
|
|
||||||
|
heap.truncate(2);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("second"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor((atom!("b")), [fixnum(1), fixnum(2)]),
|
||||||
|
functor((atom!("c")), [fixnum(1), fixnum(2)]),
|
||||||
|
char_as_cell('b')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 7);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, str_loc_as_cell!(2));
|
||||||
|
|
||||||
|
assert_eq!(heap[2], atom_as_cell!(atom!("second"), 4));
|
||||||
|
assert_eq!(heap[3], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[4], str_loc_as_cell!(7));
|
||||||
|
assert_eq!(heap[5], str_loc_as_cell!(10));
|
||||||
|
assert_eq!(heap[6], char_as_cell!('b'));
|
||||||
|
assert_eq!(heap[7], atom_as_cell!(atom!("b"), 2));
|
||||||
|
assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
assert_eq!(heap[10], atom_as_cell!(atom!("c"), 2));
|
||||||
|
assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_functors() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor(
|
||||||
|
(atom!("d")),
|
||||||
|
[
|
||||||
|
fixnum(1),
|
||||||
|
functor(
|
||||||
|
(atom!("b")),
|
||||||
|
[atom_as_cell((atom!("c"))), char_as_cell('c')]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
functor((atom!("e")), [fixnum(453), fixnum(2)]),
|
||||||
|
char_as_cell('b')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 7);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 4)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(str_loc_as_cell!(5)));
|
||||||
|
assert_eq!(functor[3], Cell(str_loc_as_cell!(11)));
|
||||||
|
assert_eq!(functor[4], Cell(char_as_cell!('b')));
|
||||||
|
assert_eq!(
|
||||||
|
functor[5],
|
||||||
|
InnerFunctor(
|
||||||
|
6,
|
||||||
|
vec![
|
||||||
|
Cell(atom_as_cell!(atom!("d"), 2)),
|
||||||
|
Cell(fixnum_as_cell!(Fixnum::build_with(1))),
|
||||||
|
Cell(str_loc_as_cell!(3)),
|
||||||
|
InnerFunctor(
|
||||||
|
3,
|
||||||
|
functor!(atom!("b"), [atom_as_cell((atom!("c"))), char_as_cell('c')])
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
functor[6],
|
||||||
|
InnerFunctor(3, functor!(atom!("e"), [fixnum(453), fixnum(2)]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_functors_in_heap() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor(
|
||||||
|
(atom!("second")),
|
||||||
|
[
|
||||||
|
fixnum(1),
|
||||||
|
functor(
|
||||||
|
(atom!("third")),
|
||||||
|
[atom_as_cell((atom!("b"))), char_as_cell('c')]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
functor((atom!("fourth")), [fixnum(453), fixnum(2)]),
|
||||||
|
char_as_cell('b')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, str_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 14);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 4));
|
||||||
|
assert_eq!(heap[1], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(5));
|
||||||
|
assert_eq!(heap[3], str_loc_as_cell!(11));
|
||||||
|
assert_eq!(heap[4], char_as_cell!('b'));
|
||||||
|
assert_eq!(heap[5], atom_as_cell!(atom!("second"), 2));
|
||||||
|
assert_eq!(heap[6], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[7], str_loc_as_cell!(8));
|
||||||
|
assert_eq!(heap[8], atom_as_cell!(atom!("third"), 2));
|
||||||
|
assert_eq!(heap[9], atom_as_cell!(atom!("b")));
|
||||||
|
assert_eq!(heap[10], char_as_cell!('c'));
|
||||||
|
assert_eq!(heap[11], atom_as_cell!(atom!("fourth"), 2));
|
||||||
|
assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(453)));
|
||||||
|
assert_eq!(heap[13], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn functors_with_strings_in_heap() {
|
||||||
|
let functor = functor!(atom!("first"), [string((String::from("a string")))]);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 3);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, str_loc_as_cell!(0));
|
||||||
|
assert_eq!(heap.cell_len(), 5);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2)));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(2), "a string".len()),
|
||||||
|
"a string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[4], empty_list_as_cell!());
|
||||||
|
|
||||||
|
heap.truncate(0);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("second"),
|
||||||
|
[string((String::from("a stuttered\0 string")))]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 10);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("second"), 1));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2)));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(2), "a stuttered".len()),
|
||||||
|
"a stuttered"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[4], list_loc_as_cell!(5));
|
||||||
|
assert_eq!(heap[5], char_as_cell!('\u{0}'));
|
||||||
|
assert_eq!(heap[6], pstr_loc_as_cell!(heap_index!(7)));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(7), " string".len()),
|
||||||
|
" string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[9], empty_list_as_cell!());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn functors_with_lists_in_heap() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[list([fixnum(1), atom_as_cell((atom!("a"))), fixnum(2)])]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 3);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 11);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1));
|
||||||
|
assert_eq!(heap[1], str_loc_as_cell!(2));
|
||||||
|
assert_eq!(heap[2], atom_as_cell!(atom!("."), 2));
|
||||||
|
assert_eq!(heap[3], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[4], str_loc_as_cell!(5));
|
||||||
|
assert_eq!(heap[5], atom_as_cell!(atom!("."), 2));
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[7], str_loc_as_cell!(8));
|
||||||
|
assert_eq!(heap[8], atom_as_cell!(atom!("."), 2));
|
||||||
|
assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
assert_eq!(heap[10], empty_list_as_cell!());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inlined_atoms() {
|
||||||
|
let atom_table = AtomTable::new();
|
||||||
|
let inlined = AtomTable::build_with(&atom_table, "inline");
|
||||||
|
|
||||||
|
assert!(inlined.is_inlined());
|
||||||
|
assert_eq!(&*inlined.as_str(), "inline");
|
||||||
|
|
||||||
|
let non_inlined = AtomTable::build_with(&atom_table, "longer non-inlined atom");
|
||||||
|
|
||||||
|
assert!(!non_inlined.is_inlined());
|
||||||
|
assert_eq!(&*non_inlined.as_str(), "longer non-inlined atom");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn functors_with_indexing_code_ptr() {
|
||||||
|
let code_ptr = IndexingCodePtr::Internal(0);
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[
|
||||||
|
string((String::from("a string"))),
|
||||||
|
indexing_code_ptr(code_ptr)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 8);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(6));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(3), "a string".len()),
|
||||||
|
"a string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[5], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("internal"), 1));
|
||||||
|
assert_eq!(heap[7], fixnum_as_cell!(Fixnum::build_with(0)));
|
||||||
|
|
||||||
|
heap.truncate(0);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("second"),
|
||||||
|
[
|
||||||
|
string((String::from("a string"))),
|
||||||
|
functor(
|
||||||
|
(atom!("third")),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
string((String::from("another string"))),
|
||||||
|
indexing_code_ptr(code_ptr)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 15);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("second"), 2));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(6));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(3), "a string".len()),
|
||||||
|
"a string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[5], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("third"), 3));
|
||||||
|
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(10)));
|
||||||
|
assert_eq!(heap[9], str_loc_as_cell!(13));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(10), "another string".len()),
|
||||||
|
"another string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[12], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[13], atom_as_cell!(atom!("internal"), 1));
|
||||||
|
assert_eq!(heap[14], fixnum_as_cell!(Fixnum::build_with(0)));
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("fourth"),
|
||||||
|
[
|
||||||
|
string((String::from("a string"))),
|
||||||
|
functor(
|
||||||
|
(atom!("a")),
|
||||||
|
[
|
||||||
|
functor(
|
||||||
|
(atom!("fifth")),
|
||||||
|
[
|
||||||
|
fixnum(5),
|
||||||
|
string((String::from("another string"))),
|
||||||
|
indexing_code_ptr(code_ptr)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
string((String::from("and another")))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
heap.truncate(0);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 21);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("fourth"), 2));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(6));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(3), "a string".len()),
|
||||||
|
"a string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[5], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("a"), 2));
|
||||||
|
assert_eq!(heap[7], str_loc_as_cell!(9));
|
||||||
|
assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(18))); // <-- wrong!
|
||||||
|
assert_eq!(heap[9], atom_as_cell!(atom!("fifth"), 3));
|
||||||
|
assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(5)));
|
||||||
|
assert_eq!(heap[11], pstr_loc_as_cell!(heap_index!(13)));
|
||||||
|
assert_eq!(heap[12], str_loc_as_cell!(16));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(13), "another string".len()),
|
||||||
|
"another string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[15], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[16], atom_as_cell!(atom!("internal"), 1));
|
||||||
|
assert_eq!(heap[17], fixnum_as_cell!(Fixnum::build_with(0)));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(18), "and another".len()),
|
||||||
|
"and another"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[20], empty_list_as_cell!());
|
||||||
|
|
||||||
|
let constants = indexmap![
|
||||||
|
atom_as_cell!(atom!("a")) => IndexingCodePtr::External(2),
|
||||||
|
atom_as_cell!(atom!("d")) => IndexingCodePtr::External(7),
|
||||||
|
];
|
||||||
|
|
||||||
|
let functor = variadic_functor(
|
||||||
|
atom!("switch_on_constants"),
|
||||||
|
1,
|
||||||
|
constants
|
||||||
|
.iter()
|
||||||
|
.map(|(c, ptr)| functor!(atom!(":"), [cell((*c)), indexing_code_ptr((*ptr))])),
|
||||||
|
);
|
||||||
|
|
||||||
|
heap.truncate(0);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("switch_on_constants"), 1));
|
||||||
|
assert_eq!(heap[1], list_loc_as_cell!(2));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(6));
|
||||||
|
assert_eq!(heap[3], list_loc_as_cell!(4));
|
||||||
|
assert_eq!(heap[4], str_loc_as_cell!(11));
|
||||||
|
assert_eq!(heap[5], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!(":"), 2));
|
||||||
|
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[8], str_loc_as_cell!(9));
|
||||||
|
assert_eq!(heap[9], atom_as_cell!(atom!("external"), 1));
|
||||||
|
assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
assert_eq!(heap[11], atom_as_cell!(atom!(":"), 2));
|
||||||
|
assert_eq!(heap[12], atom_as_cell!(atom!("d")));
|
||||||
|
assert_eq!(heap[13], str_loc_as_cell!(14));
|
||||||
|
assert_eq!(heap[14], atom_as_cell!(atom!("external"), 1));
|
||||||
|
assert_eq!(heap[15], fixnum_as_cell!(Fixnum::build_with(7)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn undefined_procedure_functor() {
|
||||||
|
// existence_error
|
||||||
|
let culprit = functor!(atom!("/"), [atom_as_cell((atom!("a"))), fixnum(1)]);
|
||||||
|
|
||||||
|
let stub = functor!(
|
||||||
|
atom!("existence_error"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("procedure"))),
|
||||||
|
functor((culprit.clone()))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("{stub:?}");
|
||||||
|
|
||||||
|
// now the error form
|
||||||
|
let lineless_error_form = functor!(atom!("error"), [functor(stub), functor(culprit)]);
|
||||||
|
|
||||||
|
println!("{lineless_error_form:?}");
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(lineless_error_form);
|
||||||
|
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("error"), 2));
|
||||||
|
assert_eq!(heap[1], str_loc_as_cell!(3));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(9));
|
||||||
|
assert_eq!(heap[3], atom_as_cell!(atom!("existence_error"), 2));
|
||||||
|
assert_eq!(heap[4], atom_as_cell!(atom!("procedure")));
|
||||||
|
assert_eq!(heap[5], str_loc_as_cell!(6)); // is str_loc_as_cell!(3)
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("/"), 2));
|
||||||
|
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[9], atom_as_cell!(atom!("/"), 2));
|
||||||
|
assert_eq!(heap[10], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn argless_functor() {
|
||||||
|
let name = functor!(atom!("[]"));
|
||||||
|
|
||||||
|
assert_eq!(name.len(), 1);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(name);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, heap_loc_as_cell!(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn predefined_subfunctors() {
|
||||||
|
let stub = functor!(atom!("sub"), [atom_as_cell((atom!("[]")))]);
|
||||||
|
let name = functor!(atom!("super"), [functor(stub)]);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(name);
|
||||||
|
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 4);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("super"), 1));
|
||||||
|
assert_eq!(heap[1], str_loc_as_cell!(2));
|
||||||
|
assert_eq!(heap[2], atom_as_cell!(atom!("sub"), 1));
|
||||||
|
assert_eq!(heap[3], empty_list_as_cell!());
|
||||||
|
}
|
||||||
|
}
|
||||||
1234
src/heap_iter.rs
1234
src/heap_iter.rs
File diff suppressed because it is too large
Load Diff
@@ -8,11 +8,10 @@ use crate::parser::dashu::{ibig, Integer, Rational};
|
|||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::heap_iter::*;
|
use crate::heap_iter::*;
|
||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
use crate::machine::machine_indices::*;
|
|
||||||
use crate::machine::machine_state::pstr_loc_and_offset;
|
|
||||||
use crate::machine::partial_string::*;
|
use crate::machine::partial_string::*;
|
||||||
use crate::machine::stack::*;
|
use crate::machine::stack::*;
|
||||||
use crate::machine::streams::*;
|
use crate::machine::streams::*;
|
||||||
|
use crate::offset_table::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use dashu::base::Signed;
|
use dashu::base::Signed;
|
||||||
@@ -25,7 +24,6 @@ use std::convert::TryFrom;
|
|||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::net::{IpAddr, TcpListener};
|
use std::net::{IpAddr, TcpListener};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
/* contains the location, name, precision and Specifier of the parent op. */
|
/* contains the location, name, precision and Specifier of the parent op. */
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
@@ -206,11 +204,12 @@ impl NumberFocus {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct CommaSeparatedCharList {
|
struct CommaSeparatedCharList {
|
||||||
pstr: PartialString,
|
// pstr: PartialString,
|
||||||
offset: usize,
|
// offset: usize,
|
||||||
|
pstr_loc: usize,
|
||||||
max_depth: usize,
|
max_depth: usize,
|
||||||
end_cell: HeapCellValue,
|
// end_cell: HeapCellValue,
|
||||||
end_h: Option<usize>,
|
// end_h: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -389,17 +388,20 @@ fn is_numbered_var(name: Atom, arity: usize) -> bool {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn negated_op_needs_bracketing(
|
fn negated_op_needs_bracketing(
|
||||||
iter: &StackfulPreOrderHeapIter<ListElider>,
|
iter: &StackfulPreOrderHeapIter<ListElider>,
|
||||||
|
f64_tbl: &F64Table,
|
||||||
op_dir: &OpDir,
|
op_dir: &OpDir,
|
||||||
op: &Option<DirectedOp>,
|
op: &Option<DirectedOp>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(ref op) = op {
|
if let Some(ref op) = op {
|
||||||
op.is_negative_sign()
|
op.is_negative_sign()
|
||||||
&& iter.leftmost_leaf_has_property(op_dir, |addr| match Number::try_from(addr) {
|
&& iter.leftmost_leaf_has_property(op_dir, |addr| {
|
||||||
Ok(Number::Fixnum(n)) => n.get_num() > 0,
|
match Number::try_from((addr, f64_tbl)) {
|
||||||
Ok(Number::Float(OrderedFloat(f))) => f > 0f64,
|
Ok(Number::Fixnum(n)) => n.get_num() > 0,
|
||||||
Ok(Number::Integer(n)) => n.is_positive(),
|
Ok(Number::Float(OrderedFloat(f))) => f > 0f64,
|
||||||
Ok(Number::Rational(n)) => n.is_positive(),
|
Ok(Number::Integer(n)) => n.is_positive(),
|
||||||
_ => false,
|
Ok(Number::Rational(n)) => n.is_positive(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -473,7 +475,7 @@ pub fn fmt_float(mut fl: f64) -> String {
|
|||||||
pub struct HCPrinter<'a, Outputter> {
|
pub struct HCPrinter<'a, Outputter> {
|
||||||
outputter: Outputter,
|
outputter: Outputter,
|
||||||
iter: StackfulPreOrderHeapIter<'a, ListElider>,
|
iter: StackfulPreOrderHeapIter<'a, ListElider>,
|
||||||
atom_tbl: Arc<AtomTable>,
|
arena: &'a Arena,
|
||||||
op_dir: &'a OpDir,
|
op_dir: &'a OpDir,
|
||||||
state_stack: Vec<TokenOrRedirect>,
|
state_stack: Vec<TokenOrRedirect>,
|
||||||
toplevel_spec: Option<DirectedOp>,
|
toplevel_spec: Option<DirectedOp>,
|
||||||
@@ -488,9 +490,24 @@ pub struct HCPrinter<'a, Outputter> {
|
|||||||
pub double_quotes: bool,
|
pub double_quotes: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ambiguity_check(
|
||||||
|
outputter: &impl HCValueOutputter,
|
||||||
|
quoted: bool,
|
||||||
|
last_item_idx: usize,
|
||||||
|
atom: &str,
|
||||||
|
) -> bool {
|
||||||
|
let tail = &outputter.as_str()[last_item_idx..];
|
||||||
|
|
||||||
|
if atom == "," || !quoted || non_quoted_token(atom.chars()) {
|
||||||
|
requires_space(tail, atom)
|
||||||
|
} else {
|
||||||
|
requires_space(tail, "'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! push_space_if_amb {
|
macro_rules! push_space_if_amb {
|
||||||
($self:expr, $atom:expr, $action:block) => {
|
($self:expr, $atom:expr, $action:block) => {
|
||||||
if $self.ambiguity_check($atom) {
|
if ambiguity_check(&$self.outputter, $self.quoted, $self.last_item_idx, $atom) {
|
||||||
$self.outputter.push_char(' ');
|
$self.outputter.push_char(' ');
|
||||||
$action;
|
$action;
|
||||||
} else {
|
} else {
|
||||||
@@ -516,28 +533,47 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match Number::try_from(addr) {
|
read_heap_cell!(addr,
|
||||||
Ok(Number::Fixnum(n)) if n.get_num() >= 0 => {
|
(HeapCellValueTag::Cons, c) => {
|
||||||
Some(numbervar(offset + Integer::from(n.get_num())))
|
match_untyped_arena_ptr!(c,
|
||||||
|
(ArenaHeaderTag::Integer, n) => {
|
||||||
|
if !n.is_negative() {
|
||||||
|
Some(numbervar(Integer::from(offset + &*n)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Ok(Number::Integer(n)) if !n.is_negative() => Some(numbervar(Integer::from(offset + &*n))),
|
(HeapCellValueTag::Fixnum, n) => {
|
||||||
_ => None,
|
if n.get_num() >= 0 {
|
||||||
}
|
Some(numbervar(offset + Integer::from(n.get_num())))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
heap: &'a mut Heap,
|
heap: &'a mut Heap,
|
||||||
atom_tbl: Arc<AtomTable>,
|
|
||||||
stack: &'a mut Stack,
|
stack: &'a mut Stack,
|
||||||
|
arena: &'a Arena,
|
||||||
op_dir: &'a OpDir,
|
op_dir: &'a OpDir,
|
||||||
output: Outputter,
|
output: Outputter,
|
||||||
cell: HeapCellValue,
|
term_loc: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
HCPrinter {
|
HCPrinter {
|
||||||
outputter: output,
|
outputter: output,
|
||||||
iter: stackful_preorder_iter(heap, stack, cell),
|
iter: stackful_preorder_iter(heap, stack, term_loc),
|
||||||
atom_tbl,
|
arena,
|
||||||
op_dir,
|
op_dir,
|
||||||
state_stack: vec![],
|
state_stack: vec![],
|
||||||
toplevel_spec: None,
|
toplevel_spec: None,
|
||||||
@@ -553,17 +589,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn ambiguity_check(&self, atom: &str) -> bool {
|
|
||||||
let tail = &self.outputter.as_str()[self.last_item_idx..];
|
|
||||||
|
|
||||||
if atom == "," || !self.quoted || non_quoted_token(atom.chars()) {
|
|
||||||
requires_space(tail, atom)
|
|
||||||
} else {
|
|
||||||
requires_space(tail, "'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_parent_of_first_op(&mut self, parent_op: Option<DirectedOp>) {
|
fn set_parent_of_first_op(&mut self, parent_op: Option<DirectedOp>) {
|
||||||
if let Some(op) = parent_op {
|
if let Some(op) = parent_op {
|
||||||
if op.is_left() && op.is_prefix() {
|
if op.is_left() && op.is_prefix() {
|
||||||
@@ -806,13 +831,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
|
|
||||||
read_heap_cell!(cell,
|
read_heap_cell!(cell,
|
||||||
(HeapCellValueTag::Lis | HeapCellValueTag::Str, h) => {
|
(HeapCellValueTag::Lis | HeapCellValueTag::Str, h) => {
|
||||||
Some(format!("{}", h))
|
Some(format!("{h}"))
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
||||||
Some(format!("_{}", h))
|
Some(format!("_{h}"))
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::StackVar, h) => {
|
(HeapCellValueTag::StackVar, h) => {
|
||||||
Some(format!("_s_{}", h))
|
Some(format!("_s_{h}"))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
None
|
None
|
||||||
@@ -878,7 +903,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
} else {
|
} else {
|
||||||
debug_assert!(cell.is_ref());
|
debug_assert!(cell.is_ref());
|
||||||
|
|
||||||
let h = cell.get_value() as usize;
|
let h = if cell.get_tag() == HeapCellValueTag::PStrLoc {
|
||||||
|
self.iter.focus().value()
|
||||||
|
} else {
|
||||||
|
cell.get_value()
|
||||||
|
} as usize;
|
||||||
|
|
||||||
self.iter.push_stack(IterStackLoc::iterable_loc(
|
self.iter.push_stack(IterStackLoc::iterable_loc(
|
||||||
h,
|
h,
|
||||||
HeapOrStackTag::Heap,
|
HeapOrStackTag::Heap,
|
||||||
@@ -908,7 +938,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
orig_cell = cell;
|
orig_cell = cell;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -972,13 +1002,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn print_ip_addr(&mut self, ip: IpAddr) {
|
fn print_ip_addr(&mut self, ip: IpAddr) {
|
||||||
push_char!(self, '\'');
|
push_char!(self, '\'');
|
||||||
append_str!(self, &format!("{}", ip));
|
append_str!(self, &format!("{ip}"));
|
||||||
push_char!(self, '\'');
|
push_char!(self, '\'');
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn print_raw_ptr(&mut self, ptr: *const ArenaHeader) {
|
fn print_raw_ptr(&mut self, ptr: *const ArenaHeader) {
|
||||||
append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize));
|
append_str!(self, &format!("0x{:x}", ptr.addr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_number(&mut self, max_depth: usize, n: NumberFocus, op: &Option<DirectedOp>) {
|
fn print_number(&mut self, max_depth: usize, n: NumberFocus, op: &Option<DirectedOp>) {
|
||||||
@@ -1009,7 +1039,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
self.print_rational(max_depth, r, *op);
|
self.print_rational(max_depth, r, *op);
|
||||||
}
|
}
|
||||||
n => {
|
n => {
|
||||||
let output_str = format!("{}", n);
|
let output_str = format!("{n}");
|
||||||
|
|
||||||
push_space_if_amb!(self, &output_str, {
|
push_space_if_amb!(self, &output_str, {
|
||||||
append_str!(self, &output_str);
|
append_str!(self, &output_str);
|
||||||
@@ -1056,7 +1086,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) {
|
match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) {
|
||||||
Some(op_desc) => {
|
Some(op_desc) => {
|
||||||
if r.is_int() {
|
if r.is_int() {
|
||||||
let output_str = format!("{}", r);
|
let output_str = format!("{r}");
|
||||||
|
|
||||||
push_space_if_amb!(self, &output_str, {
|
push_space_if_amb!(self, &output_str, {
|
||||||
append_str!(self, &output_str);
|
append_str!(self, &output_str);
|
||||||
@@ -1123,9 +1153,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
|
|
||||||
// returns true if max_depth limit is reached and ellipsis is printed.
|
// returns true if max_depth limit is reached and ellipsis is printed.
|
||||||
fn print_string_as_functor(&mut self, focus: usize, max_depth: &mut usize) -> bool {
|
fn print_string_as_functor(&mut self, focus: usize, max_depth: &mut usize) -> bool {
|
||||||
let iter = HeapPStrIter::new(self.iter.heap, focus);
|
let mut iter = HeapPStrIter::new(self.iter.heap, focus);
|
||||||
|
let mut char_count = 0;
|
||||||
|
|
||||||
for (char_count, c) in iter.chars().enumerate() {
|
while let Some(iteratee) = iter.next() {
|
||||||
if self.check_max_depth(max_depth) {
|
if self.check_max_depth(max_depth) {
|
||||||
if char_count > 0 {
|
if char_count > 0 {
|
||||||
self.state_stack.push(TokenOrRedirect::Close);
|
self.state_stack.push(TokenOrRedirect::Close);
|
||||||
@@ -1135,13 +1166,34 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
append_str!(self, "'.'");
|
macro_rules! emit_char {
|
||||||
push_char!(self, '(');
|
($c:expr) => {{
|
||||||
|
append_str!(self, "'.'");
|
||||||
|
push_char!(self, '(');
|
||||||
|
|
||||||
print_char!(self, self.quoted, c);
|
print_char!(self, self.quoted, $c);
|
||||||
push_char!(self, ',');
|
push_char!(self, ',');
|
||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::Close);
|
self.state_stack.push(TokenOrRedirect::Close);
|
||||||
|
char_count += 1;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
match iteratee {
|
||||||
|
PStrIteratee::Char { value, .. } => {
|
||||||
|
emit_char!(value);
|
||||||
|
}
|
||||||
|
PStrIteratee::PStrSlice {
|
||||||
|
slice_loc,
|
||||||
|
slice_len,
|
||||||
|
} => {
|
||||||
|
let s = iter.heap.slice_to_str(slice_loc, slice_len);
|
||||||
|
|
||||||
|
for c in s.chars() {
|
||||||
|
emit_char!(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
@@ -1152,7 +1204,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
fn print_proper_string(&mut self, focus: usize, max_depth: usize) {
|
fn print_proper_string(&mut self, focus: usize, max_depth: usize) {
|
||||||
push_char!(self, '"');
|
push_char!(self, '"');
|
||||||
|
|
||||||
let iter = HeapPStrIter::new(self.iter.heap, focus);
|
let mut iter = HeapPStrIter::new(self.iter.heap, focus);
|
||||||
|
|
||||||
let char_to_string = |c: char| {
|
let char_to_string = |c: char| {
|
||||||
// refrain from quoting characters other than '"' and '\'
|
// refrain from quoting characters other than '"' and '\'
|
||||||
// unless self.quoted is true.
|
// unless self.quoted is true.
|
||||||
@@ -1164,19 +1217,45 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if max_depth == 0 {
|
if max_depth == 0 {
|
||||||
for c in iter.chars() {
|
while let Some(iteratee) = iter.next() {
|
||||||
for c in char_to_string(c).chars() {
|
let iter: Box<dyn Iterator<Item = char>> = match iteratee {
|
||||||
push_char!(self, c);
|
PStrIteratee::Char { value: c, .. } => Box::new(std::iter::once(c)),
|
||||||
|
PStrIteratee::PStrSlice {
|
||||||
|
slice_loc,
|
||||||
|
slice_len,
|
||||||
|
} => {
|
||||||
|
let s = iter.heap.slice_to_str(slice_loc, slice_len);
|
||||||
|
Box::new(s.chars())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for c in iter {
|
||||||
|
for c in char_to_string(c).chars() {
|
||||||
|
push_char!(self, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut char_count = 0;
|
let mut char_count = 0;
|
||||||
|
|
||||||
for c in iter.chars().take(max_depth) {
|
while let Some(iteratee) = iter.next() {
|
||||||
char_count += 1;
|
let iter: Box<dyn Iterator<Item = char>> = match iteratee {
|
||||||
|
PStrIteratee::Char { value: c, .. } => Box::new(std::iter::once(c)),
|
||||||
|
PStrIteratee::PStrSlice {
|
||||||
|
slice_loc,
|
||||||
|
slice_len,
|
||||||
|
} => {
|
||||||
|
let s = iter.heap.slice_to_str(slice_loc, slice_len);
|
||||||
|
Box::new(s.chars())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for c in char_to_string(c).chars() {
|
for c in iter.take(max_depth - char_count) {
|
||||||
push_char!(self, c);
|
char_count += 1;
|
||||||
|
|
||||||
|
for c in char_to_string(c).chars() {
|
||||||
|
push_char!(self, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1194,10 +1273,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
self.iter.pop_stack();
|
self.iter.pop_stack();
|
||||||
self.iter.pop_stack();
|
self.iter.pop_stack();
|
||||||
}
|
}
|
||||||
HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset => {
|
HeapCellValueTag::PStrLoc => {
|
||||||
self.iter.pop_stack();
|
self.iter.pop_stack();
|
||||||
}
|
}
|
||||||
HeapCellValueTag::CStr => {}
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
@@ -1208,19 +1286,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
let focus = self.iter.focus();
|
let focus = self.iter.focus();
|
||||||
let mut heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus.value() as usize);
|
let mut heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus.value() as usize);
|
||||||
|
|
||||||
let next_h;
|
let is_cyclic = if heap_pstr_iter.next().is_some() {
|
||||||
let next_hare;
|
|
||||||
|
|
||||||
if heap_pstr_iter.next().is_some() {
|
|
||||||
next_h = heap_pstr_iter.focus;
|
|
||||||
next_hare = heap_pstr_iter.focus();
|
|
||||||
for _ in heap_pstr_iter.by_ref() {}
|
for _ in heap_pstr_iter.by_ref() {}
|
||||||
|
heap_pstr_iter.is_cyclic()
|
||||||
} else {
|
} else {
|
||||||
return self.push_list(max_depth);
|
return self.push_list(max_depth);
|
||||||
}
|
};
|
||||||
|
|
||||||
let end_h = heap_pstr_iter.focus();
|
let end_h = heap_pstr_iter.focus();
|
||||||
let end_cell = heap_pstr_iter.focus;
|
let end_cell = heap_pstr_iter.heap[end_h]; // heap_pstr_iter.focus;
|
||||||
|
|
||||||
if self.check_max_depth(&mut max_depth) {
|
if self.check_max_depth(&mut max_depth) {
|
||||||
self.remove_list_children(focus.value() as usize);
|
self.remove_list_children(focus.value() as usize);
|
||||||
@@ -1230,7 +1304,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
|
|
||||||
let at_cdr = self.outputter.ends_with("|");
|
let at_cdr = self.outputter.ends_with("|");
|
||||||
|
|
||||||
if self.double_quotes && !self.ignore_ops && end_cell.is_string_terminator(self.iter.heap) {
|
if self.double_quotes
|
||||||
|
&& !self.ignore_ops
|
||||||
|
&& !is_cyclic
|
||||||
|
&& end_cell.is_string_terminator(self.iter.heap)
|
||||||
|
{
|
||||||
self.remove_list_children(focus.value() as usize);
|
self.remove_list_children(focus.value() as usize);
|
||||||
return self.print_proper_string(focus.value() as usize, max_depth);
|
return self.print_proper_string(focus.value() as usize, max_depth);
|
||||||
}
|
}
|
||||||
@@ -1261,37 +1339,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
(HeapCellValueTag::Lis) => {
|
(HeapCellValueTag::Lis) => {
|
||||||
self.push_list(max_depth)
|
self.push_list(max_depth)
|
||||||
}
|
}
|
||||||
_ => {
|
(HeapCellValueTag::PStrLoc, h) => {
|
||||||
let switch = Rc::new(Cell::new((!at_cdr, 0)));
|
let switch = Rc::new(Cell::new((!at_cdr, 0)));
|
||||||
let switch = self.close_list(switch);
|
let switch = self.close_list(switch);
|
||||||
|
|
||||||
let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus.value() as usize);
|
|
||||||
|
|
||||||
let offset = offset.get_num() as usize;
|
|
||||||
let tag = value.get_tag();
|
|
||||||
|
|
||||||
let end_h = if tag == HeapCellValueTag::PStrOffset {
|
|
||||||
// remove the fixnum offset from the iterator stack so we don't
|
|
||||||
// print an extraneous number. pstr offset value cells are never
|
|
||||||
// used by the iterator to mark cyclic terms so the removal is safe.
|
|
||||||
self.iter.pop_stack();
|
|
||||||
Some(next_hare)
|
|
||||||
// Some(end_h)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if !self.max_depth_exhausted(max_depth) {
|
if !self.max_depth_exhausted(max_depth) {
|
||||||
let pstr = cell_as_string!(self.iter.heap[h]);
|
self.state_stack.push(
|
||||||
self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList(CommaSeparatedCharList {
|
TokenOrRedirect::CommaSeparatedCharList(
|
||||||
pstr, offset, max_depth, end_cell: next_h, end_h,
|
CommaSeparatedCharList {
|
||||||
}));
|
pstr_loc: h, max_depth,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.open_list(switch);
|
self.open_list(switch);
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1384,7 +1452,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
|| if let Some(ref op) = op {
|
|| if let Some(ref op) = op {
|
||||||
if self.numbervars && arity == 1 && name == atom!("$VAR") {
|
if self.numbervars && arity == 1 && name == atom!("$VAR") {
|
||||||
!self.iter.immediate_leaf_has_property(|addr| {
|
!self.iter.immediate_leaf_has_property(|addr| {
|
||||||
match Number::try_from(addr) {
|
match Number::try_from((addr, &self.arena.f64_tbl)) {
|
||||||
Ok(Number::Integer(n)) => (*n).sign() == Sign::Positive,
|
Ok(Number::Integer(n)) => (*n).sign() == Sign::Positive,
|
||||||
Ok(Number::Fixnum(n)) => n.get_num() >= 0,
|
Ok(Number::Fixnum(n)) => n.get_num() >= 0,
|
||||||
Ok(Number::Float(f)) => f >= OrderedFloat(0f64),
|
Ok(Number::Float(f)) => f >= OrderedFloat(0f64),
|
||||||
@@ -1458,7 +1526,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
|
|
||||||
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
self.state_stack.push(TokenOrRedirect::NumberFocus(
|
||||||
max_depth,
|
max_depth,
|
||||||
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port as i64))),
|
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port))),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
self.state_stack.push(TokenOrRedirect::Comma);
|
self.state_stack.push(TokenOrRedirect::Comma);
|
||||||
@@ -1469,23 +1537,29 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_index_ptr(&mut self, index_ptr: IndexPtr, max_depth: usize) {
|
fn print_index_ptr(&mut self, idx: CodeIndexOffset, max_depth: usize) {
|
||||||
if self.format_struct(max_depth, 1, atom!("$index_ptr")) {
|
if self.format_struct(max_depth, 1, atom!("$index_ptr")) {
|
||||||
let atom = self.state_stack.pop().unwrap();
|
let atom = self.state_stack.pop().unwrap();
|
||||||
|
|
||||||
self.state_stack.pop();
|
self.state_stack.pop();
|
||||||
self.state_stack.pop();
|
self.state_stack.pop();
|
||||||
|
|
||||||
let offset = if index_ptr.is_undefined() || index_ptr.is_dynamic_undefined() {
|
let idx_ptr = self.arena.code_index_tbl.get_entry(idx);
|
||||||
|
|
||||||
|
let offset = if idx_ptr.is_undefined() || idx_ptr.is_dynamic_undefined() {
|
||||||
TokenOrRedirect::Atom(atom!("undefined"))
|
TokenOrRedirect::Atom(atom!("undefined"))
|
||||||
} else {
|
} else {
|
||||||
let idx = index_ptr.p() as i64;
|
let idx_ptr_p = idx_ptr.p() as i64;
|
||||||
|
|
||||||
TokenOrRedirect::NumberFocus(
|
if let Ok(n) = Fixnum::build_with_checked(idx_ptr_p) {
|
||||||
max_depth,
|
TokenOrRedirect::NumberFocus(
|
||||||
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx))),
|
max_depth,
|
||||||
None,
|
NumberFocus::Unfocused(Number::Fixnum(n)),
|
||||||
)
|
None,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
TokenOrRedirect::Atom(atom!("out_of_bounds_idx_ptr"))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.state_stack.push(offset);
|
self.state_stack.push(offset);
|
||||||
@@ -1521,32 +1595,26 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
|
|
||||||
fn print_comma_separated_char_list(&mut self, char_list: CommaSeparatedCharList) {
|
fn print_comma_separated_char_list(&mut self, char_list: CommaSeparatedCharList) {
|
||||||
let CommaSeparatedCharList {
|
let CommaSeparatedCharList {
|
||||||
pstr,
|
pstr_loc,
|
||||||
offset,
|
|
||||||
max_depth,
|
max_depth,
|
||||||
end_cell,
|
|
||||||
end_h,
|
|
||||||
} = char_list;
|
} = char_list;
|
||||||
let pstr_str = pstr.as_str_from(offset);
|
|
||||||
|
|
||||||
if let Some(c) = pstr_str.chars().next() {
|
let c = self.iter.heap.char_at(pstr_loc);
|
||||||
let offset = offset + c.len_utf8();
|
|
||||||
|
|
||||||
|
if c != '\u{0}' {
|
||||||
if !self.max_depth_exhausted(max_depth) {
|
if !self.max_depth_exhausted(max_depth) {
|
||||||
self.state_stack
|
self.state_stack
|
||||||
.push(TokenOrRedirect::CommaSeparatedCharList(
|
.push(TokenOrRedirect::CommaSeparatedCharList(
|
||||||
CommaSeparatedCharList {
|
CommaSeparatedCharList {
|
||||||
pstr,
|
pstr_loc: pstr_loc + c.len_utf8(),
|
||||||
offset,
|
|
||||||
max_depth: max_depth.saturating_sub(1),
|
max_depth: max_depth.saturating_sub(1),
|
||||||
end_cell,
|
|
||||||
end_h,
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
let max_depth_allows = self.max_depth == 0 || max_depth > 1;
|
let max_depth_allows = self.max_depth == 0 || max_depth > 1;
|
||||||
|
let next_c = self.iter.heap.char_at(pstr_loc + c.len_utf8());
|
||||||
|
|
||||||
if max_depth_allows && pstr_str.chars().nth(1).is_some() {
|
if max_depth_allows && next_c != '\u{0}' {
|
||||||
self.state_stack.push(TokenOrRedirect::Comma);
|
self.state_stack.push(TokenOrRedirect::Comma);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1558,12 +1626,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
} else if self.max_depth_exhausted(max_depth) {
|
} else if self.max_depth_exhausted(max_depth) {
|
||||||
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
|
||||||
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
|
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
|
||||||
} else if end_cell != empty_list_as_cell!() {
|
} else {
|
||||||
if let Some(end_h) = end_h {
|
|
||||||
self.iter
|
|
||||||
.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.state_stack
|
self.state_stack
|
||||||
.push(TokenOrRedirect::FunctorRedirect(max_depth + 1));
|
.push(TokenOrRedirect::FunctorRedirect(max_depth + 1));
|
||||||
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
|
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
|
||||||
@@ -1576,7 +1639,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
is_functor_redirect: bool,
|
is_functor_redirect: bool,
|
||||||
mut max_depth: usize,
|
mut max_depth: usize,
|
||||||
) {
|
) {
|
||||||
let negated_operand = negated_op_needs_bracketing(&self.iter, self.op_dir, &op);
|
let negated_operand =
|
||||||
|
negated_op_needs_bracketing(&self.iter, &self.arena.f64_tbl, self.op_dir, &op);
|
||||||
|
|
||||||
let addr = match self.check_for_seen(&mut max_depth) {
|
let addr = match self.check_for_seen(&mut max_depth) {
|
||||||
Some(addr) => addr,
|
Some(addr) => addr,
|
||||||
@@ -1658,10 +1722,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
print_struct(self, name, arity);
|
print_struct(self, name, arity);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Char, c) => {
|
|
||||||
let name = AtomTable::build_with(&self.atom_tbl, &String::from(c));
|
|
||||||
print_struct(self, name, 0);
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
let (name, arity) = cell_as_atom_cell!(self.iter.heap[s])
|
let (name, arity) = cell_as_atom_cell!(self.iter.heap[s])
|
||||||
.get_name_and_arity();
|
.get_name_and_arity();
|
||||||
@@ -1682,13 +1742,17 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::CodeIndexOffset, idx) => {
|
||||||
|
self.print_index_ptr(idx, self.max_depth);
|
||||||
|
}
|
||||||
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
|
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
|
||||||
self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op);
|
self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::F64, f) => {
|
(HeapCellValueTag::F64Offset, offset) => {
|
||||||
self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(*f)), &op);
|
let f = self.arena.f64_tbl.get_entry(offset);
|
||||||
|
self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(f)), &op);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
(HeapCellValueTag::PStrLoc) => {
|
||||||
self.print_list_like(max_depth);
|
self.print_list_like(max_depth);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Lis) => {
|
(HeapCellValueTag::Lis) => {
|
||||||
@@ -1725,8 +1789,22 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
(ArenaHeaderTag::Dropped, _value) => {
|
(ArenaHeaderTag::Dropped, _value) => {
|
||||||
self.print_impromptu_atom(atom!("$dropped_value"));
|
self.print_impromptu_atom(atom!("$dropped_value"));
|
||||||
}
|
}
|
||||||
(ArenaHeaderTag::IndexPtr, index_ptr) => {
|
(ArenaHeaderTag::ChildProcess, process) => {
|
||||||
self.print_index_ptr(*index_ptr, max_depth);
|
|
||||||
|
let process_atom = atom!("$process");
|
||||||
|
|
||||||
|
if self.format_struct(max_depth, 1, process_atom) {
|
||||||
|
let atom = TokenOrRedirect::NumberFocus(max_depth, NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(process.id()))), op);
|
||||||
|
|
||||||
|
let process_root = self.state_stack.pop().unwrap();
|
||||||
|
|
||||||
|
self.state_stack.pop();
|
||||||
|
self.state_stack.pop();
|
||||||
|
|
||||||
|
self.state_stack.push(atom);
|
||||||
|
self.state_stack.push(TokenOrRedirect::Open);
|
||||||
|
self.state_stack.push(process_root);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
}
|
}
|
||||||
@@ -1825,6 +1903,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use crate::functor_macro::*;
|
||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1832,23 +1911,30 @@ mod tests {
|
|||||||
fn term_printing_tests() {
|
fn term_printing_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
// clear the heap of resource error data etc
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
let f_atom = atom!("f");
|
let f_atom = atom!("f");
|
||||||
let a_atom = atom!("a");
|
let a_atom = atom!("a");
|
||||||
let b_atom = atom!("b");
|
let b_atom = atom!("b");
|
||||||
let c_atom = atom!("c");
|
let c_atom = atom!("c");
|
||||||
|
|
||||||
wam.machine_st
|
let mut functor_writer = Heap::functor_writer(functor!(
|
||||||
.heap
|
f_atom,
|
||||||
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
[atom_as_cell(a_atom), atom_as_cell(b_atom)]
|
||||||
|
));
|
||||||
|
|
||||||
|
let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
|
||||||
|
wam.machine_st.heap.push_cell(cell).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
3,
|
||||||
);
|
);
|
||||||
|
|
||||||
let output = printer.print();
|
let output = printer.print();
|
||||||
@@ -1860,24 +1946,28 @@ mod tests {
|
|||||||
|
|
||||||
wam.machine_st.heap.clear();
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
wam.machine_st.heap.extend(functor!(
|
let mut functor_writer = Heap::functor_writer(functor!(
|
||||||
f_atom,
|
f_atom,
|
||||||
[
|
[
|
||||||
atom(a_atom),
|
atom_as_cell(a_atom),
|
||||||
atom(b_atom),
|
atom_as_cell(b_atom),
|
||||||
atom(a_atom),
|
atom_as_cell(a_atom),
|
||||||
cell(str_loc_as_cell!(0))
|
str_loc_as_cell(0)
|
||||||
]
|
]
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push_cell(cell).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
5,
|
||||||
);
|
);
|
||||||
|
|
||||||
let output = printer.print();
|
let output = printer.print();
|
||||||
@@ -1889,19 +1979,23 @@ mod tests {
|
|||||||
|
|
||||||
wam.machine_st.heap.clear();
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
let mut writer = wam.machine_st.heap.reserve(96).unwrap();
|
||||||
|
|
||||||
// print L = [L|L].
|
// print L = [L|L].
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(1));
|
writer.write_with(|section| {
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(1));
|
section.push_cell(list_loc_as_cell!(1));
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(1));
|
section.push_cell(list_loc_as_cell!(1));
|
||||||
|
section.push_cell(list_loc_as_cell!(1));
|
||||||
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
let output = printer.print();
|
let output = printer.print();
|
||||||
@@ -1910,11 +2004,11 @@ mod tests {
|
|||||||
|
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
printer
|
printer
|
||||||
@@ -1930,24 +2024,35 @@ mod tests {
|
|||||||
|
|
||||||
wam.machine_st.heap.clear();
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
|
let mut writer = wam.machine_st.heap.reserve(96).unwrap();
|
||||||
|
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(1));
|
writer.write_with(|section| {
|
||||||
wam.machine_st.heap.push(str_loc_as_cell!(5));
|
section.push_cell(list_loc_as_cell!(1));
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(3));
|
section.push_cell(str_loc_as_cell!(5));
|
||||||
wam.machine_st.heap.push(str_loc_as_cell!(5));
|
section.push_cell(list_loc_as_cell!(3));
|
||||||
wam.machine_st.heap.push(empty_list_as_cell!());
|
section.push_cell(str_loc_as_cell!(5));
|
||||||
|
section.push_cell(empty_list_as_cell!());
|
||||||
|
});
|
||||||
|
|
||||||
wam.machine_st.heap.extend(functor);
|
let mut functor_writer = Heap::functor_writer(functor!(
|
||||||
|
f_atom,
|
||||||
|
[
|
||||||
|
atom_as_cell(a_atom),
|
||||||
|
atom_as_cell(b_atom),
|
||||||
|
atom_as_cell(b_atom)
|
||||||
|
]
|
||||||
|
));
|
||||||
|
|
||||||
|
functor_writer(&mut wam.machine_st.heap).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
let output = printer.print();
|
let output = printer.print();
|
||||||
@@ -1962,11 +2067,11 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
let output = printer.print();
|
let output = printer.print();
|
||||||
@@ -1979,11 +2084,11 @@ mod tests {
|
|||||||
{
|
{
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
printer
|
printer
|
||||||
@@ -1999,23 +2104,28 @@ mod tests {
|
|||||||
|
|
||||||
// issue #382
|
// issue #382
|
||||||
wam.machine_st.heap.clear();
|
wam.machine_st.heap.clear();
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(1));
|
|
||||||
|
|
||||||
for idx in 0..3000 {
|
let mut writer = wam.machine_st.heap.reserve(6002).unwrap();
|
||||||
wam.machine_st.heap.push(heap_loc_as_cell!(2 * idx + 1));
|
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(2 * idx + 2 + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
wam.machine_st.heap.push(empty_list_as_cell!());
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(list_loc_as_cell!(1));
|
||||||
|
|
||||||
|
for idx in 0..3000 {
|
||||||
|
section.push_cell(heap_loc_as_cell!(2 * idx + 1));
|
||||||
|
section.push_cell(list_loc_as_cell!(2 * idx + 2 + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
section.push_cell(empty_list_as_cell!());
|
||||||
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
printer.max_depth = 5;
|
printer.max_depth = 5;
|
||||||
@@ -2029,16 +2139,19 @@ mod tests {
|
|||||||
|
|
||||||
wam.machine_st.heap.clear();
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
put_partial_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
|
wam.machine_st.heap.allocate_pstr("abc").unwrap();
|
||||||
|
|
||||||
|
wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
|
||||||
|
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let printer = HCPrinter::new(
|
let printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
pstr_loc_as_cell!(0),
|
2,
|
||||||
);
|
);
|
||||||
|
|
||||||
let output = printer.print();
|
let output = printer.print();
|
||||||
@@ -2048,25 +2161,27 @@ mod tests {
|
|||||||
|
|
||||||
all_cells_unmarked(&wam.machine_st.heap);
|
all_cells_unmarked(&wam.machine_st.heap);
|
||||||
|
|
||||||
wam.machine_st.heap.pop();
|
let mut writer = wam.machine_st.heap.reserve(96).unwrap();
|
||||||
|
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(2));
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(atom_as_cell!(a_atom));
|
||||||
|
section.push_cell(list_loc_as_cell!(5));
|
||||||
|
section.push_cell(atom_as_cell!(b_atom));
|
||||||
|
section.push_cell(list_loc_as_cell!(7));
|
||||||
|
section.push_cell(atom_as_cell!(c_atom));
|
||||||
|
section.push_cell(empty_list_as_cell!());
|
||||||
|
});
|
||||||
|
|
||||||
wam.machine_st.heap.push(atom_as_cell!(a_atom));
|
wam.machine_st.heap[1] = list_loc_as_cell!(3);
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(4));
|
|
||||||
wam.machine_st.heap.push(atom_as_cell!(b_atom));
|
|
||||||
wam.machine_st.heap.push(list_loc_as_cell!(6));
|
|
||||||
wam.machine_st.heap.push(atom_as_cell!(c_atom));
|
|
||||||
wam.machine_st.heap.push(empty_list_as_cell!());
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut wam.machine_st.heap,
|
&mut wam.machine_st.heap,
|
||||||
Arc::clone(&wam.machine_st.atom_tbl),
|
|
||||||
&mut wam.machine_st.stack,
|
&mut wam.machine_st.stack,
|
||||||
|
&wam.machine_st.arena,
|
||||||
&wam.op_dir,
|
&wam.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(0),
|
2,
|
||||||
);
|
);
|
||||||
|
|
||||||
printer.double_quotes = true;
|
printer.double_quotes = true;
|
||||||
|
|||||||
116
src/indexing.rs
116
src/indexing.rs
@@ -3,6 +3,7 @@ use crate::parser::ast::*;
|
|||||||
|
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::instructions::*;
|
use crate::instructions::*;
|
||||||
|
use crate::types::HeapCellValue;
|
||||||
|
|
||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
@@ -112,7 +113,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
|
|
||||||
match constant_key {
|
match constant_key {
|
||||||
Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
|
Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
|
||||||
constants.insert(*constant, constant_ptr);
|
constants.insert(HeapCellValue::from(*constant), constant_ptr);
|
||||||
}
|
}
|
||||||
_ if constant_ptr.is_external() => {
|
_ if constant_ptr.is_external() => {
|
||||||
// this must be a defunct clause, because it's been deleted
|
// this must be a defunct clause, because it's been deleted
|
||||||
@@ -144,7 +145,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
fn add_static_indexed_choice_for_constant(
|
fn add_static_indexed_choice_for_constant(
|
||||||
&mut self,
|
&mut self,
|
||||||
external: usize,
|
external: usize,
|
||||||
constant: Literal,
|
constant: HeapCellValue,
|
||||||
index: usize,
|
index: usize,
|
||||||
) {
|
) {
|
||||||
let third_level_index = if self.append_or_prepend.is_append() {
|
let third_level_index = if self.append_or_prepend.is_append() {
|
||||||
@@ -181,7 +182,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
fn add_dynamic_indexed_choice_for_constant(
|
fn add_dynamic_indexed_choice_for_constant(
|
||||||
&mut self,
|
&mut self,
|
||||||
external: usize,
|
external: usize,
|
||||||
constant: Literal,
|
constant: HeapCellValue,
|
||||||
index: usize,
|
index: usize,
|
||||||
) {
|
) {
|
||||||
let third_level_index = if self.append_or_prepend.is_append() {
|
let third_level_index = if self.append_or_prepend.is_append() {
|
||||||
@@ -235,8 +236,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
|
|
||||||
fn index_overlapping_constant(
|
fn index_overlapping_constant(
|
||||||
&mut self,
|
&mut self,
|
||||||
orig_constant: Literal,
|
orig_constant: HeapCellValue,
|
||||||
overlapping_constant: Literal,
|
overlapping_constant: HeapCellValue,
|
||||||
index: usize,
|
index: usize,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
@@ -316,7 +317,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index_constant(&mut self, constant: Literal, index: usize) {
|
fn index_constant(&mut self, constant: HeapCellValue, index: usize) {
|
||||||
loop {
|
loop {
|
||||||
let indexing_code_len = self.indexing_code.len();
|
let indexing_code_len = self.indexing_code.len();
|
||||||
|
|
||||||
@@ -633,12 +634,15 @@ pub(crate) fn merge_clause_index(
|
|||||||
match &opt_arg_index_key {
|
match &opt_arg_index_key {
|
||||||
OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => {
|
OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => {
|
||||||
let offset = new_clause_loc - index_loc + 1;
|
let offset = new_clause_loc - index_loc + 1;
|
||||||
merging_ptr.index_constant(*constant, offset);
|
merging_ptr.index_constant(HeapCellValue::from(*constant), offset);
|
||||||
|
|
||||||
for overlapping_constant in overlapping_constants {
|
if let Some(overlapping_constant) = overlapping_constants {
|
||||||
merging_ptr.offset = 0;
|
merging_ptr.offset = 0;
|
||||||
|
merging_ptr.index_overlapping_constant(
|
||||||
merging_ptr.index_overlapping_constant(*constant, *overlapping_constant, offset);
|
HeapCellValue::from(*constant),
|
||||||
|
HeapCellValue::from(*overlapping_constant),
|
||||||
|
offset,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OptArgIndexKey::Structure(_, index_loc, name, arity) => {
|
OptArgIndexKey::Structure(_, index_loc, name, arity) => {
|
||||||
@@ -664,7 +668,7 @@ pub(crate) fn merge_clause_index(
|
|||||||
|
|
||||||
pub(crate) fn remove_constant_indices(
|
pub(crate) fn remove_constant_indices(
|
||||||
constant: Literal,
|
constant: Literal,
|
||||||
overlapping_constants: &[Literal],
|
overlapping_constants: Option<Literal>,
|
||||||
indexing_code: &mut [IndexingLine],
|
indexing_code: &mut [IndexingLine],
|
||||||
offset: usize,
|
offset: usize,
|
||||||
) {
|
) {
|
||||||
@@ -693,7 +697,7 @@ pub(crate) fn remove_constant_indices(
|
|||||||
|
|
||||||
let mut constants_index = 0;
|
let mut constants_index = 0;
|
||||||
|
|
||||||
for constant in iter {
|
for constant in iter.map(|l| HeapCellValue::from(*l)) {
|
||||||
loop {
|
loop {
|
||||||
match &mut indexing_code[index] {
|
match &mut indexing_code[index] {
|
||||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
|
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
|
||||||
@@ -701,8 +705,6 @@ pub(crate) fn remove_constant_indices(
|
|||||||
)) => {
|
)) => {
|
||||||
constants_index = index;
|
constants_index = index;
|
||||||
|
|
||||||
let constant = *constant;
|
|
||||||
|
|
||||||
match constants.get(&constant).cloned() {
|
match constants.get(&constant).cloned() {
|
||||||
Some(IndexingCodePtr::DynamicExternal(_))
|
Some(IndexingCodePtr::DynamicExternal(_))
|
||||||
| Some(IndexingCodePtr::External(_))
|
| Some(IndexingCodePtr::External(_))
|
||||||
@@ -740,7 +742,7 @@ pub(crate) fn remove_constant_indices(
|
|||||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
|
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
|
||||||
ref mut constants,
|
ref mut constants,
|
||||||
)) => {
|
)) => {
|
||||||
constants.insert(*constant, ext);
|
constants.insert(constant, ext);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -773,7 +775,7 @@ pub(crate) fn remove_constant_indices(
|
|||||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
|
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
|
||||||
ref mut constants,
|
ref mut constants,
|
||||||
)) => {
|
)) => {
|
||||||
constants.insert(*constant, ext);
|
constants.insert(constant, ext);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -1033,7 +1035,7 @@ pub(crate) fn remove_index(
|
|||||||
) {
|
) {
|
||||||
match opt_arg_index_key {
|
match opt_arg_index_key {
|
||||||
OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => {
|
OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => {
|
||||||
remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc);
|
remove_constant_indices(*constant, *overlapping_constants, indexing_code, clause_loc);
|
||||||
}
|
}
|
||||||
OptArgIndexKey::Structure(_, _, name, arity) => {
|
OptArgIndexKey::Structure(_, _, name, arity) => {
|
||||||
remove_structure_index(*name, *arity, indexing_code, clause_loc);
|
remove_structure_index(*name, *arity, indexing_code, clause_loc);
|
||||||
@@ -1095,56 +1097,26 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn constant_key_alternatives(
|
pub(crate) fn constant_key_alternatives(constant: Literal) -> Option<Literal> {
|
||||||
constant: Literal,
|
let n = match &constant {
|
||||||
atom_tbl: &AtomTable,
|
Literal::Rational(n) if n.denominator().is_one() => n.numerator(),
|
||||||
// arena: &mut Arena,
|
Literal::Integer(n) => n,
|
||||||
) -> Vec<Literal> {
|
_ => return None,
|
||||||
let mut constants = vec![];
|
};
|
||||||
|
|
||||||
match constant {
|
Fixnum::build_with_checked(n).map(Literal::Fixnum).ok()
|
||||||
Literal::Atom(ref name) => {
|
|
||||||
if let Some(c) = name.as_char() {
|
|
||||||
constants.push(Literal::Char(c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Literal::Char(c) => {
|
|
||||||
let atom = AtomTable::build_with(atom_tbl, &c.to_string());
|
|
||||||
constants.push(Literal::Atom(atom));
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
// constant_to_literal takes care of the downward conversion from Integer to Fixnum
|
|
||||||
// if possible.
|
|
||||||
Literal::Fixnum(ref n) => {
|
|
||||||
constants.push(Literal::Integer(arena_alloc!(n, arena)));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
Literal::Integer(ref n) => {
|
|
||||||
let result = (&**n).try_into();
|
|
||||||
if let Ok(value) = result {
|
|
||||||
Fixnum::build_with_checked(value)
|
|
||||||
.map(|n| {
|
|
||||||
constants.push(Literal::Fixnum(n));
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
constants
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct StaticCodeIndices {
|
pub(crate) struct StaticCodeIndices {
|
||||||
constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
constants: IndexMap<HeapCellValue, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||||
lists: VecDeque<IndexedChoiceInstruction>,
|
lists: VecDeque<IndexedChoiceInstruction>,
|
||||||
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct DynamicCodeIndices {
|
pub(crate) struct DynamicCodeIndices {
|
||||||
constants: IndexMap<Literal, VecDeque<usize>, FxBuildHasher>,
|
constants: IndexMap<HeapCellValue, VecDeque<usize>, FxBuildHasher>,
|
||||||
lists: VecDeque<usize>,
|
lists: VecDeque<usize>,
|
||||||
structures: IndexMap<(Atom, usize), VecDeque<usize>, FxBuildHasher>,
|
structures: IndexMap<(Atom, usize), VecDeque<usize>, FxBuildHasher>,
|
||||||
}
|
}
|
||||||
@@ -1156,7 +1128,7 @@ pub(crate) trait Indexer {
|
|||||||
|
|
||||||
fn constants(
|
fn constants(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>;
|
) -> &mut IndexMap<HeapCellValue, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>;
|
||||||
fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>;
|
fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>;
|
||||||
fn structures(
|
fn structures(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -1204,7 +1176,7 @@ impl Indexer for StaticCodeIndices {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn constants(
|
fn constants(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
|
) -> &mut IndexMap<HeapCellValue, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
|
||||||
&mut self.constants
|
&mut self.constants
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1328,7 +1300,7 @@ impl Indexer for DynamicCodeIndices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>, FxBuildHasher> {
|
fn constants(&mut self) -> &mut IndexMap<HeapCellValue, VecDeque<usize>, FxBuildHasher> {
|
||||||
&mut self.constants
|
&mut self.constants
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1447,14 +1419,13 @@ impl<I: Indexer> CodeOffsets<I> {
|
|||||||
self.indices.lists().push_back(index);
|
self.indices.lists().push_back(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index_constant(
|
fn index_constant(&mut self, constant: Literal, index: usize) -> Option<Literal> {
|
||||||
&mut self,
|
let overlapping_constant_opt = constant_key_alternatives(constant);
|
||||||
atom_tbl: &AtomTable,
|
let code = self
|
||||||
constant: Literal,
|
.indices
|
||||||
index: usize,
|
.constants()
|
||||||
) -> Vec<Literal> {
|
.entry(HeapCellValue::from(constant))
|
||||||
let overlapping_constants = constant_key_alternatives(constant, atom_tbl);
|
.or_default();
|
||||||
let code = self.indices.constants().entry(constant).or_default();
|
|
||||||
|
|
||||||
let is_initial_index = code.is_empty();
|
let is_initial_index = code.is_empty();
|
||||||
code.push_back(I::compute_index(
|
code.push_back(I::compute_index(
|
||||||
@@ -1463,8 +1434,8 @@ impl<I: Indexer> CodeOffsets<I> {
|
|||||||
self.non_counted_bt,
|
self.non_counted_bt,
|
||||||
));
|
));
|
||||||
|
|
||||||
for constant in &overlapping_constants {
|
if let Some(constant) = overlapping_constant_opt.map(HeapCellValue::from) {
|
||||||
let code = self.indices.constants().entry(*constant).or_default();
|
let code = self.indices.constants().entry(constant).or_default();
|
||||||
|
|
||||||
let is_initial_index = code.is_empty();
|
let is_initial_index = code.is_empty();
|
||||||
let index = I::compute_index(is_initial_index, index, self.non_counted_bt);
|
let index = I::compute_index(is_initial_index, index, self.non_counted_bt);
|
||||||
@@ -1472,7 +1443,7 @@ impl<I: Indexer> CodeOffsets<I> {
|
|||||||
code.push_back(index);
|
code.push_back(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
overlapping_constants
|
overlapping_constant_opt
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
|
fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
|
||||||
@@ -1494,14 +1465,13 @@ impl<I: Indexer> CodeOffsets<I> {
|
|||||||
optimal_arg: &Term,
|
optimal_arg: &Term,
|
||||||
index: usize,
|
index: usize,
|
||||||
clause_index_info: &mut ClauseIndexInfo,
|
clause_index_info: &mut ClauseIndexInfo,
|
||||||
atom_tbl: &AtomTable,
|
|
||||||
) {
|
) {
|
||||||
match optimal_arg {
|
match optimal_arg {
|
||||||
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
|
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
|
||||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
||||||
self.index_list(index);
|
self.index_list(index);
|
||||||
}
|
}
|
||||||
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
|
&Term::Cons(..) | &Term::PartialString(..) | &Term::CompleteString(..) => {
|
||||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
||||||
self.index_list(index);
|
self.index_list(index);
|
||||||
}
|
}
|
||||||
@@ -1512,7 +1482,7 @@ impl<I: Indexer> CodeOffsets<I> {
|
|||||||
self.index_structure(name, terms.len(), index);
|
self.index_structure(name, terms.len(), index);
|
||||||
}
|
}
|
||||||
&Term::Literal(_, constant) => {
|
&Term::Literal(_, constant) => {
|
||||||
let overlapping_constants = self.index_constant(atom_tbl, constant, index);
|
let overlapping_constants = self.index_constant(constant, index);
|
||||||
|
|
||||||
clause_index_info.opt_arg_index_key =
|
clause_index_info.opt_arg_index_key =
|
||||||
OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
|
OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crate::parser::ast::*;
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::iter::*;
|
use std::iter::*;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
#[allow(clippy::borrowed_box)]
|
#[allow(clippy::borrowed_box)]
|
||||||
@@ -15,27 +16,11 @@ pub(crate) enum TermRef<'a> {
|
|||||||
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||||
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
||||||
PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
PartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
|
||||||
CompleteString(Level, &'a Cell<RegType>, Atom),
|
CompleteString(Level, &'a Cell<RegType>, Rc<String>),
|
||||||
Var(Level, &'a Cell<VarReg>, VarPtr),
|
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
impl<'a> TermRef<'a> {
|
|
||||||
pub(crate) fn level(&self) -> Level {
|
|
||||||
match self {
|
|
||||||
TermRef::AnonVar(lvl) |
|
|
||||||
TermRef::Cons(lvl, ..) |
|
|
||||||
TermRef::Literal(lvl, ..) |
|
|
||||||
TermRef::Var(lvl, ..) |
|
|
||||||
TermRef::Clause(lvl, ..) |
|
|
||||||
TermRef::CompleteString(lvl, ..) |
|
|
||||||
TermRef::PartialString(lvl, ..) => *lvl,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[allow(clippy::borrowed_box)]
|
#[allow(clippy::borrowed_box)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum TermIterState<'a> {
|
pub(crate) enum TermIterState<'a> {
|
||||||
@@ -44,9 +29,9 @@ pub(crate) enum TermIterState<'a> {
|
|||||||
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||||
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
InitialPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
|
||||||
FinalPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
|
FinalPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
|
||||||
CompleteString(Level, &'a Cell<RegType>, Atom),
|
CompleteString(Level, &'a Cell<RegType>, Rc<String>),
|
||||||
Var(Level, &'a Cell<VarReg>, VarPtr),
|
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,9 +47,11 @@ impl<'a> TermIterState<'a> {
|
|||||||
}
|
}
|
||||||
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
|
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
|
||||||
Term::PartialString(cell, string_buf, tail) => {
|
Term::PartialString(cell, string_buf, tail) => {
|
||||||
TermIterState::InitialPartialString(lvl, cell, string_buf, tail)
|
TermIterState::InitialPartialString(lvl, cell, string_buf.clone(), tail)
|
||||||
|
}
|
||||||
|
Term::CompleteString(cell, string) => {
|
||||||
|
TermIterState::CompleteString(lvl, cell, string.clone())
|
||||||
}
|
}
|
||||||
Term::CompleteString(cell, atom) => TermIterState::CompleteString(lvl, cell, *atom),
|
|
||||||
Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
|
Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,11 +169,11 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
|
.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
|
||||||
self.push_subterm(lvl.child_level(), tail);
|
self.push_subterm(lvl.child_level(), tail);
|
||||||
}
|
}
|
||||||
TermIterState::FinalPartialString(lvl, cell, atom, tail) => {
|
TermIterState::FinalPartialString(lvl, cell, string, tail) => {
|
||||||
return Some(TermRef::PartialString(lvl, cell, atom, tail));
|
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||||
}
|
}
|
||||||
TermIterState::CompleteString(lvl, cell, atom) => {
|
TermIterState::CompleteString(lvl, cell, string) => {
|
||||||
return Some(TermRef::CompleteString(lvl, cell, atom));
|
return Some(TermRef::CompleteString(lvl, cell, string));
|
||||||
}
|
}
|
||||||
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
||||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||||
@@ -242,16 +229,20 @@ impl<'a> FactIterator<'a> {
|
|||||||
head.as_ref(),
|
head.as_ref(),
|
||||||
tail.as_ref(),
|
tail.as_ref(),
|
||||||
)],
|
)],
|
||||||
Term::PartialString(cell, string_buf, tail) => {
|
Term::PartialString(cell, string, tail) => {
|
||||||
vec![TermIterState::InitialPartialString(
|
vec![TermIterState::InitialPartialString(
|
||||||
Level::Root,
|
Level::Root,
|
||||||
cell,
|
cell,
|
||||||
string_buf,
|
string.clone(),
|
||||||
tail,
|
tail,
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
Term::CompleteString(cell, atom) => {
|
Term::CompleteString(cell, string) => {
|
||||||
vec![TermIterState::CompleteString(Level::Root, cell, *atom)]
|
vec![TermIterState::CompleteString(
|
||||||
|
Level::Root,
|
||||||
|
cell,
|
||||||
|
string.clone(),
|
||||||
|
)]
|
||||||
}
|
}
|
||||||
Term::Literal(cell, constant) => {
|
Term::Literal(cell, constant) => {
|
||||||
vec![TermIterState::Literal(Level::Root, cell, constant)]
|
vec![TermIterState::Literal(Level::Root, cell, constant)]
|
||||||
@@ -336,7 +327,7 @@ pub(crate) enum ClauseItem<'a> {
|
|||||||
FirstBranch(usize),
|
FirstBranch(usize),
|
||||||
NextBranch,
|
NextBranch,
|
||||||
BranchEnd(usize),
|
BranchEnd(usize),
|
||||||
Chunk(&'a VecDeque<QueryTerm>),
|
Chunk { terms: &'a VecDeque<QueryTerm> },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -412,8 +403,8 @@ impl<'a> Iterator for ClauseIterator<'a> {
|
|||||||
self.state_stack
|
self.state_stack
|
||||||
.push(ClauseIteratorState::RemainingBranches(branches, 0));
|
.push(ClauseIteratorState::RemainingBranches(branches, 0));
|
||||||
}
|
}
|
||||||
ChunkedTerms::Chunk(chunk) => {
|
ChunkedTerms::Chunk { ref terms } => {
|
||||||
return Some(ClauseItem::Chunk(chunk));
|
return Some(ClauseItem::Chunk { terms });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,11 @@ pub(crate) mod macros;
|
|||||||
pub(crate) mod atom_table;
|
pub(crate) mod atom_table;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub(crate) mod arena;
|
pub(crate) mod arena;
|
||||||
|
pub(crate) mod offset_table;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub(crate) mod parser;
|
pub(crate) mod parser;
|
||||||
|
#[macro_use]
|
||||||
|
pub(crate) mod functor_macro;
|
||||||
mod allocator;
|
mod allocator;
|
||||||
mod arithmetic;
|
mod arithmetic;
|
||||||
pub(crate) mod codegen;
|
pub(crate) mod codegen;
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ call(_, _, _, _, _, _, _, _, _).
|
|||||||
%
|
%
|
||||||
% The flags that Scryer Prolog support are:
|
% The flags that Scryer Prolog support are:
|
||||||
%
|
%
|
||||||
% * `max_arity`: The max arity a predicate can have in Prolog. On Scryer is set to 1023. Read only.
|
% * `max_arity`: The max arity a predicate can have in Prolog. On Scryer is set to 255. Read only.
|
||||||
% * `bounded`: `true` if integer arithmethic is bounded between some min/max values. On Scryer is always set
|
% * `bounded`: `true` if integer arithmethic is bounded between some min/max values. On Scryer is always set
|
||||||
% to `false` since it supports unbounded integer arithmethic. Read only.
|
% to `false` since it supports unbounded integer arithmethic. Read only.
|
||||||
% * `integer_rounding_function`: Describes the rounding donde by `//` and `rem` functions. On Scryer is
|
% * `integer_rounding_function`: Describes the rounding donde by `//` and `rem` functions. On Scryer is
|
||||||
@@ -145,8 +145,8 @@ call(_, _, _, _, _, _, _, _, _).
|
|||||||
% `fail` (the call silently fails) and `warn` (the call fails and a warning about the undefined predicate is printed).
|
% `fail` (the call silently fails) and `warn` (the call fails and a warning about the undefined predicate is printed).
|
||||||
% * `answer_write_options`: Additional write options used by the top level for writing answers.
|
% * `answer_write_options`: Additional write options used by the top level for writing answers.
|
||||||
%
|
%
|
||||||
current_prolog_flag(Flag, Value) :- Flag == max_arity, !, Value = 1023.
|
current_prolog_flag(Flag, Value) :- Flag == max_arity, !, Value = 255.
|
||||||
current_prolog_flag(max_arity, 1023).
|
current_prolog_flag(max_arity, 255).
|
||||||
current_prolog_flag(Flag, Value) :- Flag == bounded, !, Value = false.
|
current_prolog_flag(Flag, Value) :- Flag == bounded, !, Value = false.
|
||||||
current_prolog_flag(bounded, false).
|
current_prolog_flag(bounded, false).
|
||||||
current_prolog_flag(Flag, Value) :- Flag == integer_rounding_function, !, Value == toward_zero.
|
current_prolog_flag(Flag, Value) :- Flag == integer_rounding_function, !, Value == toward_zero.
|
||||||
@@ -1719,20 +1719,27 @@ must_be_number(N, PI) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
chars_or_vars(Cs, _) :-
|
chars_or_vars(Cs, PI) :-
|
||||||
|
( '$is_partial_string'(Cs) ->
|
||||||
|
% use a fast test for the expected case
|
||||||
|
true
|
||||||
|
; chars_or_vars_(Cs, PI)
|
||||||
|
).
|
||||||
|
|
||||||
|
chars_or_vars_(Cs, _) :-
|
||||||
( var(Cs) ->
|
( var(Cs) ->
|
||||||
!
|
!
|
||||||
; Cs == [] ->
|
; Cs == [] ->
|
||||||
!
|
!
|
||||||
).
|
).
|
||||||
chars_or_vars([C|Cs], PI) :-
|
chars_or_vars_([C|Cs], PI) :-
|
||||||
( nonvar(C) ->
|
( nonvar(C) ->
|
||||||
( atom(C),
|
( atom(C),
|
||||||
atom_length(C, 1) ->
|
atom_length(C, 1) ->
|
||||||
chars_or_vars(Cs, PI)
|
chars_or_vars_(Cs, PI)
|
||||||
; throw(error(type_error(character, C), PI))
|
; throw(error(type_error(character, C), PI))
|
||||||
)
|
)
|
||||||
; chars_or_vars(Cs, PI)
|
; chars_or_vars_(Cs, PI)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ but they're not part of the ISO Prolog standard at the moment.
|
|||||||
copy_term/3]).
|
copy_term/3]).
|
||||||
|
|
||||||
:- use_module(library(error), [can_be/2,
|
:- use_module(library(error), [can_be/2,
|
||||||
|
must_be/2,
|
||||||
domain_error/3,
|
domain_error/3,
|
||||||
instantiation_error/1,
|
instantiation_error/1,
|
||||||
type_error/3]).
|
type_error/3]).
|
||||||
@@ -275,17 +276,15 @@ call_with_inference_limit(_, _, R, Bb, B) :-
|
|||||||
; nonvar(R)
|
; nonvar(R)
|
||||||
).
|
).
|
||||||
|
|
||||||
%% partial_string(String, L, L0)
|
%% partial_string(String, Ls0, Ls)
|
||||||
%
|
%
|
||||||
% Explicitly construct a partial string "manually". It can be used as an optimized append/3.
|
% Explicitly construct a partial string "manually". It can be used as an optimized append/3.
|
||||||
% It's not recommended to use this predicate in application code.
|
% It's not recommended to use this predicate in application code.
|
||||||
partial_string(String, L, L0) :-
|
partial_string(String, Ls0, Ls) :-
|
||||||
|
must_be(chars, String),
|
||||||
( String == [] ->
|
( String == [] ->
|
||||||
L = L0
|
Ls0 = Ls
|
||||||
; catch(atom_chars(Atom, String),
|
; '$create_partial_string'(String, Ls0, Ls)
|
||||||
error(E, _),
|
|
||||||
throw(error(E, partial_string/3))),
|
|
||||||
'$create_partial_string'(Atom, L, L0)
|
|
||||||
).
|
).
|
||||||
|
|
||||||
%% partial_string(+String)
|
%% partial_string(+String)
|
||||||
|
|||||||
@@ -39,7 +39,8 @@
|
|||||||
% represented as a list of characters.
|
% represented as a list of characters.
|
||||||
|
|
||||||
phrase_from_stream(GRBody, Stream) :-
|
phrase_from_stream(GRBody, Stream) :-
|
||||||
stream_to_lazy_list(Stream, Ls),
|
stream_property(Stream, reposition(Reposition)),
|
||||||
|
stream_to_lazy_list(Reposition, Stream, Ls),
|
||||||
phrase(GRBody, Ls).
|
phrase(GRBody, Ls).
|
||||||
|
|
||||||
%% phrase_from_file(+GRBody, +File)
|
%% phrase_from_file(+GRBody, +File)
|
||||||
@@ -64,7 +65,7 @@ phrase_from_file(NT, File, Options) :-
|
|||||||
; Type = text
|
; Type = text
|
||||||
),
|
),
|
||||||
setup_call_cleanup(
|
setup_call_cleanup(
|
||||||
open(File, read, Stream, Options),
|
open(File, read, Stream, [reposition(true)|Options]),
|
||||||
phrase_from_stream(NT, Stream),
|
phrase_from_stream(NT, Stream),
|
||||||
close(Stream)
|
close(Stream)
|
||||||
)
|
)
|
||||||
@@ -73,34 +74,41 @@ phrase_from_file(NT, File, Options) :-
|
|||||||
% How many chars to read from stream and buffer in each step
|
% How many chars to read from stream and buffer in each step
|
||||||
chars_to_read(4096).
|
chars_to_read(4096).
|
||||||
|
|
||||||
stream_to_lazy_list(Stream, Ls) :-
|
stream_to_lazy_list(Reposition, Stream, Ls) :-
|
||||||
get_stream_buffer_position(Stream, Pos),
|
get_stream_buffer_position(Reposition, Stream, Pos),
|
||||||
freeze(Ls, render_step(Stream, Pos, Ls)).
|
freeze(Ls, render_step(Reposition, Stream, Pos, Ls)).
|
||||||
|
|
||||||
render_step(Stream, Pos, Ls) :-
|
render_step(Reposition, Stream, Pos, Ls) :-
|
||||||
set_stream_buffer_position(Stream, Pos),
|
set_stream_buffer_position(Reposition, Stream, Pos),
|
||||||
( buffer_at_end_of_stream(Stream) ->
|
( buffer_at_end_of_stream(Reposition, Stream) ->
|
||||||
Ls = []
|
Ls = []
|
||||||
; chars_to_read(CharsToRead),
|
; chars_to_read(CharsToRead),
|
||||||
buffer_get_n_chars(Stream, CharsToRead, Chars),
|
buffer_get_n_chars(Reposition, Stream, CharsToRead, Chars),
|
||||||
partial_string(Chars, Ls, Ls0),
|
partial_string(Chars, Ls, Ls0),
|
||||||
stream_to_lazy_list(Stream, Ls0)
|
stream_to_lazy_list(Reposition, Stream, Ls0)
|
||||||
).
|
).
|
||||||
|
|
||||||
buffer_at_end_of_stream(Stream) :-
|
buffer_at_end_of_stream(true, Stream) :- at_end_of_stream(Stream).
|
||||||
|
buffer_at_end_of_stream(false, Stream) :-
|
||||||
stream_bufferids(Stream, _, BufferPosId, _),
|
stream_bufferids(Stream, _, BufferPosId, _),
|
||||||
bb_get(BufferPosId, Pos),
|
bb_get(BufferPosId, Pos),
|
||||||
Pos = eof.
|
Pos = eof.
|
||||||
|
|
||||||
get_stream_buffer_position(Stream, Pos) :-
|
get_stream_buffer_position(true, Stream, Pos) :-
|
||||||
|
stream_property(Stream, position(Pos)).
|
||||||
|
get_stream_buffer_position(false, Stream, Pos) :-
|
||||||
stream_bufferids(Stream, _, BufferPosId, _),
|
stream_bufferids(Stream, _, BufferPosId, _),
|
||||||
bb_get(BufferPosId, Pos).
|
bb_get(BufferPosId, Pos).
|
||||||
|
|
||||||
set_stream_buffer_position(Stream, Pos) :-
|
set_stream_buffer_position(true, Stream, Pos) :-
|
||||||
|
set_stream_position(Stream, Pos).
|
||||||
|
set_stream_buffer_position(false, Stream, Pos) :-
|
||||||
stream_bufferids(Stream, _, BufferPosId, _),
|
stream_bufferids(Stream, _, BufferPosId, _),
|
||||||
bb_put(BufferPosId, Pos).
|
bb_put(BufferPosId, Pos).
|
||||||
|
|
||||||
buffer_get_n_chars(Stream, N, Chars) :-
|
buffer_get_n_chars(true, Stream, N, Chars) :-
|
||||||
|
get_n_chars(Stream, N, Chars).
|
||||||
|
buffer_get_n_chars(false, Stream, N, Chars) :-
|
||||||
stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId),
|
stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId),
|
||||||
buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N),
|
buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N),
|
||||||
bb_get(BufferId, Buffer),
|
bb_get(BufferId, Buffer),
|
||||||
|
|||||||
224
src/lib/process.pl
Normal file
224
src/lib/process.pl
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
:- module(process, [
|
||||||
|
process_create/3,
|
||||||
|
process_id/2,
|
||||||
|
process_release/1,
|
||||||
|
process_wait/2,
|
||||||
|
process_wait/3,
|
||||||
|
process_kill/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(library(error)).
|
||||||
|
:- use_module(library(iso_ext)).
|
||||||
|
:- use_module(library(lists), [member/2, maplist/2, maplist/3, append/2]).
|
||||||
|
:- use_module(library(reif), [tfilter/3, memberd_t/3]).
|
||||||
|
|
||||||
|
|
||||||
|
%% process_create(+Exe, +Args:list, +Options).
|
||||||
|
%
|
||||||
|
% Create a new process by executing the executable Exe and passing it the Arguments Args.
|
||||||
|
%
|
||||||
|
% Note: On windows please take note of [windows argument splitting](https://doc.rust-lang.org/std/process/index.html#windows-argument-splitting).
|
||||||
|
%
|
||||||
|
% Options is a list consisting of the following options:
|
||||||
|
%
|
||||||
|
% * `cwd(+Path)` Set the processes working directory to `Path`
|
||||||
|
% * `process(-Process)` `Process` will be assigned a process handle for the spawned process
|
||||||
|
% * `env(+List)` Don't inherit environment variables and set the variables defined in `List`
|
||||||
|
% * `environment(+List)` Inherit environment variables and set/override the variables defined in `List`
|
||||||
|
% * `stdin(Spec)`, `stdout(Spec)` or `stderr(Spec)` defines how to redirect the spawned processes io streams
|
||||||
|
%
|
||||||
|
% The elements of `List` in `env(List)`/`environment(List)` List must be string pairs using `=/2`.
|
||||||
|
% `env/1` and `environment/1` may not be both specified.
|
||||||
|
%
|
||||||
|
% The following stdio `Spec` are available:
|
||||||
|
%
|
||||||
|
% * `std` inherit the current processes original stdio streams (does currently not account for stdio being changed by `set_input` or `set_output`)
|
||||||
|
% * `file(+Path)` attach the strea to the file at `Path`
|
||||||
|
% * `null` discards writes and behaves as eof for read. Equivalent to using `file(/dev/null)`
|
||||||
|
% * `pipe(-Steam)` create a new pipe and assigne one end to the created process and the other end to `Stream`
|
||||||
|
%
|
||||||
|
% Specifying an option multiple times is an error, when an option is not specified the following defaults apply:
|
||||||
|
%
|
||||||
|
% - `cwd(".")`
|
||||||
|
% - `environment([])`
|
||||||
|
% - `stdin(std)`, `stdout(std)`, `stderr(std)`
|
||||||
|
%
|
||||||
|
process_create(Exe, Args, Options) :- call_with_error_context(process_create_(Exe, Args, Options), predicate-process_create/3).
|
||||||
|
|
||||||
|
process_create_(Exe, Args, Options) :-
|
||||||
|
must_be(chars, Exe),
|
||||||
|
must_be(list, Args),
|
||||||
|
maplist(must_be(chars), Args),
|
||||||
|
must_be(list, Options),
|
||||||
|
check_options(
|
||||||
|
[
|
||||||
|
option([stdin], valid_stdio, stdin(std), stdin(Stdin)),
|
||||||
|
option([stdout], valid_stdio, stdout(std), stdout(Stdout)),
|
||||||
|
option([stderr], valid_stdio, stderr(std), stderr(Stderr)),
|
||||||
|
option([env, environment], valid_env, environment([]), Env),
|
||||||
|
option([process], valid_uninit_process, process(_), process(Process)),
|
||||||
|
option([cwd], valid_cwd, cwd("."), cwd(Cwd))
|
||||||
|
],
|
||||||
|
Options,
|
||||||
|
process_create_option
|
||||||
|
),
|
||||||
|
Stdin =.. Stdin1,
|
||||||
|
Stdout =.. Stdout1,
|
||||||
|
Stderr =.. Stderr1,
|
||||||
|
simplify_env(Env, Env1),
|
||||||
|
'$process_create'(Exe, Args, Stdin1, Stdout1, Stderr1, Env1, Cwd, Process).
|
||||||
|
|
||||||
|
%% process_id(+Process, -Pid).
|
||||||
|
%
|
||||||
|
process_id(Process, Pid) :- call_with_error_context(process_id_(Process, Pid), predicate-process_id/2).
|
||||||
|
|
||||||
|
process_id_(Process, Pid) :-
|
||||||
|
valid_process(Process),
|
||||||
|
must_be(var, Pid),
|
||||||
|
'$process_id'(Process, Pid).
|
||||||
|
|
||||||
|
%% process_wait(+Process, Status).
|
||||||
|
%
|
||||||
|
% See `process_create/3` with `Options = []`
|
||||||
|
%
|
||||||
|
process_wait(Process, Status) :- call_with_error_context(process_wait(Process, Status, []), predicate-process_wait/2).
|
||||||
|
|
||||||
|
|
||||||
|
%% process_wait(+Process, Status, Options).
|
||||||
|
%
|
||||||
|
% Wait for the process behind the process handle `Process` to exit.
|
||||||
|
%
|
||||||
|
% When the process exits regulary `Status` will be unified with `exit(Exit)` where `Exit` is the processes exit code.
|
||||||
|
% When the process exits was killed `Status` will be unified with `killed(Signal)` where `Signal` is the signal number that killed the process.
|
||||||
|
% When the process doesn't exit before the timeout `Status` will be unified with `timeout`.
|
||||||
|
%
|
||||||
|
% `Options` is a a list of the following options
|
||||||
|
%
|
||||||
|
% * timeout(Timeout) supported values for `Timeout` are 0 or `infinite`
|
||||||
|
%
|
||||||
|
% Each options may be specified at most once, when an option is not specified the following defaults apply:
|
||||||
|
%
|
||||||
|
% - timeout(infinite)
|
||||||
|
%
|
||||||
|
process_wait(Process, Status, Options) :- call_with_error_context(process_wait_(Process, Status, Options), predicate-process_wait/3).
|
||||||
|
|
||||||
|
process_wait_(Process, Status, Options) :-
|
||||||
|
valid_process(Process),
|
||||||
|
check_options(
|
||||||
|
[
|
||||||
|
option([timeout], valid_timeout, timeout(infinite), timeout(Timeout))
|
||||||
|
],
|
||||||
|
Options,
|
||||||
|
process_wait_option
|
||||||
|
),
|
||||||
|
'$process_wait'(Process, Exit, Timeout),
|
||||||
|
Exit = Status.
|
||||||
|
|
||||||
|
valid_timeout(timeout(infinite)).
|
||||||
|
valid_timeout(timeout(0)).
|
||||||
|
|
||||||
|
|
||||||
|
%% process_kill(+Process).
|
||||||
|
%
|
||||||
|
% Kill the process using the process handle `Process`.
|
||||||
|
% On Unix this sends SIGKILL.
|
||||||
|
%
|
||||||
|
% Only works for processes spawned with `process_create/3` that have not yet been release with `process_release/1`
|
||||||
|
%
|
||||||
|
process_kill(Process) :- call_with_error_context(process_kill_(Process), predicate-process_kill/1).
|
||||||
|
|
||||||
|
process_kill_(Process) :-
|
||||||
|
valid_process(Process),
|
||||||
|
'$process_kill'(Process).
|
||||||
|
|
||||||
|
%% process_release(+Process)
|
||||||
|
%
|
||||||
|
% wait for the process to exit (if not already) and release process handle `Process`
|
||||||
|
%
|
||||||
|
% It's an error if `Process` is not a valid process handle
|
||||||
|
%
|
||||||
|
process_release(Process) :- call_with_error_context(process_release_(Process), predicate-process_release/1).
|
||||||
|
|
||||||
|
process_release_(Process) :-
|
||||||
|
valid_process(Process),
|
||||||
|
process_wait(Process, _),
|
||||||
|
'$process_release'(Process).
|
||||||
|
|
||||||
|
|
||||||
|
must_be_known_options(Valid, Options, Domain) :- call_with_error_context(must_be_known_options_(Valid, [], Options, Domain),predicate-must_be_known_options/3).
|
||||||
|
|
||||||
|
must_be_known_options_(_, _, [], _).
|
||||||
|
must_be_known_options_(Valid, Found, [X|XS], Domain) :-
|
||||||
|
( functor(X, Option, 1) -> true
|
||||||
|
; domain_error(Domain, X, [])
|
||||||
|
) ,
|
||||||
|
( member(Option, Found) -> domain_error(non_duplicate_options, Option , [])
|
||||||
|
; member(Option, Valid) -> true
|
||||||
|
; domain_error(Domain, Option, [])
|
||||||
|
),
|
||||||
|
must_be_known_options_(Valid, [Option | Found], XS, Domain).
|
||||||
|
|
||||||
|
check_options(KnownOptions, Options, Domain) :- call_with_error_context(check_options_(KnownOptions, Options, Domain), predicate-check_options/3).
|
||||||
|
|
||||||
|
check_options_(KnownOptions, Options, Domain) :-
|
||||||
|
maplist(option_names, KnownOptions, Namess),
|
||||||
|
append(Namess, Names),
|
||||||
|
must_be_known_options(Names, Options, Domain),
|
||||||
|
extract_options(KnownOptions, Options).
|
||||||
|
|
||||||
|
option_names(option(Names,_,_,_), Names).
|
||||||
|
|
||||||
|
extract_options(KnownOptions, Options) :- call_with_error_context(extract_options_(KnownOptions, Options), predicate-extract_options/2).
|
||||||
|
|
||||||
|
extract_options_([], _).
|
||||||
|
extract_options_([X | XS], Options) :-
|
||||||
|
option(Kinds, Pred, Default, Choice) = X,
|
||||||
|
tfilter(find_option(Kinds), Options, Solutions),
|
||||||
|
( Solutions = [] -> Choice = Default
|
||||||
|
; Solutions = [Provided] -> functor(Pred, Name, Arity), ArityP1 is Arity+1, call_with_error_context(call(Pred, Provided),predicate-Name/ArityP1), Choice = Provided
|
||||||
|
; domain_error(non_conflicting_options, Solutions, [])
|
||||||
|
),
|
||||||
|
extract_options_(XS, Options).
|
||||||
|
|
||||||
|
find_option(Names, Found, T) :-
|
||||||
|
functor(Found, Name, 1),
|
||||||
|
memberd_t(Name, Names, T).
|
||||||
|
|
||||||
|
valid_stdio(IO) :- arg(1, IO, Arg),
|
||||||
|
( var(Arg) -> instantiation_error([])
|
||||||
|
; valid_stdio_(Arg) -> true
|
||||||
|
; domain_error(stdio_spec, Arg, [])
|
||||||
|
).
|
||||||
|
|
||||||
|
valid_stdio_(std).
|
||||||
|
valid_stdio_(null).
|
||||||
|
valid_stdio_(pipe(Stream)) :- must_be(var, Stream).
|
||||||
|
valid_stdio_(file(Path)) :- must_be(chars, Path).
|
||||||
|
|
||||||
|
valid_env(env(E)) :-
|
||||||
|
must_be(list, E),
|
||||||
|
( valid_env_(E) -> true
|
||||||
|
; domain_error(process_create_option, env(E), [])
|
||||||
|
).
|
||||||
|
valid_env(environment(E)) :-
|
||||||
|
must_be(list, E),
|
||||||
|
( valid_env_(E) -> true
|
||||||
|
; domain_error(process_create_option, environment(E), [])
|
||||||
|
).
|
||||||
|
|
||||||
|
valid_env_([]).
|
||||||
|
valid_env_([N=V|ES]) :-
|
||||||
|
must_be(chars, N),
|
||||||
|
must_be(chars, V),
|
||||||
|
valid_env_(ES).
|
||||||
|
|
||||||
|
valid_uninit_process(process(Process)) :- must_be(var, Process).
|
||||||
|
|
||||||
|
valid_process(Process) :- var(Process) -> instantiation_error([]) ; true.
|
||||||
|
|
||||||
|
valid_cwd(cwd(Cwd)) :- must_be(chars, Cwd).
|
||||||
|
|
||||||
|
simplify_env(E, [Kind, Envs1]) :- E =.. [Kind, Envs], simplify_env_(Envs, Envs1).
|
||||||
|
|
||||||
|
simplify_env_([],[]).
|
||||||
|
simplify_env_([N=V|E],[[N, V]|E1]) :- simplify_env_(E, E1).
|
||||||
@@ -96,14 +96,14 @@ is_sgml_source([]).
|
|||||||
is_sgml_source([C|Cs]) :- must_be(chars, [C|Cs]).
|
is_sgml_source([C|Cs]) :- must_be(chars, [C|Cs]).
|
||||||
|
|
||||||
load_structure_([], [], _, _).
|
load_structure_([], [], _, _).
|
||||||
load_structure_([C|Cs], [E], Options, What) :-
|
load_structure_([C|Cs], [E|Es], Options, What) :-
|
||||||
load_(What, [C|Cs], E, Options).
|
load_(What, [C|Cs], [E|Es], Options).
|
||||||
load_structure_(file(Fs), [E], Options, What) :-
|
load_structure_(file(Fs), [E|Es], Options, What) :-
|
||||||
once(phrase_from_file(seq(Cs), Fs)),
|
once(phrase_from_file(seq(Cs), Fs)),
|
||||||
load_(What, Cs, E, Options).
|
load_(What, Cs, [E|Es], Options).
|
||||||
load_structure_(stream(Stream), [E], Options, What) :-
|
load_structure_(stream(Stream), [E|Es], Options, What) :-
|
||||||
get_n_chars(Stream, _, Cs),
|
get_n_chars(Stream, _, Cs),
|
||||||
load_(What, Cs, E, Options).
|
load_(What, Cs, [E|Es], Options).
|
||||||
|
|
||||||
load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options).
|
load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options).
|
||||||
load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options).
|
load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options).
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ expand_term_goals(Terms0, Terms) :-
|
|||||||
( atom(Module) ->
|
( atom(Module) ->
|
||||||
prolog_load_context(module, Target),
|
prolog_load_context(module, Target),
|
||||||
module_expanded_head_variables(Head2, HeadVars),
|
module_expanded_head_variables(Head2, HeadVars),
|
||||||
catch(expand_goal(Body0, Target, Body1, HeadVars, []),
|
catch('$call'(loader:expand_goal(Body0, Target, Body1, HeadVars, [])),
|
||||||
error(type_error(callable, Pred), _),
|
error(type_error(callable, Pred), _),
|
||||||
( loader:print_goal_expansion_warning(Pred),
|
( loader:print_goal_expansion_warning(Pred),
|
||||||
builtins:(Body1 = Body0)
|
builtins:(Body1 = Body0)
|
||||||
@@ -309,7 +309,7 @@ expand_term_goals(Terms0, Terms) :-
|
|||||||
)
|
)
|
||||||
; module_expanded_head_variables(Head1, HeadVars),
|
; module_expanded_head_variables(Head1, HeadVars),
|
||||||
prolog_load_context(module, Target),
|
prolog_load_context(module, Target),
|
||||||
catch(expand_goal(Body0, Target, Body1, HeadVars, []),
|
catch('$call'(loader:expand_goal(Body0, Target, Body1, HeadVars, [])),
|
||||||
error(type_error(callable, Pred), _),
|
error(type_error(callable, Pred), _),
|
||||||
( loader:print_goal_expansion_warning(Pred),
|
( loader:print_goal_expansion_warning(Pred),
|
||||||
builtins:(Body1 = Body0)
|
builtins:(Body1 = Body0)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use crate::forms::*;
|
|||||||
use crate::heap_iter::*;
|
use crate::heap_iter::*;
|
||||||
use crate::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::machine::machine_state::*;
|
use crate::machine::machine_state::*;
|
||||||
|
use crate::offset_table::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::dashu::{Integer, Rational};
|
use crate::parser::dashu::{Integer, Rational};
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
@@ -48,7 +49,7 @@ macro_rules! drop_iter_on_err {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zero_divisor_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> MachineStubGen {
|
fn zero_divisor_eval_error(stub_gen: impl Fn() -> MachineStub + 'static) -> MachineStubGen {
|
||||||
Box::new(move |machine_st| {
|
Box::new(move |machine_st| {
|
||||||
let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor);
|
let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor);
|
||||||
let stub = stub_gen();
|
let stub = stub_gen();
|
||||||
@@ -57,7 +58,7 @@ fn zero_divisor_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> Mach
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn undefined_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> MachineStubGen {
|
fn undefined_eval_error(stub_gen: impl Fn() -> MachineStub + 'static) -> MachineStubGen {
|
||||||
Box::new(move |machine_st| {
|
Box::new(move |machine_st| {
|
||||||
let eval_error = machine_st.evaluation_error(EvalError::Undefined);
|
let eval_error = machine_st.evaluation_error(EvalError::Undefined);
|
||||||
let stub = stub_gen();
|
let stub = stub_gen();
|
||||||
@@ -69,7 +70,7 @@ fn undefined_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> Machine
|
|||||||
fn numerical_type_error(
|
fn numerical_type_error(
|
||||||
valid_type: ValidType,
|
valid_type: ValidType,
|
||||||
n: Number,
|
n: Number,
|
||||||
stub_gen: impl Fn() -> FunctorStub + 'static,
|
stub_gen: impl Fn() -> MachineStub + 'static,
|
||||||
) -> MachineStubGen {
|
) -> MachineStubGen {
|
||||||
Box::new(move |machine_st| {
|
Box::new(move |machine_st| {
|
||||||
let type_error = machine_st.type_error(valid_type, n);
|
let type_error = machine_st.type_error(valid_type, n);
|
||||||
@@ -197,11 +198,10 @@ pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number {
|
|||||||
pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number {
|
pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number {
|
||||||
match n {
|
match n {
|
||||||
Number::Fixnum(n) => {
|
Number::Fixnum(n) => {
|
||||||
if let Some(n) = n.get_num().checked_abs() {
|
if let Some(n) = n.checked_abs() {
|
||||||
fixnum!(Number, n, arena)
|
Number::Fixnum(n)
|
||||||
} else {
|
} else {
|
||||||
let arena_int = Integer::from(n.get_num());
|
Number::arena_from(Integer::from(Fixnum::MAX + 1), arena)
|
||||||
Number::arena_from(arena_int.abs(), arena)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Number::Integer(n) => {
|
Number::Integer(n) => {
|
||||||
@@ -528,7 +528,7 @@ pub(crate) fn min(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
|
|||||||
|
|
||||||
pub fn rational_from_number(
|
pub fn rational_from_number(
|
||||||
n: Number,
|
n: Number,
|
||||||
stub_gen: impl Fn() -> FunctorStub + 'static,
|
stub_gen: impl Fn() -> MachineStub + 'static,
|
||||||
arena: &mut Arena,
|
arena: &mut Arena,
|
||||||
) -> Result<TypedArenaPtr<Rational>, MachineStubGen> {
|
) -> Result<TypedArenaPtr<Rational>, MachineStubGen> {
|
||||||
match n {
|
match n {
|
||||||
@@ -1104,7 +1104,7 @@ pub(crate) fn round(num: Number, arena: &mut Arena) -> Result<Number, MachineStu
|
|||||||
|
|
||||||
pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
|
pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
|
||||||
match n1 {
|
match n1 {
|
||||||
Number::Fixnum(n) => Ok(Number::Fixnum(Fixnum::build_with(!n.get_num()))),
|
Number::Fixnum(n) => Ok(Number::Fixnum(!n)),
|
||||||
Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)),
|
Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)),
|
||||||
_ => {
|
_ => {
|
||||||
let stub_gen = || {
|
let stub_gen = || {
|
||||||
@@ -1124,9 +1124,12 @@ impl MachineState {
|
|||||||
&ArithmeticTerm::Reg(r) => {
|
&ArithmeticTerm::Reg(r) => {
|
||||||
let value = self.store(self.deref(self[r]));
|
let value = self.store(self.deref(self[r]));
|
||||||
|
|
||||||
match Number::try_from(value) {
|
match Number::try_from((value, &self.arena.f64_tbl)) {
|
||||||
Ok(n) => Ok(n),
|
Ok(n) => Ok(n),
|
||||||
Err(_) => self.arith_eval_by_metacall(value),
|
Err(_) => {
|
||||||
|
self.heap[0] = value;
|
||||||
|
self.arith_eval_by_metacall(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&ArithmeticTerm::Interm(i) => Ok(mem::replace(
|
&ArithmeticTerm::Interm(i) => Ok(mem::replace(
|
||||||
@@ -1140,7 +1143,7 @@ impl MachineState {
|
|||||||
pub fn get_rational(
|
pub fn get_rational(
|
||||||
&mut self,
|
&mut self,
|
||||||
at: &ArithmeticTerm,
|
at: &ArithmeticTerm,
|
||||||
caller: impl Fn() -> FunctorStub + 'static,
|
caller: impl Fn() -> MachineStub + 'static,
|
||||||
) -> Result<TypedArenaPtr<Rational>, MachineStub> {
|
) -> Result<TypedArenaPtr<Rational>, MachineStub> {
|
||||||
let n = self.get_number(at)?;
|
let n = self.get_number(at)?;
|
||||||
|
|
||||||
@@ -1152,11 +1155,11 @@ impl MachineState {
|
|||||||
|
|
||||||
pub(crate) fn arith_eval_by_metacall(
|
pub(crate) fn arith_eval_by_metacall(
|
||||||
&mut self,
|
&mut self,
|
||||||
value: HeapCellValue,
|
term_loc: usize,
|
||||||
) -> Result<Number, MachineStub> {
|
) -> Result<Number, MachineStub> {
|
||||||
let stub_gen = || functor_stub(atom!("is"), 2);
|
let stub_gen = || functor_stub(atom!("is"), 2);
|
||||||
let mut iter =
|
let mut iter =
|
||||||
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, value);
|
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term_loc);
|
||||||
|
|
||||||
while let Some(value) = iter.next() {
|
while let Some(value) = iter.next() {
|
||||||
if value.get_forwarding_bit() {
|
if value.get_forwarding_bit() {
|
||||||
@@ -1169,7 +1172,7 @@ impl MachineState {
|
|||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
cell_as_atom_cell!(self.heap[s]).get_name_and_arity()
|
cell_as_atom_cell!(self.heap[s]).get_name_and_arity()
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Lis | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset |
|
(HeapCellValueTag::Lis | // HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset |
|
||||||
HeapCellValueTag::PStrLoc) => {
|
HeapCellValueTag::PStrLoc) => {
|
||||||
(atom!("."), 2)
|
(atom!("."), 2)
|
||||||
}
|
}
|
||||||
@@ -1385,8 +1388,9 @@ impl MachineState {
|
|||||||
(HeapCellValueTag::Fixnum, n) => {
|
(HeapCellValueTag::Fixnum, n) => {
|
||||||
self.interms.push(Number::Fixnum(n));
|
self.interms.push(Number::Fixnum(n));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::F64, fl) => {
|
(HeapCellValueTag::F64Offset, offset) => {
|
||||||
self.interms.push(Number::Float(*fl));
|
let fl = self.arena.f64_tbl.get_entry(offset);
|
||||||
|
self.interms.push(Number::Float(fl));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Cons, ptr) => {
|
(HeapCellValueTag::Cons, ptr) => {
|
||||||
match_untyped_arena_ptr!(ptr,
|
match_untyped_arena_ptr!(ptr,
|
||||||
@@ -1449,7 +1453,7 @@ mod tests {
|
|||||||
parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap();
|
parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
|
wam.arith_eval_by_metacall(term_write_result.heap_loc),
|
||||||
Ok(Number::Fixnum(Fixnum::build_with(8))),
|
Ok(Number::Fixnum(Fixnum::build_with(8))),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1459,7 +1463,7 @@ mod tests {
|
|||||||
parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap();
|
parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
|
wam.arith_eval_by_metacall(term_write_result.heap_loc),
|
||||||
Ok(Number::Fixnum(Fixnum::build_with(19))),
|
Ok(Number::Fixnum(Fixnum::build_with(19))),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1469,7 +1473,7 @@ mod tests {
|
|||||||
parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap();
|
parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
|
wam.arith_eval_by_metacall(term_write_result.heap_loc),
|
||||||
Ok(Number::Fixnum(Fixnum::build_with(-1)))
|
Ok(Number::Fixnum(Fixnum::build_with(-1)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use crate::types::*;
|
|||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::vec::IntoIter;
|
|
||||||
|
|
||||||
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
|
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
|
||||||
|
|
||||||
@@ -55,32 +54,36 @@ impl MachineState {
|
|||||||
self.attr_var_init.bindings.push((h, addr));
|
self.attr_var_init.bindings.push((h, addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) {
|
fn populate_var_and_value_lists(&mut self) -> Result<(HeapCellValue, HeapCellValue), usize> {
|
||||||
|
let size = self.attr_var_init.bindings.len();
|
||||||
|
|
||||||
let iter = self
|
let iter = self
|
||||||
.attr_var_init
|
.attr_var_init
|
||||||
.bindings
|
.bindings
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(ref h, _)| attr_var_as_cell!(*h));
|
.map(|(ref h, _)| attr_var_as_cell!(*h));
|
||||||
|
|
||||||
let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
|
let var_list_addr = sized_iter_to_heap_list(&mut self.heap, size, iter)?;
|
||||||
let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
|
let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
|
||||||
let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
|
let value_list_addr = sized_iter_to_heap_list(&mut self.heap, size, iter)?;
|
||||||
|
|
||||||
(var_list_addr, value_list_addr)
|
Ok((var_list_addr, value_list_addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_attributes(&mut self) {
|
fn verify_attributes(&mut self) -> Result<(), usize> {
|
||||||
for (h, _) in &self.attr_var_init.bindings {
|
for (h, _) in &self.attr_var_init.bindings {
|
||||||
self.heap[*h] = attr_var_as_cell!(*h);
|
self.heap[*h] = attr_var_as_cell!(*h);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists();
|
let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists()?;
|
||||||
|
|
||||||
self[temp_v!(1)] = var_list_addr;
|
self[temp_v!(1)] = var_list_addr;
|
||||||
self[temp_v!(2)] = value_list_addr;
|
self[temp_v!(2)] = value_list_addr;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter<HeapCellValue> {
|
pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> Vec<HeapCellValue> {
|
||||||
let mut attr_vars: Vec<_> = if b >= self.attr_var_init.attr_var_queue.len() {
|
let mut attr_vars: Vec<_> = if b >= self.attr_var_init.attr_var_queue.len() {
|
||||||
vec![]
|
vec![]
|
||||||
} else {
|
} else {
|
||||||
@@ -104,10 +107,10 @@ impl MachineState {
|
|||||||
});
|
});
|
||||||
|
|
||||||
attr_vars.dedup();
|
attr_vars.dedup();
|
||||||
attr_vars.into_iter()
|
attr_vars
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) {
|
pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) -> Result<(), usize> {
|
||||||
self.allocate(arity + 3);
|
self.allocate(arity + 3);
|
||||||
|
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
@@ -117,23 +120,40 @@ impl MachineState {
|
|||||||
and_frame[i] = self.registers[i];
|
and_frame[i] = self.registers[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
and_frame[arity + 1] = fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
|
and_frame[arity + 1] =
|
||||||
and_frame[arity + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
|
fixnum_as_cell!(
|
||||||
and_frame[arity + 3] = fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
|
/* FIXME this is not safe */
|
||||||
|
unsafe { Fixnum::build_with_unchecked(self.b0 as i64) }
|
||||||
|
);
|
||||||
|
and_frame[arity + 2] =
|
||||||
|
fixnum_as_cell!(
|
||||||
|
/* FIXME this is not safe */
|
||||||
|
unsafe { Fixnum::build_with_unchecked(self.num_of_args as i64) }
|
||||||
|
);
|
||||||
|
and_frame[arity + 3] =
|
||||||
|
fixnum_as_cell!(
|
||||||
|
/* FIXME this is not safe */
|
||||||
|
unsafe { Fixnum::build_with_unchecked(self.attr_var_init.cp as i64) }
|
||||||
|
);
|
||||||
|
|
||||||
self.verify_attributes();
|
self.verify_attributes()?;
|
||||||
|
|
||||||
self.num_of_args = 3;
|
self.num_of_args = 3;
|
||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
self.p = p;
|
self.p = p;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
|
pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
|
||||||
|
debug_assert!(cell.is_ref());
|
||||||
|
|
||||||
let mut seen_set = IndexSet::new();
|
let mut seen_set = IndexSet::new();
|
||||||
let mut seen_vars = vec![];
|
let mut seen_vars = vec![];
|
||||||
|
|
||||||
let mut iter =
|
self.heap[0] = cell;
|
||||||
stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, cell);
|
|
||||||
|
let mut iter = stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
|
||||||
|
|
||||||
while let Some(value) = iter.next() {
|
while let Some(value) = iter.next() {
|
||||||
read_heap_cell!(value,
|
read_heap_cell!(value,
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ fn merge_indices(
|
|||||||
);
|
);
|
||||||
|
|
||||||
retraction_info.push_record(RetractionRecord::AddedIndex(
|
retraction_info.push_record(RetractionRecord::AddedIndex(
|
||||||
skeleton[clause_index].opt_arg_index_key.clone(),
|
skeleton[clause_index].opt_arg_index_key,
|
||||||
clause_loc,
|
clause_loc,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
@@ -246,7 +246,7 @@ fn remove_index_from_subsequence(
|
|||||||
// appear anywhere inside an Internal record.
|
// appear anywhere inside an Internal record.
|
||||||
retraction_info.push_record(RetractionRecord::RemovedIndex(
|
retraction_info.push_record(RetractionRecord::RemovedIndex(
|
||||||
index_loc,
|
index_loc,
|
||||||
opt_arg_index_key.clone(),
|
*opt_arg_index_key,
|
||||||
offset,
|
offset,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -700,31 +700,25 @@ fn remove_non_leading_clause(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalize_retract(
|
fn finalize_retract<'a, LS: LoadState<'a>>(
|
||||||
|
payload: &mut <LS as LoadState<'a>>::LoaderFieldType,
|
||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
compilation_target: CompilationTarget,
|
compilation_target: CompilationTarget,
|
||||||
skeleton: &mut PredicateSkeleton,
|
skeleton: &mut PredicateSkeleton,
|
||||||
code_index: CodeIndex,
|
code_index: CodeIndex,
|
||||||
target_pos: usize,
|
target_pos: usize,
|
||||||
index_ptr_opt: Option<IndexPtr>,
|
index_ptr_opt: Option<IndexPtr>,
|
||||||
retraction_info: &mut RetractionInfo,
|
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let clause_clause_loc = delete_from_skeleton(
|
let clause_clause_loc = delete_from_skeleton(
|
||||||
compilation_target,
|
compilation_target,
|
||||||
key,
|
key,
|
||||||
skeleton,
|
skeleton,
|
||||||
target_pos,
|
target_pos,
|
||||||
retraction_info,
|
&mut payload.retraction_info,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(index_ptr) = index_ptr_opt {
|
if let Some(index_ptr) = index_ptr_opt {
|
||||||
set_code_index(
|
set_code_index::<LS>(payload, &compilation_target, key, code_index, index_ptr);
|
||||||
retraction_info,
|
|
||||||
&compilation_target,
|
|
||||||
key,
|
|
||||||
code_index,
|
|
||||||
index_ptr,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clause_clause_loc
|
clause_clause_loc
|
||||||
@@ -814,7 +808,7 @@ fn prepend_compiled_clause(
|
|||||||
skeleton.clauses[0].clause_start = clause_loc + 2;
|
skeleton.clauses[0].clause_start = clause_loc + 2;
|
||||||
|
|
||||||
retraction_info.push_record(RetractionRecord::AddedIndex(
|
retraction_info.push_record(RetractionRecord::AddedIndex(
|
||||||
skeleton.clauses[0].opt_arg_index_key.clone(),
|
skeleton.clauses[0].opt_arg_index_key,
|
||||||
skeleton.clauses[0].clause_start,
|
skeleton.clauses[0].clause_start,
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -1076,7 +1070,7 @@ fn append_compiled_clause(
|
|||||||
skeleton.clauses[target_pos].opt_arg_index_key += index_loc - 1;
|
skeleton.clauses[target_pos].opt_arg_index_key += index_loc - 1;
|
||||||
|
|
||||||
retraction_info.push_record(RetractionRecord::AddedIndex(
|
retraction_info.push_record(RetractionRecord::AddedIndex(
|
||||||
skeleton.clauses[target_pos].opt_arg_index_key.clone(),
|
skeleton.clauses[target_pos].opt_arg_index_key,
|
||||||
skeleton.clauses[target_pos].clause_start,
|
skeleton.clauses[target_pos].clause_start,
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -1237,12 +1231,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
settings: CodeGenSettings,
|
settings: CodeGenSettings,
|
||||||
) -> Result<StandaloneCompileResult, SessionError> {
|
) -> Result<StandaloneCompileResult, SessionError> {
|
||||||
let mut preprocessor = Preprocessor::new(settings);
|
let mut preprocessor = Preprocessor::new(settings);
|
||||||
|
let clause = preprocessor.try_term_to_tl(self, term)?;
|
||||||
|
|
||||||
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
|
let f64_tbl = &LS::machine_st(&mut self.payload).arena.f64_tbl;
|
||||||
// let queue = preprocessor.parse_queue(self)?;
|
|
||||||
|
|
||||||
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
|
|
||||||
|
|
||||||
|
let mut cg = CodeGenerator::new(f64_tbl, settings);
|
||||||
let clause_code = cg.compile_predicate(vec![clause])?;
|
let clause_code = cg.compile_predicate(vec![clause])?;
|
||||||
|
|
||||||
Ok(StandaloneCompileResult {
|
Ok(StandaloneCompileResult {
|
||||||
@@ -1257,7 +1250,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
mut predicates: PredicateQueue,
|
mut predicates: PredicateQueue,
|
||||||
settings: CodeGenSettings,
|
settings: CodeGenSettings,
|
||||||
) -> Result<CodeIndex, SessionError> {
|
) -> Result<CodeIndex, SessionError> {
|
||||||
let code_index = self.get_or_insert_code_index(key, predicates.compilation_target);
|
let code_idx = self.get_or_insert_code_index(key, predicates.compilation_target);
|
||||||
|
|
||||||
LS::err_on_builtin_overwrite(self, key)?;
|
LS::err_on_builtin_overwrite(self, key)?;
|
||||||
|
|
||||||
@@ -1268,11 +1261,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
let mut preprocessor = Preprocessor::new(settings);
|
let mut preprocessor = Preprocessor::new(settings);
|
||||||
|
|
||||||
for term in predicates.predicates.drain(0..) {
|
for term in predicates.predicates.drain(0..) {
|
||||||
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
|
clauses.push(preprocessor.try_term_to_tl(self, term)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
|
let f64_tbl = &LS::machine_st(&mut self.payload).arena.f64_tbl;
|
||||||
|
|
||||||
|
let mut cg = CodeGenerator::new(f64_tbl, settings);
|
||||||
let mut code = cg.compile_predicate(clauses)?;
|
let mut code = cg.compile_predicate(clauses)?;
|
||||||
|
|
||||||
if settings.is_extensible {
|
if settings.is_extensible {
|
||||||
@@ -1331,9 +1325,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let index_ptr = LS::machine_st(&mut self.payload)
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(code_idx.into());
|
||||||
|
|
||||||
print_overwrite_warning(
|
print_overwrite_warning(
|
||||||
&predicates.compilation_target,
|
&predicates.compilation_target,
|
||||||
code_index.get(),
|
index_ptr,
|
||||||
key,
|
key,
|
||||||
settings.is_dynamic(),
|
settings.is_dynamic(),
|
||||||
);
|
);
|
||||||
@@ -1344,16 +1343,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
IndexPtr::index(code_ptr)
|
IndexPtr::index(code_ptr)
|
||||||
};
|
};
|
||||||
|
|
||||||
set_code_index(
|
set_code_index::<LS>(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload,
|
||||||
&predicates.compilation_target,
|
&predicates.compilation_target,
|
||||||
key,
|
key,
|
||||||
code_index,
|
code_idx,
|
||||||
index_ptr,
|
index_ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.wam_prelude.code.extend(code);
|
self.wam_prelude.code.extend(code);
|
||||||
Ok(code_index)
|
Ok(code_idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extend_local_predicate_skeleton(
|
fn extend_local_predicate_skeleton(
|
||||||
@@ -1555,19 +1554,19 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
self.push_back_to_local_predicate_skeleton(&compilation_target, &key, code_len);
|
self.push_back_to_local_predicate_skeleton(&compilation_target, &key, code_len);
|
||||||
|
|
||||||
let code_index = self.get_or_insert_code_index(key, compilation_target);
|
let code_idx = self.get_or_insert_code_index(key, compilation_target);
|
||||||
|
|
||||||
if let Some(new_code_ptr) = result {
|
if let Some(new_code_ptr) = result {
|
||||||
set_code_index(
|
set_code_index::<LS>(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload,
|
||||||
&compilation_target,
|
&compilation_target,
|
||||||
key,
|
key,
|
||||||
code_index,
|
code_idx,
|
||||||
new_code_ptr,
|
new_code_ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(code_index)
|
Ok(code_idx)
|
||||||
}
|
}
|
||||||
AppendOrPrepend::Prepend => {
|
AppendOrPrepend::Prepend => {
|
||||||
let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap();
|
let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap();
|
||||||
@@ -1597,17 +1596,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
self.push_front_to_local_predicate_skeleton(&compilation_target, &key, code_len);
|
self.push_front_to_local_predicate_skeleton(&compilation_target, &key, code_len);
|
||||||
|
|
||||||
let code_index = self.get_or_insert_code_index(key, compilation_target);
|
let code_idx = self.get_or_insert_code_index(key, compilation_target);
|
||||||
|
|
||||||
set_code_index(
|
set_code_index::<LS>(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload,
|
||||||
&compilation_target,
|
&compilation_target,
|
||||||
key,
|
key,
|
||||||
code_index,
|
code_idx,
|
||||||
new_code_ptr,
|
new_code_ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(code_index)
|
Ok(code_idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1655,7 +1654,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize {
|
pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize {
|
||||||
let payload_compilation_target = self.payload.compilation_target;
|
let payload_compilation_target = self.payload.compilation_target;
|
||||||
let code_index = self.get_or_insert_code_index(key, payload_compilation_target);
|
let code_idx_offset = self.get_or_insert_code_index(key, payload_compilation_target);
|
||||||
|
|
||||||
let skeleton = self
|
let skeleton = self
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
@@ -1733,14 +1732,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
return finalize_retract(
|
return finalize_retract::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
key,
|
key,
|
||||||
payload_compilation_target,
|
payload_compilation_target,
|
||||||
skeleton,
|
skeleton,
|
||||||
code_index,
|
code_idx_offset,
|
||||||
target_pos,
|
target_pos,
|
||||||
index_ptr_opt,
|
index_ptr_opt,
|
||||||
&mut self.payload.retraction_info,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@@ -1762,14 +1761,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
return finalize_retract(
|
return finalize_retract::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
key,
|
key,
|
||||||
payload_compilation_target,
|
payload_compilation_target,
|
||||||
skeleton,
|
skeleton,
|
||||||
code_index,
|
code_idx_offset,
|
||||||
target_pos,
|
target_pos,
|
||||||
index_ptr_opt,
|
index_ptr_opt,
|
||||||
&mut self.payload.retraction_info,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1992,14 +1991,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
finalize_retract(
|
finalize_retract::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
key,
|
key,
|
||||||
payload_compilation_target,
|
payload_compilation_target,
|
||||||
skeleton,
|
skeleton,
|
||||||
code_index,
|
code_idx_offset,
|
||||||
target_pos,
|
target_pos,
|
||||||
index_ptr_opt,
|
index_ptr_opt,
|
||||||
&mut self.payload.retraction_info,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2226,18 +2225,22 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let predicates = self.payload.predicates.take();
|
let predicates = self.payload.predicates.take();
|
||||||
let code_index = self.compile(key, predicates, settings)?;
|
let offset = self.compile(key, predicates, settings)?;
|
||||||
|
|
||||||
if let Some(filename) = self.listing_src_file_name() {
|
if let Some(filename) = self.listing_src_file_name() {
|
||||||
if let Some(ref mut module) = self.wam_prelude.indices.modules.get_mut(&filename) {
|
if let Some(ref mut module) = self.wam_prelude.indices.modules.get_mut(&filename) {
|
||||||
let index_ptr = code_index.get();
|
let index_ptr = LS::machine_st(&mut self.payload)
|
||||||
let code_index = *module.code_dir.entry(key).or_insert(code_index);
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(offset.into());
|
||||||
|
|
||||||
set_code_index(
|
let offset = *module.code_dir.entry(key).or_insert(offset);
|
||||||
&mut self.payload.retraction_info,
|
|
||||||
|
set_code_index::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
&CompilationTarget::Module(filename),
|
&CompilationTarget::Module(filename),
|
||||||
key,
|
key,
|
||||||
code_index,
|
offset,
|
||||||
index_ptr,
|
index_ptr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,71 @@
|
|||||||
|
use fxhash::FxBuildHasher;
|
||||||
|
use indexmap::IndexSet;
|
||||||
|
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::machine::get_structure_index;
|
use crate::machine::get_structure_index;
|
||||||
|
use crate::machine::heap::*;
|
||||||
use crate::machine::stack::*;
|
use crate::machine::stack::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use std::mem;
|
use scryer_modular_bitfield::specifiers::*;
|
||||||
use std::ops::IndexMut;
|
use scryer_modular_bitfield::*;
|
||||||
|
|
||||||
type Trail = Vec<(Ref, HeapCellValue)>;
|
use std::collections::BTreeMap;
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::{IndexMut, Range};
|
||||||
|
|
||||||
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
|
||||||
|
#[bits = 6]
|
||||||
|
enum TrailRefTag {
|
||||||
|
HeapCell = 0b001011,
|
||||||
|
StackCell = 0b001101,
|
||||||
|
AttrVar = 0b010001,
|
||||||
|
PStrLoc = 0b001111,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
|
struct TrailRef {
|
||||||
|
val: B56,
|
||||||
|
#[allow(unused)]
|
||||||
|
m: bool,
|
||||||
|
#[allow(unused)]
|
||||||
|
f: bool,
|
||||||
|
tag: TrailRefTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrailRef {
|
||||||
|
#[inline(always)]
|
||||||
|
fn heap_cell(h: usize) -> Self {
|
||||||
|
TrailRef::new()
|
||||||
|
.with_tag(TrailRefTag::HeapCell)
|
||||||
|
.with_val(h as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn stack_cell(h: usize) -> Self {
|
||||||
|
TrailRef::new()
|
||||||
|
.with_tag(TrailRefTag::StackCell)
|
||||||
|
.with_val(h as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn attr_var(h: usize) -> Self {
|
||||||
|
TrailRef::new()
|
||||||
|
.with_tag(TrailRefTag::AttrVar)
|
||||||
|
.with_val(h as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn pstr_loc(h: usize) -> Self {
|
||||||
|
TrailRef::new()
|
||||||
|
.with_tag(TrailRefTag::PStrLoc)
|
||||||
|
.with_val(h as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Trail = Vec<(TrailRef, HeapCellValue)>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum AttrVarPolicy {
|
pub enum AttrVarPolicy {
|
||||||
@@ -17,22 +76,39 @@ pub enum AttrVarPolicy {
|
|||||||
pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
||||||
fn store(&self, value: HeapCellValue) -> HeapCellValue;
|
fn store(&self, value: HeapCellValue) -> HeapCellValue;
|
||||||
fn deref(&self, value: HeapCellValue) -> HeapCellValue;
|
fn deref(&self, value: HeapCellValue) -> HeapCellValue;
|
||||||
fn push(&mut self, value: HeapCellValue);
|
|
||||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize);
|
fn push_attr_var_queue(&mut self, attr_var_loc: usize);
|
||||||
fn stack(&mut self) -> &mut Stack;
|
fn stack(&mut self) -> &mut Stack;
|
||||||
fn threshold(&self) -> usize;
|
fn threshold(&self) -> usize;
|
||||||
|
// returns the tail location of the pstr on success
|
||||||
|
fn as_slice_from<'a>(&'a self, from: usize) -> Box<dyn Iterator<Item = u8> + 'a>;
|
||||||
|
fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize>;
|
||||||
|
fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize>;
|
||||||
|
fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn copy_term<T: CopierTarget>(
|
pub(crate) fn copy_term<T: CopierTarget>(
|
||||||
target: T,
|
target: T,
|
||||||
addr: HeapCellValue,
|
addr: HeapCellValue,
|
||||||
attr_var_policy: AttrVarPolicy,
|
attr_var_policy: AttrVarPolicy,
|
||||||
) {
|
) -> Result<usize, usize> {
|
||||||
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
|
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
|
||||||
|
let old_threshold = copy_term_state.target.threshold();
|
||||||
|
|
||||||
copy_term_state.copy_term_impl(addr);
|
copy_term_state.copy_term_impl(addr)?;
|
||||||
copy_term_state.copy_attr_var_lists();
|
copy_term_state.copy_attr_var_lists()?;
|
||||||
copy_term_state.unwind_trail();
|
copy_term_state.unwind_trail();
|
||||||
|
|
||||||
|
let new_threshold = copy_term_state.target.threshold();
|
||||||
|
copy_term_state.copy_pstrs()?;
|
||||||
|
|
||||||
|
Ok(new_threshold - old_threshold)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PStrData {
|
||||||
|
pre_old_h_tail_loc: usize,
|
||||||
|
post_old_h_tail_loc: usize,
|
||||||
|
post_old_h_pstr_loc_locs: IndexSet<usize, FxBuildHasher>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -43,6 +119,9 @@ struct CopyTermState<T: CopierTarget> {
|
|||||||
target: T,
|
target: T,
|
||||||
attr_var_policy: AttrVarPolicy,
|
attr_var_policy: AttrVarPolicy,
|
||||||
attr_var_list_locs: Vec<(usize, HeapCellValue)>,
|
attr_var_list_locs: Vec<(usize, HeapCellValue)>,
|
||||||
|
// keys of pstr_loc_locs are byte indices rounded down to the
|
||||||
|
// nearest cell boundary
|
||||||
|
pstr_loc_locs: BTreeMap<usize, PStrData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: CopierTarget> CopyTermState<T> {
|
impl<T: CopierTarget> CopyTermState<T> {
|
||||||
@@ -54,6 +133,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
target,
|
target,
|
||||||
attr_var_policy,
|
attr_var_policy,
|
||||||
attr_var_list_locs: vec![],
|
attr_var_list_locs: vec![],
|
||||||
|
pstr_loc_locs: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,17 +144,17 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
|
|
||||||
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
|
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
|
||||||
let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
|
let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
|
||||||
self.trail.push((Ref::heap_cell(addr), trail_item));
|
self.trail.push((TrailRef::heap_cell(addr), trail_item));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_list(&mut self, addr: usize) {
|
fn copy_list(&mut self, addr: usize) -> Result<(), usize> {
|
||||||
for offset in 0..2 {
|
for offset in 0..2 {
|
||||||
read_heap_cell!(self.target[addr + offset],
|
read_heap_cell!(self.target[addr + offset],
|
||||||
(HeapCellValueTag::Lis, h) => {
|
(HeapCellValueTag::Lis, h) => {
|
||||||
if h >= self.old_h {
|
if h >= self.old_h {
|
||||||
*self.value_at_scan() = list_loc_as_cell!(h);
|
*self.value_at_scan() = list_loc_as_cell!(h);
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -83,14 +163,10 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let threshold = self.target.threshold();
|
let threshold = self.target.threshold();
|
||||||
|
self.target.copy_slice_to_end(addr..addr + 2)?;
|
||||||
|
|
||||||
*self.value_at_scan() = list_loc_as_cell!(threshold);
|
*self.value_at_scan() = list_loc_as_cell!(threshold);
|
||||||
|
|
||||||
for i in 0..2 {
|
|
||||||
let hcv = self.target[addr + i];
|
|
||||||
self.target.push(hcv);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cdr = self
|
let cdr = self
|
||||||
.target
|
.target
|
||||||
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
|
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
|
||||||
@@ -113,80 +189,108 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) {
|
fn copy_partial_string(&mut self, pstr_loc: usize) -> Result<(), usize> {
|
||||||
read_heap_cell!(self.target[pstr_loc],
|
match self.pstr_loc_locs.range_mut(..=pstr_loc).next_back() {
|
||||||
(HeapCellValueTag::PStrLoc, h) => {
|
Some((
|
||||||
debug_assert!(h >= self.old_h);
|
_prev_pstr_loc,
|
||||||
|
&mut PStrData {
|
||||||
*self.value_at_scan() = match scan_tag {
|
pre_old_h_tail_loc,
|
||||||
HeapCellValueTag::PStrLoc => {
|
ref mut post_old_h_pstr_loc_locs,
|
||||||
pstr_loc_as_cell!(h)
|
..
|
||||||
}
|
},
|
||||||
tag => {
|
)) if pre_old_h_tail_loc >= cell_index!(pstr_loc) => {
|
||||||
debug_assert_eq!(tag, HeapCellValueTag::PStrOffset);
|
post_old_h_pstr_loc_locs.insert(self.scan);
|
||||||
pstr_offset_as_cell!(h)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
return;
|
return Ok(());
|
||||||
}
|
|
||||||
(HeapCellValueTag::Var, h) => {
|
|
||||||
debug_assert!(h >= self.old_h);
|
|
||||||
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
|
|
||||||
|
|
||||||
*self.value_at_scan() = pstr_offset_as_cell!(h);
|
|
||||||
self.scan += 1;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
);
|
}
|
||||||
|
|
||||||
let threshold = self.target.threshold();
|
let offset = self
|
||||||
|
.target
|
||||||
|
.as_slice_from(pstr_loc)
|
||||||
|
.take_while(|b| *b != 0u8)
|
||||||
|
.count();
|
||||||
|
|
||||||
let replacement = read_heap_cell!(self.target[pstr_loc],
|
let left_pstr_boundary = cell_index!(pstr_loc + offset);
|
||||||
(HeapCellValueTag::CStr) => {
|
let flag = u64::from_be_bytes(self.target[left_pstr_boundary].into_bytes());
|
||||||
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
|
let pstr_loc_idx = cell_index!(pstr_loc);
|
||||||
|
|
||||||
*self.value_at_scan() = pstr_offset_as_cell!(threshold);
|
if flag == 1 {
|
||||||
self.target.push(self.target[pstr_loc]);
|
if left_pstr_boundary != pstr_loc_idx {
|
||||||
|
let mut pstr_data = self
|
||||||
|
.pstr_loc_locs
|
||||||
|
.remove(&heap_index!(left_pstr_boundary))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
heap_loc_as_cell!(threshold)
|
pstr_data.post_old_h_pstr_loc_locs.insert(self.scan);
|
||||||
|
self.pstr_loc_locs
|
||||||
|
.insert(heap_index!(cell_index!(pstr_loc)), pstr_data);
|
||||||
|
|
||||||
|
let old_cell = self.target[pstr_loc_idx];
|
||||||
|
self.target[pstr_loc_idx] = HeapCellValue::from_bytes(u64::to_be_bytes(1));
|
||||||
|
self.trail
|
||||||
|
.push((TrailRef::pstr_loc(pstr_loc_idx), old_cell));
|
||||||
|
} else {
|
||||||
|
let pstr_data = self
|
||||||
|
.pstr_loc_locs
|
||||||
|
.get_mut(&heap_index!(left_pstr_boundary))
|
||||||
|
.unwrap();
|
||||||
|
pstr_data.post_old_h_pstr_loc_locs.insert(self.scan);
|
||||||
}
|
}
|
||||||
_ => {
|
} else {
|
||||||
*self.value_at_scan() = if scan_tag == HeapCellValueTag::PStrLoc {
|
let old_cell = self.target[pstr_loc_idx];
|
||||||
pstr_loc_as_cell!(threshold)
|
self.target[pstr_loc_idx] = HeapCellValue::from_bytes(u64::to_be_bytes(1));
|
||||||
} else {
|
self.trail
|
||||||
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
|
.push((TrailRef::pstr_loc(pstr_loc_idx), old_cell));
|
||||||
pstr_offset_as_cell!(threshold)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.target.push(self.target[pstr_loc]);
|
let old_tail_idx = if (pstr_loc + offset + 1) % Heap::heap_cell_alignment() == 0 {
|
||||||
self.target.push(self.target[pstr_loc + 1]);
|
cell_index!(pstr_loc + offset) + 2
|
||||||
|
} else {
|
||||||
|
cell_index!(pstr_loc + offset) + 1
|
||||||
|
};
|
||||||
|
|
||||||
pstr_loc_as_cell!(threshold)
|
let tail_cell = self.target[old_tail_idx];
|
||||||
}
|
|
||||||
);
|
let new_tail_idx = self.target.threshold();
|
||||||
|
let mut writer = self.target.reserve(1)?;
|
||||||
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(tail_cell);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut post_old_h_pstr_loc_locs = IndexSet::with_hasher(FxBuildHasher::default());
|
||||||
|
post_old_h_pstr_loc_locs.insert(self.scan);
|
||||||
|
|
||||||
|
let pstr_data = PStrData {
|
||||||
|
pre_old_h_tail_loc: old_tail_idx,
|
||||||
|
post_old_h_tail_loc: new_tail_idx,
|
||||||
|
post_old_h_pstr_loc_locs,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pstr_loc_locs
|
||||||
|
.insert(heap_index!(pstr_loc_idx), pstr_data);
|
||||||
|
}
|
||||||
|
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
|
Ok(())
|
||||||
let trail_item = mem::replace(&mut self.target[pstr_loc], replacement);
|
|
||||||
self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_attr_var_lists(&mut self) {
|
fn copy_attr_var_lists(&mut self) -> Result<(), usize> {
|
||||||
while !self.attr_var_list_locs.is_empty() {
|
while !self.attr_var_list_locs.is_empty() {
|
||||||
let iter = std::mem::take(&mut self.attr_var_list_locs);
|
let mut list_loc_vec = std::mem::take(&mut self.attr_var_list_locs);
|
||||||
|
|
||||||
for (threshold, list_loc) in iter {
|
while let Some((threshold, list_loc)) = list_loc_vec.pop() {
|
||||||
self.target[threshold] = list_loc_as_cell!(self.target.threshold());
|
self.target[threshold] = list_loc_as_cell!(self.target.threshold());
|
||||||
self.target.push_attr_var_queue(threshold - 1);
|
self.target.push_attr_var_queue(threshold - 1);
|
||||||
self.copy_attr_var_list(list_loc);
|
self.copy_attr_var_list(list_loc)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -194,48 +298,49 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
* structure which is ensured by this function and not at all by
|
* structure which is ensured by this function and not at all by
|
||||||
* the vanilla copier.
|
* the vanilla copier.
|
||||||
*/
|
*/
|
||||||
fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) {
|
fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) -> Result<(), usize> {
|
||||||
while let HeapCellValueTag::Lis = list_addr.get_tag() {
|
while let HeapCellValueTag::Lis = list_addr.get_tag() {
|
||||||
let threshold = self.target.threshold();
|
let threshold = self.target.threshold();
|
||||||
let heap_loc = list_addr.get_value() as usize;
|
let heap_loc = list_addr.get_value() as usize;
|
||||||
let str_loc = self.target[heap_loc].get_value() as usize;
|
let str_loc = self.target[heap_loc].get_value() as usize;
|
||||||
|
let str_cell = self.target[str_loc];
|
||||||
|
let mut writer = self.target.reserve(3).unwrap();
|
||||||
|
|
||||||
self.target.push(heap_loc_as_cell!(threshold + 2));
|
writer.write_with(|section| {
|
||||||
self.target.push(heap_loc_as_cell!(threshold + 1));
|
section.push_cell(heap_loc_as_cell!(threshold + 2));
|
||||||
|
section.push_cell(heap_loc_as_cell!(threshold + 1));
|
||||||
|
|
||||||
read_heap_cell!(self.target[str_loc],
|
if str_cell.to_atom().is_some() {
|
||||||
(HeapCellValueTag::Atom) => {
|
section.push_cell(str_cell);
|
||||||
self.target.push(self.target[str_loc]);
|
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str) => {
|
});
|
||||||
self.copy_term_impl(self.target[str_loc]);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
debug_assert_eq!(str_cell.get_tag(), HeapCellValueTag::Str);
|
||||||
|
|
||||||
|
self.copy_term_impl(str_cell)?;
|
||||||
list_addr = self.target[heap_loc + 1];
|
list_addr = self.target[heap_loc + 1];
|
||||||
|
|
||||||
if HeapCellValueTag::Lis == list_addr.get_tag() {
|
if HeapCellValueTag::Lis == list_addr.get_tag() {
|
||||||
self.target[threshold + 1] = list_loc_as_cell!(self.target.threshold());
|
self.target[threshold + 1] = list_loc_as_cell!(self.target.threshold());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
|
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) -> Result<(), usize> {
|
||||||
read_heap_cell!(addr,
|
read_heap_cell!(addr,
|
||||||
(HeapCellValueTag::Var, h) => {
|
(HeapCellValueTag::Var, h) => {
|
||||||
self.target[frontier] = heap_loc_as_cell!(frontier);
|
self.target[frontier] = heap_loc_as_cell!(frontier);
|
||||||
self.target[h] = 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)));
|
self.trail.push((TrailRef::heap_cell(h), heap_loc_as_cell!(h)));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::StackVar, s) => {
|
(HeapCellValueTag::StackVar, s) => {
|
||||||
self.target[frontier] = heap_loc_as_cell!(frontier);
|
self.target[frontier] = heap_loc_as_cell!(frontier);
|
||||||
self.target.stack()[s] = 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)));
|
self.trail.push((TrailRef::stack_cell(s), stack_loc_as_cell!(s)));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::AttrVar, h) => {
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||||
@@ -247,14 +352,18 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
self.target[frontier] = heap_loc_as_cell!(threshold);
|
self.target[frontier] = heap_loc_as_cell!(threshold);
|
||||||
self.target[h] = heap_loc_as_cell!(threshold);
|
self.target[h] = heap_loc_as_cell!(threshold);
|
||||||
|
|
||||||
self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h)));
|
self.trail.push((TrailRef::attr_var(h), attr_var_as_cell!(h)));
|
||||||
|
|
||||||
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||||
self.target.push(attr_var_as_cell!(threshold));
|
let mut writer = self.target.reserve(2)?;
|
||||||
self.target.push(heap_loc_as_cell!(threshold + 1));
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(attr_var_as_cell!(threshold));
|
||||||
|
section.push_cell(heap_loc_as_cell!(threshold + 1));
|
||||||
|
});
|
||||||
|
|
||||||
let old_list_link = self.target[h + 1];
|
let old_list_link = self.target[h + 1];
|
||||||
self.trail.push((Ref::heap_cell(h + 1), old_list_link));
|
self.trail.push((TrailRef::heap_cell(h + 1), old_list_link));
|
||||||
self.target[h + 1] = heap_loc_as_cell!(threshold + 1);
|
self.target[h + 1] = heap_loc_as_cell!(threshold + 1);
|
||||||
|
|
||||||
if old_list_link.get_tag() == HeapCellValueTag::Lis {
|
if old_list_link.get_tag() == HeapCellValueTag::Lis {
|
||||||
@@ -266,9 +375,11 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_var(&mut self, addr: HeapCellValue) {
|
fn copy_var(&mut self, addr: HeapCellValue) -> Result<(), usize> {
|
||||||
let index = addr.get_value() as usize;
|
let index = addr.get_value() as usize;
|
||||||
let rd = self.target.deref(addr);
|
let rd = self.target.deref(addr);
|
||||||
let ra = self.target.store(rd);
|
let ra = self.target.store(rd);
|
||||||
@@ -278,7 +389,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
if h >= self.old_h {
|
if h >= self.old_h {
|
||||||
*self.value_at_scan() = ra;
|
*self.value_at_scan() = ra;
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Lis, h) => {
|
(HeapCellValueTag::Lis, h) => {
|
||||||
@@ -292,47 +403,52 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
);
|
);
|
||||||
|
|
||||||
if rd == ra {
|
if rd == ra {
|
||||||
self.reinstantiate_var(ra, self.scan);
|
self.reinstantiate_var(ra, self.scan)?;
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
} else {
|
} else {
|
||||||
*self.value_at_scan() = ra;
|
*self.value_at_scan() = ra;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_structure(&mut self, addr: usize) {
|
fn copy_structure(&mut self, addr: usize) -> Result<(), usize> {
|
||||||
read_heap_cell!(self.target[addr],
|
read_heap_cell!(self.target[addr],
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||||
let threshold = self.target.threshold();
|
let threshold = self.target.threshold();
|
||||||
|
|
||||||
*self.value_at_scan() = str_loc_as_cell!(threshold);
|
let index_cell = self.target[addr.saturating_sub(1)];
|
||||||
|
|
||||||
|
let str_cell = if get_structure_index(index_cell).is_some() {
|
||||||
|
// copy the index pointer trailing this
|
||||||
|
// inlined or expanded goal.
|
||||||
|
let mut writer = self.target.reserve(1).unwrap();
|
||||||
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(index_cell);
|
||||||
|
});
|
||||||
|
|
||||||
|
str_loc_as_cell!(threshold + 1)
|
||||||
|
} else {
|
||||||
|
str_loc_as_cell!(threshold)
|
||||||
|
};
|
||||||
|
|
||||||
|
*self.value_at_scan() = str_cell;
|
||||||
|
self.target.copy_slice_to_end(addr .. addr + 1 + arity)?;
|
||||||
|
|
||||||
let trail_item = mem::replace(
|
let trail_item = mem::replace(
|
||||||
&mut self.target[addr],
|
&mut self.target[addr],
|
||||||
str_loc_as_cell!(threshold),
|
str_cell,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.trail.push((Ref::heap_cell(addr), trail_item));
|
self.trail.push((TrailRef::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];
|
|
||||||
self.target.push(hcv);
|
|
||||||
}
|
|
||||||
|
|
||||||
let index_cell = self.target[addr + 1 + arity];
|
|
||||||
|
|
||||||
if get_structure_index(index_cell).is_some() {
|
|
||||||
// copy the index pointer trailing this
|
|
||||||
// inlined or expanded goal.
|
|
||||||
self.target.push(index_cell);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str, h) => {
|
(HeapCellValueTag::Str, h) => {
|
||||||
*self.value_at_scan() = str_loc_as_cell!(h);
|
*self.value_at_scan() = str_loc_as_cell!(h);
|
||||||
@@ -343,11 +459,16 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_term_impl(&mut self, addr: HeapCellValue) {
|
fn copy_term_impl(&mut self, addr: HeapCellValue) -> Result<(), usize> {
|
||||||
self.scan = self.target.threshold();
|
self.scan = self.target.threshold();
|
||||||
self.target.push(addr);
|
let mut writer = self.target.reserve(1)?;
|
||||||
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(addr);
|
||||||
|
});
|
||||||
|
|
||||||
while self.scan < self.target.threshold() {
|
while self.scan < self.target.threshold() {
|
||||||
let addr = *self.value_at_scan();
|
let addr = *self.value_at_scan();
|
||||||
@@ -356,37 +477,64 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
(HeapCellValueTag::Lis, h) => {
|
(HeapCellValueTag::Lis, h) => {
|
||||||
if h >= self.old_h {
|
if h >= self.old_h {
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
self.copy_list(h);
|
self.copy_list(h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
|
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
|
||||||
self.copy_var(addr);
|
self.copy_var(addr)
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str, h) => {
|
(HeapCellValueTag::Str, h) => {
|
||||||
self.copy_structure(h);
|
self.copy_structure(h)
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => {
|
(HeapCellValueTag::PStrLoc, pstr_loc) => {
|
||||||
self.copy_partial_string(addr.get_tag(), pstr_loc);
|
self.copy_partial_string(pstr_loc)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.scan += 1;
|
self.scan += 1;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwind_trail(mut self) {
|
fn copy_pstrs(&mut self) -> Result<(), usize> {
|
||||||
for (r, value) in self.trail {
|
while let Some((least_pstr_loc, pstr_data)) = self.pstr_loc_locs.pop_first() {
|
||||||
let index = r.get_value() as usize;
|
let threshold = heap_index!(self.target.threshold());
|
||||||
|
|
||||||
match r.get_tag() {
|
for pstr_loc_loc in pstr_data.post_old_h_pstr_loc_locs {
|
||||||
RefTag::AttrVar | RefTag::HeapCell => {
|
let pstr_loc = self.target[pstr_loc_loc].get_value() as usize;
|
||||||
|
self.target[pstr_loc_loc] =
|
||||||
|
pstr_loc_as_cell!(threshold + pstr_loc - least_pstr_loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.target.copy_pstr_to_threshold(least_pstr_loc)?;
|
||||||
|
|
||||||
|
let mut writer = self.target.reserve(1)?;
|
||||||
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(heap_loc_as_cell!(pstr_data.post_old_h_tail_loc));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unwind_trail(&mut self) {
|
||||||
|
for (r, value) in self.trail.drain(..) {
|
||||||
|
let index = r.val() as usize;
|
||||||
|
|
||||||
|
match r.tag() {
|
||||||
|
TrailRefTag::AttrVar | TrailRefTag::HeapCell => {
|
||||||
self.target[index] = value;
|
self.target[index] = value;
|
||||||
self.target[index].set_mark_bit(false);
|
self.target[index].set_mark_bit(false);
|
||||||
self.target[index].set_forwarding_bit(false);
|
self.target[index].set_forwarding_bit(false);
|
||||||
}
|
}
|
||||||
RefTag::StackCell => self.target.stack()[index] = value,
|
TrailRefTag::StackCell => self.target.stack()[index] = value,
|
||||||
|
TrailRefTag::PStrLoc => self.target[index] = value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,19 +543,26 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::functor_macro::*;
|
||||||
use crate::machine::mock_wam::*;
|
use crate::machine::mock_wam::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn copier_tests() {
|
fn copier_tests() {
|
||||||
let mut wam = MockWAM::new();
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
// clear the heap of resource error data etc
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
let f_atom = atom!("f");
|
let f_atom = atom!("f");
|
||||||
let a_atom = atom!("a");
|
let a_atom = atom!("a");
|
||||||
let b_atom = atom!("b");
|
let b_atom = atom!("b");
|
||||||
|
|
||||||
wam.machine_st
|
let mut functor_writer = Heap::functor_writer(functor!(
|
||||||
.heap
|
f_atom,
|
||||||
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
[atom_as_cell(a_atom), atom_as_cell(b_atom)]
|
||||||
|
));
|
||||||
|
|
||||||
|
functor_writer(&mut wam.machine_st.heap).unwrap();
|
||||||
|
|
||||||
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
|
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[1], atom_as_cell!(a_atom));
|
||||||
@@ -415,7 +570,7 @@ mod tests {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let wam = TermCopyingMockWAM { wam: &mut wam };
|
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||||
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
|
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that the original heap state is still intact.
|
// check that the original heap state is still intact.
|
||||||
@@ -430,69 +585,266 @@ mod tests {
|
|||||||
|
|
||||||
wam.machine_st.heap.clear();
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
let pstr_var_cell =
|
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
|
||||||
put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
|
|
||||||
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
|
|
||||||
|
|
||||||
wam.machine_st.heap.pop();
|
writer.write_with(|section| {
|
||||||
wam.machine_st.heap.push(pstr_loc_as_cell!(2));
|
section.push_pstr("abc ");
|
||||||
|
section.push_cell(pstr_loc_as_cell!(heap_index!(2)));
|
||||||
|
|
||||||
let pstr_second_var_cell =
|
section.push_pstr("def");
|
||||||
put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
|
section.push_cell(pstr_loc_as_cell!(0));
|
||||||
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 };
|
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||||
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
|
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
print_heap_terms(wam.machine_st.heap[6..].iter(), 6);
|
assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc ");
|
||||||
|
assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(2)));
|
||||||
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!(
|
assert_eq!(
|
||||||
wam.machine_st.heap[5],
|
wam.machine_st
|
||||||
fixnum_as_cell!(Fixnum::build_with(0i64))
|
.heap
|
||||||
|
.slice_to_str(heap_index!(2), "def".len()),
|
||||||
|
"def"
|
||||||
);
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(7)));
|
||||||
|
assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(9)));
|
||||||
|
assert_eq!(wam.machine_st.heap[6], pstr_loc_as_cell!(heap_index!(7)));
|
||||||
|
|
||||||
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!(
|
assert_eq!(
|
||||||
wam.machine_st.heap[12],
|
wam.machine_st
|
||||||
fixnum_as_cell!(Fixnum::build_with(0i64))
|
.heap
|
||||||
|
.slice_to_str(heap_index!(7), "abc ".len()),
|
||||||
|
"abc "
|
||||||
);
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[8], heap_loc_as_cell!(5));
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st
|
||||||
|
.heap
|
||||||
|
.slice_to_str(heap_index!(9), "def".len()),
|
||||||
|
"def"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[10], heap_loc_as_cell!(6));
|
||||||
|
|
||||||
wam.machine_st.heap.clear();
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
wam.machine_st.heap.extend(functor!(
|
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
|
||||||
f_atom,
|
|
||||||
[
|
writer.write_with(|section| {
|
||||||
atom(a_atom),
|
section.push_pstr("abc ");
|
||||||
atom(b_atom),
|
section.push_cell(pstr_loc_as_cell!(heap_index!(2) + 9));
|
||||||
atom(a_atom),
|
|
||||||
cell(str_loc_as_cell!(0))
|
section.push_pstr("defdefdefdef");
|
||||||
]
|
section.push_cell(pstr_loc_as_cell!(0));
|
||||||
));
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
let wam = TermCopyingMockWAM { wam: &mut wam };
|
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||||
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
|
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc ");
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[1],
|
||||||
|
pstr_loc_as_cell!(heap_index!(2) + 9)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st
|
||||||
|
.heap
|
||||||
|
.slice_to_str(heap_index!(2), "defdefdefdef".len()),
|
||||||
|
"defdefdefdef"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(8)));
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[6],
|
||||||
|
pstr_loc_as_cell!(heap_index!(10) + 1)
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[7], pstr_loc_as_cell!(heap_index!(8)));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st
|
||||||
|
.heap
|
||||||
|
.slice_to_str(heap_index!(8), "abc ".len()),
|
||||||
|
"abc "
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(6));
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st
|
||||||
|
.heap
|
||||||
|
.slice_to_str(heap_index!(10), "fdef".len()),
|
||||||
|
"fdef"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[11], heap_loc_as_cell!(7));
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
|
||||||
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_pstr("012345678912345");
|
||||||
|
section.push_cell(pstr_loc_as_cell!(heap_index!(0)));
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||||
|
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
|
||||||
|
"012345678912345"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(heap_index!(0)));
|
||||||
|
|
||||||
|
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(6)));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st
|
||||||
|
.heap
|
||||||
|
.slice_to_str(heap_index!(6), "012345678912345".len()),
|
||||||
|
"012345678912345"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(6)));
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
|
||||||
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_pstr("012345678912345");
|
||||||
|
section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 9));
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||||
|
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
|
||||||
|
"012345678912345"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[3],
|
||||||
|
pstr_loc_as_cell!(heap_index!(0) + 9)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(6)));
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[5],
|
||||||
|
pstr_loc_as_cell!(heap_index!(6) + 9)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st
|
||||||
|
.heap
|
||||||
|
.slice_to_str(heap_index!(6), "012345678912345".len()),
|
||||||
|
"012345678912345"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(5));
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
|
||||||
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_pstr("012345678912345");
|
||||||
|
section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 7));
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||||
|
copy_term(wam, pstr_loc_as_cell!(11), AttrVarPolicy::DeepCopy).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
|
||||||
|
"012345678912345"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[3],
|
||||||
|
pstr_loc_as_cell!(heap_index!(0) + 7)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[4],
|
||||||
|
pstr_loc_as_cell!(heap_index!(6) + 11)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[5],
|
||||||
|
pstr_loc_as_cell!(heap_index!(6) + 7)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st
|
||||||
|
.heap
|
||||||
|
.slice_to_str(heap_index!(6), "012345678912345".len()),
|
||||||
|
"012345678912345"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(5));
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
|
||||||
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_pstr("012345678912345");
|
||||||
|
section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 12));
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||||
|
copy_term(wam, pstr_loc_as_cell!(11), AttrVarPolicy::DeepCopy).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
|
||||||
|
"012345678912345"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[3],
|
||||||
|
pstr_loc_as_cell!(heap_index!(0) + 12)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[4],
|
||||||
|
pstr_loc_as_cell!(heap_index!(6) + 3)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st.heap[5],
|
||||||
|
pstr_loc_as_cell!(heap_index!(6) + 4)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wam.machine_st
|
||||||
|
.heap
|
||||||
|
.slice_to_str(heap_index!(6), "8912345".len()),
|
||||||
|
"8912345"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.machine_st.heap[8], heap_loc_as_cell!(5));
|
||||||
|
|
||||||
|
wam.machine_st.heap.clear();
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor!(
|
||||||
|
f_atom,
|
||||||
|
[
|
||||||
|
atom_as_cell(a_atom),
|
||||||
|
atom_as_cell(b_atom),
|
||||||
|
atom_as_cell(a_atom),
|
||||||
|
str_loc_as_cell(0)
|
||||||
|
]
|
||||||
|
));
|
||||||
|
|
||||||
|
functor_writer(&mut wam.machine_st.heap).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||||
|
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4));
|
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4));
|
||||||
@@ -500,7 +852,6 @@ mod tests {
|
|||||||
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_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[3], atom_as_cell!(a_atom));
|
||||||
assert_eq!(wam.machine_st.heap[4], str_loc_as_cell!(0));
|
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[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[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[7], atom_as_cell!(a_atom));
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
|
use crate::machine::heap::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
/* Use the pointer reversal technique of the Deutsch-Schorr-Waite
|
/* Use the pointer reversal technique of the Deutsch-Schorr-Waite
|
||||||
@@ -11,7 +12,7 @@ use crate::types::*;
|
|||||||
* - Cells are only marked during the backward phase
|
* - Cells are only marked during the backward phase
|
||||||
* - Visiting subterms of a visited compound does not immediately shift to the backward phase
|
* - Visiting subterms of a visited compound does not immediately shift to the backward phase
|
||||||
* - The heads of LIS structures are both marked and forwarded rather
|
* - The heads of LIS structures are both marked and forwarded rather
|
||||||
* than just forwarded to distinguish them from tails;
|
* than just forwarded to distinguish them from tails
|
||||||
* continue_forwarding() checks for this before entering the forward
|
* continue_forwarding() checks for this before entering the forward
|
||||||
* phase
|
* phase
|
||||||
*
|
*
|
||||||
@@ -22,7 +23,7 @@ use crate::types::*;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> {
|
pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> {
|
||||||
pub(crate) heap: &'a mut [HeapCellValue],
|
pub(crate) heap: &'a mut Heap,
|
||||||
start: usize,
|
start: usize,
|
||||||
current: usize,
|
current: usize,
|
||||||
next: u64,
|
next: u64,
|
||||||
@@ -31,7 +32,7 @@ pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
|
impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
|
||||||
pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self {
|
pub(crate) fn new(heap: &'a mut Heap, start: usize) -> Self {
|
||||||
heap[start].set_forwarding_bit(true);
|
heap[start].set_forwarding_bit(true);
|
||||||
let next = heap[start].get_value();
|
let next = heap[start].get_value();
|
||||||
|
|
||||||
@@ -127,7 +128,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
|
|||||||
self.current = next;
|
self.current = next;
|
||||||
self.next = temp;
|
self.next = temp;
|
||||||
|
|
||||||
if self.next < self.heap.len() as u64 {
|
if self.next < self.heap.cell_len() as u64 {
|
||||||
return Some(HeapCellValue::build_with(tag, next as u64));
|
return Some(HeapCellValue::build_with(tag, next as u64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,10 +137,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
|
|||||||
let cell = self.heap[h];
|
let cell = self.heap[h];
|
||||||
let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
|
let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
|
||||||
|
|
||||||
let last_cell_loc = match self.traverse_subterm(h + 1, arity) {
|
let last_cell_loc = self.traverse_subterm(h + 1, arity)?;
|
||||||
Some(last_cell_loc) => last_cell_loc,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if last_cell_loc == h {
|
if last_cell_loc == h {
|
||||||
if self.backward() {
|
if self.backward() {
|
||||||
@@ -170,10 +168,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
|
|||||||
let mut cell = self.heap[self.current];
|
let mut cell = self.heap[self.current];
|
||||||
cell.set_value(self.next);
|
cell.set_value(self.next);
|
||||||
|
|
||||||
let last_cell_loc = match self.traverse_subterm(self.next as usize, 2) {
|
let last_cell_loc = self.traverse_subterm(self.next as usize, 2)?;
|
||||||
Some(last_cell_loc) => last_cell_loc,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.cycle_detection_active() {
|
if self.cycle_detection_active() {
|
||||||
for idx in (self.next as usize..last_cell_loc).rev() {
|
for idx in (self.next as usize..last_cell_loc).rev() {
|
||||||
@@ -205,10 +200,9 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
|
|||||||
}
|
}
|
||||||
HeapCellValueTag::PStrLoc => {
|
HeapCellValueTag::PStrLoc => {
|
||||||
let h = self.next as usize;
|
let h = self.next as usize;
|
||||||
let cell = self.heap[h];
|
let tail_idx = self.heap.scan_slice_to_str(h).tail_idx;
|
||||||
let last_cell_loc = h + 1;
|
|
||||||
|
|
||||||
if self.heap[last_cell_loc].get_forwarding_bit() {
|
if self.heap[tail_idx].get_forwarding_bit() {
|
||||||
if self.cycle_detection_active() {
|
if self.cycle_detection_active() {
|
||||||
self.cycle_found = true;
|
self.cycle_found = true;
|
||||||
return None;
|
return None;
|
||||||
@@ -219,45 +213,13 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.heap[last_cell_loc].set_forwarding_bit(true);
|
self.heap[tail_idx].set_forwarding_bit(true);
|
||||||
|
|
||||||
self.next = self.heap[last_cell_loc].get_value();
|
self.next = self.heap[tail_idx].get_value();
|
||||||
self.heap[last_cell_loc].set_value(self.current as u64);
|
self.heap[tail_idx].set_value(self.current as u64);
|
||||||
self.current = last_cell_loc;
|
self.current = tail_idx;
|
||||||
|
|
||||||
return Some(cell);
|
return Some(pstr_loc_as_cell!(h));
|
||||||
}
|
|
||||||
HeapCellValueTag::PStrOffset => {
|
|
||||||
let h = self.next as usize;
|
|
||||||
let cell = self.heap[h];
|
|
||||||
let last_cell_loc = h + 1;
|
|
||||||
|
|
||||||
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
|
|
||||||
if self.heap[last_cell_loc].get_forwarding_bit() {
|
|
||||||
if self.cycle_detection_active() {
|
|
||||||
self.cycle_found = true;
|
|
||||||
return None;
|
|
||||||
} else if self.backward() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.heap[last_cell_loc].set_forwarding_bit(true);
|
|
||||||
|
|
||||||
self.next = self.heap[last_cell_loc].get_value();
|
|
||||||
self.heap[last_cell_loc].set_value(self.current as u64);
|
|
||||||
self.current = last_cell_loc;
|
|
||||||
} else {
|
|
||||||
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr);
|
|
||||||
|
|
||||||
self.next = self.heap[h].get_value();
|
|
||||||
self.heap[h].set_value(self.current as u64);
|
|
||||||
self.current = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(cell);
|
|
||||||
}
|
}
|
||||||
tag @ HeapCellValueTag::Atom => {
|
tag @ HeapCellValueTag::Atom => {
|
||||||
let cell = HeapCellValue::build_with(tag, self.next);
|
let cell = HeapCellValue::build_with(tag, self.next);
|
||||||
@@ -269,11 +231,6 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HeapCellValueTag::PStr => {
|
|
||||||
if self.backward() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
return Some(self.backward_and_return());
|
return Some(self.backward_and_return());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,10 +200,12 @@ impl VarData {
|
|||||||
|
|
||||||
match build_stack.front_mut() {
|
match build_stack.front_mut() {
|
||||||
Some(ChunkedTerms::Branch(_)) => {
|
Some(ChunkedTerms::Branch(_)) => {
|
||||||
build_stack.push_front(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
|
build_stack.push_front(ChunkedTerms::Chunk {
|
||||||
|
terms: VecDeque::from(vec![term]),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Some(ChunkedTerms::Chunk(chunk)) => {
|
Some(ChunkedTerms::Chunk { terms, .. }) => {
|
||||||
chunk.push_front(term);
|
terms.push_front(term);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -423,7 +425,6 @@ impl VariableClassifier {
|
|||||||
// "probe_head_var". note the difference between it
|
// "probe_head_var". note the difference between it
|
||||||
// and "probe_body_var".
|
// and "probe_body_var".
|
||||||
let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
|
let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
|
||||||
|
|
||||||
let needs_new_branch = branch_info_v.is_empty();
|
let needs_new_branch = branch_info_v.is_empty();
|
||||||
|
|
||||||
if needs_new_branch {
|
if needs_new_branch {
|
||||||
@@ -578,7 +579,7 @@ impl VariableClassifier {
|
|||||||
mut terms,
|
mut terms,
|
||||||
) if terms.len() == 3 => {
|
) if terms.len() == 3 => {
|
||||||
if let Some(last_arg) = terms.last() {
|
if let Some(last_arg) = terms.last() {
|
||||||
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
|
if let Term::Literal(_, Literal::CodeIndexOffset(_)) = last_arg {
|
||||||
terms.pop();
|
terms.pop();
|
||||||
state_stack.push(TraversalState::Term(Term::Clause(
|
state_stack.push(TraversalState::Term(Term::Clause(
|
||||||
Cell::default(),
|
Cell::default(),
|
||||||
@@ -801,7 +802,7 @@ impl VariableClassifier {
|
|||||||
self.call_policy,
|
self.call_policy,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
|
Term::Literal(_, Literal::Atom(atom!("!"))) => {
|
||||||
let (var_num, is_global) =
|
let (var_num, is_global) =
|
||||||
if let Some(var_num) = self.global_cut_var_num_override {
|
if let Some(var_num) = self.global_cut_var_num_override {
|
||||||
(var_num, false)
|
(var_num, false)
|
||||||
@@ -879,10 +880,10 @@ impl BranchMap {
|
|||||||
|
|
||||||
for var_info in chunk.vars.iter_mut() {
|
for var_info in chunk.vars.iter_mut() {
|
||||||
if var_info.lvl == Level::Shallow {
|
if var_info.lvl == Level::Shallow {
|
||||||
let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num);
|
let context = var_info.chunk_type.to_gen_context(chunk.chunk_num);
|
||||||
temp_var_data
|
temp_var_data
|
||||||
.use_set
|
.use_set
|
||||||
.insert((term_loc, var_info.classify_info.arg_c));
|
.insert((context, var_info.classify_info.arg_c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1566
src/machine/gc.rs
1566
src/machine/gc.rs
File diff suppressed because it is too large
Load Diff
1277
src/machine/heap.rs
1277
src/machine/heap.rs
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,15 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::atom_table;
|
use crate::atom_table;
|
||||||
use crate::heap_iter::{stackful_post_order_iter, NonListElider};
|
use crate::heap_iter::{stackful_post_order_iter, NonListElider};
|
||||||
use crate::machine::machine_indices::VarKey;
|
use crate::machine::machine_indices::VarKey;
|
||||||
use crate::machine::mock_wam::CompositeOpDir;
|
use crate::machine::mock_wam::CompositeOpDir;
|
||||||
use crate::machine::{
|
use crate::machine::{
|
||||||
ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC,
|
ArenaHeaderTag, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS,
|
||||||
LIB_QUERY_SUCCESS,
|
|
||||||
};
|
};
|
||||||
|
use crate::offset_table::*;
|
||||||
use crate::parser::ast::{Var, VarPtr};
|
use crate::parser::ast::{Var, VarPtr};
|
||||||
use crate::parser::parser::{Parser, Tokens};
|
use crate::parser::parser::{Parser, Tokens};
|
||||||
use crate::read::{write_term_to_heap, TermWriteResult};
|
use crate::read::{write_term_to_heap, TermWriteResult};
|
||||||
@@ -175,10 +176,13 @@ impl Term {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
// Adapted from MachineState::read_term_from_heap
|
// Adapted from MachineState::read_term_from_heap
|
||||||
let mut term_stack = vec![];
|
let mut term_stack = vec![];
|
||||||
let iter = stackful_post_order_iter::<NonListElider>(
|
|
||||||
|
machine.machine_st.heap[0] = heap_cell;
|
||||||
|
|
||||||
|
let mut iter = stackful_post_order_iter::<NonListElider>(
|
||||||
&mut machine.machine_st.heap,
|
&mut machine.machine_st.heap,
|
||||||
&mut machine.machine_st.stack,
|
&mut machine.machine_st.stack,
|
||||||
heap_cell,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut anon_count: usize = 0;
|
let mut anon_count: usize = 0;
|
||||||
@@ -193,7 +197,7 @@ impl Term {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
for addr in iter {
|
while let Some(addr) = iter.next() {
|
||||||
let addr = unmark_cell_bits!(addr);
|
let addr = unmark_cell_bits!(addr);
|
||||||
|
|
||||||
read_heap_cell!(addr,
|
read_heap_cell!(addr,
|
||||||
@@ -244,11 +248,11 @@ impl Term {
|
|||||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
|
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
|
||||||
let var = var_names.get(&addr).map(|x| x.borrow().clone());
|
let var = var_names.get(&addr).map(|x| x.borrow().clone());
|
||||||
match var {
|
match var {
|
||||||
Some(Var::Named(name)) => term_stack.push(Term::Var(name)),
|
Some(Var::Named(name)) => term_stack.push(Term::Var(name.as_ref().to_owned())),
|
||||||
_ => {
|
_ => {
|
||||||
let anon_name = loop {
|
let anon_name = loop {
|
||||||
// Generate a name for the anonymous variable
|
// Generate a name for the anonymous variable
|
||||||
let anon_name = count_to_letter_code(anon_count);
|
let anon_name = Rc::new(count_to_letter_code(anon_count));
|
||||||
|
|
||||||
// Find if this name is already being used
|
// Find if this name is already being used
|
||||||
var_names.sort_by(|_, a, _, b| {
|
var_names.sort_by(|_, a, _, b| {
|
||||||
@@ -269,21 +273,19 @@ impl Term {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
term_stack.push(Term::Var(anon_name));
|
term_stack.push(Term::Var(anon_name.as_ref().to_owned()));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::F64, f) => {
|
(HeapCellValueTag::F64Offset, offset) => {
|
||||||
term_stack.push(Term::Float((*f).into()));
|
let f = machine.machine_st.arena.f64_tbl.get_entry(offset);
|
||||||
}
|
term_stack.push(Term::Float(f.into()));
|
||||||
(HeapCellValueTag::Char, c) => {
|
|
||||||
term_stack.push(Term::Atom(c.into()));
|
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Fixnum, n) => {
|
(HeapCellValueTag::Fixnum, n) => {
|
||||||
term_stack.push(Term::Integer(n.into()));
|
term_stack.push(Term::Integer(n.into()));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Cons, ptr) => {
|
(HeapCellValueTag::Cons, ptr) => {
|
||||||
if let Ok(n) = Number::try_from(addr) {
|
if let Ok(n) = Number::try_from((addr, &machine.machine_st.arena.f64_tbl)) {
|
||||||
match n {
|
match n {
|
||||||
Number::Integer(i) => term_stack.push(Term::Integer((*i).clone())),
|
Number::Integer(i) => term_stack.push(Term::Integer((*i).clone())),
|
||||||
Number::Rational(r) => term_stack.push(Term::Rational((*r).clone())),
|
Number::Rational(r) => term_stack.push(Term::Rational((*r).clone())),
|
||||||
@@ -296,7 +298,7 @@ impl Term {
|
|||||||
Term::atom(alias.as_str().to_string())
|
Term::atom(alias.as_str().to_string())
|
||||||
} else {
|
} else {
|
||||||
Term::compound("$stream", [
|
Term::compound("$stream", [
|
||||||
Term::integer(stream.as_ptr() as usize)
|
Term::integer(stream.as_ptr().addr())
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
term_stack.push(stream_term);
|
term_stack.push(stream_term);
|
||||||
@@ -310,35 +312,7 @@ impl Term {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::CStr, s) => {
|
|
||||||
term_stack.push(Term::String(s.as_str().to_string()));
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
//let h = iter.focus().value() as usize;
|
|
||||||
//let mut arity = arity;
|
|
||||||
|
|
||||||
// Not sure why/if this is needed.
|
|
||||||
// Might find out with better testing later.
|
|
||||||
/*
|
|
||||||
if iter.heap.len() > h + arity + 1 {
|
|
||||||
let value = iter.heap[h + arity + 1];
|
|
||||||
|
|
||||||
if let Some(idx) = get_structure_index(value) {
|
|
||||||
// in the second condition, arity == 0,
|
|
||||||
// meaning idx cannot pertain to this atom
|
|
||||||
// if it is the direct subterm of a larger
|
|
||||||
// structure.
|
|
||||||
if arity > 0 || !iter.direct_subterm_of_str(h) {
|
|
||||||
term_stack.push(
|
|
||||||
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
|
|
||||||
);
|
|
||||||
|
|
||||||
arity += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if arity == 0 {
|
if arity == 0 {
|
||||||
let atom_name = name.as_str().to_string();
|
let atom_name = name.as_str().to_string();
|
||||||
if atom_name == "[]" {
|
if atom_name == "[]" {
|
||||||
@@ -354,8 +328,9 @@ impl Term {
|
|||||||
term_stack.push(Term::Compound(name.as_str().to_string(), subterms));
|
term_stack.push(Term::Compound(name.as_str().to_string(), subterms));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStr, atom) => {
|
(HeapCellValueTag::PStrLoc, pstr_loc) => {
|
||||||
let tail = term_stack.pop().unwrap();
|
let tail = term_stack.pop().unwrap();
|
||||||
|
let char_iter = iter.base_iter.heap.char_iter(pstr_loc);
|
||||||
|
|
||||||
match tail {
|
match tail {
|
||||||
Term::Atom(atom) => {
|
Term::Atom(atom) => {
|
||||||
@@ -363,21 +338,18 @@ impl Term {
|
|||||||
term_stack.push(Term::String(atom.as_str().to_string()));
|
term_stack.push(Term::String(atom.as_str().to_string()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Term::List(l) if l.is_empty() => {
|
||||||
|
term_stack.push(Term::String(char_iter.collect()));
|
||||||
|
}
|
||||||
Term::List(l) => {
|
Term::List(l) => {
|
||||||
let mut list: Vec<Term> = atom
|
let mut list: Vec<Term> = char_iter
|
||||||
.as_str()
|
|
||||||
.to_string()
|
|
||||||
.chars()
|
|
||||||
.map(|x| Term::Atom(x.to_string()))
|
.map(|x| Term::Atom(x.to_string()))
|
||||||
.collect();
|
.collect();
|
||||||
list.extend(l.into_iter());
|
list.extend(l.into_iter());
|
||||||
term_stack.push(Term::List(list));
|
term_stack.push(Term::List(list));
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let mut list: Vec<Term> = atom
|
let mut list: Vec<Term> = char_iter
|
||||||
.as_str()
|
|
||||||
.to_string()
|
|
||||||
.chars()
|
|
||||||
.map(|x| Term::Atom(x.to_string()))
|
.map(|x| Term::Atom(x.to_string()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -403,19 +375,6 @@ impl Term {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// I dont know if this is needed here.
|
|
||||||
/*
|
|
||||||
(HeapCellValueTag::PStrLoc, h) => {
|
|
||||||
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
|
|
||||||
let tail = term_stack.pop().unwrap();
|
|
||||||
|
|
||||||
term_stack.push(Term::PartialString(
|
|
||||||
Cell::default(),
|
|
||||||
atom.as_str().to_owned(),
|
|
||||||
Box::new(tail),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
@@ -467,11 +426,20 @@ impl Iterator for QueryState<'_> {
|
|||||||
// this should halt the search for solutions as it
|
// this should halt the search for solutions as it
|
||||||
// does in the Scryer top-level. the exception term is
|
// does in the Scryer top-level. the exception term is
|
||||||
// contained in self.machine_st.ball.
|
// contained in self.machine_st.ball.
|
||||||
let h = machine.machine_st.heap.len();
|
let h = machine.machine_st.heap.cell_len();
|
||||||
machine
|
|
||||||
|
if let Err(resource_err_loc) = machine
|
||||||
.machine_st
|
.machine_st
|
||||||
.heap
|
.heap
|
||||||
.extend(machine.machine_st.ball.stub.clone());
|
.append(&machine.machine_st.ball.stub)
|
||||||
|
{
|
||||||
|
return Some(Err(Term::from_heapcell(
|
||||||
|
machine,
|
||||||
|
machine.machine_st.heap[resource_err_loc],
|
||||||
|
&mut IndexMap::new(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
let exception_term =
|
let exception_term =
|
||||||
Term::from_heapcell(machine, machine.machine_st.heap[h], &mut var_names.clone());
|
Term::from_heapcell(machine, machine.machine_st.heap[h], &mut var_names.clone());
|
||||||
|
|
||||||
@@ -503,7 +471,7 @@ impl Iterator for QueryState<'_> {
|
|||||||
let mut var_name = var_key.to_string();
|
let mut var_name = var_key.to_string();
|
||||||
if var_name.starts_with('_') {
|
if var_name.starts_with('_') {
|
||||||
let should_print = var_names.values().any(|x| match x.borrow().clone() {
|
let should_print = var_names.values().any(|x| match x.borrow().clone() {
|
||||||
Var::Named(v) => v == var_name,
|
Var::Named(v) => *v == *var_name,
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
});
|
||||||
if !should_print {
|
if !should_print {
|
||||||
@@ -522,10 +490,10 @@ impl Iterator for QueryState<'_> {
|
|||||||
// Var dict is in the order things appear in the query. If var_name appears
|
// Var dict is in the order things appear in the query. If var_name appears
|
||||||
// after term in the query, switch their places.
|
// after term in the query, switch their places.
|
||||||
let var_name_idx = var_dict
|
let var_name_idx = var_dict
|
||||||
.get_index_of(&VarKey::VarPtr(Var::Named(var_name.clone()).into()))
|
.get_index_of(&VarKey::VarPtr(Var::from(var_name.clone()).into()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let term_idx =
|
let term_idx =
|
||||||
var_dict.get_index_of(&VarKey::VarPtr(Var::Named(term_str.clone()).into()));
|
var_dict.get_index_of(&VarKey::VarPtr(Var::from(term_str.clone()).into()));
|
||||||
if let Some(idx) = term_idx {
|
if let Some(idx) = term_idx {
|
||||||
if idx < var_name_idx {
|
if idx < var_name_idx {
|
||||||
let new_term = Term::Var(var_name);
|
let new_term = Term::Var(var_name);
|
||||||
@@ -559,7 +527,7 @@ impl Machine {
|
|||||||
/// Consults a module into the [`Machine`] from a string.
|
/// Consults a module into the [`Machine`] from a string.
|
||||||
pub fn consult_module_string(&mut self, module_name: &str, program: impl Into<String>) {
|
pub fn consult_module_string(&mut self, module_name: &str, program: impl Into<String>) {
|
||||||
let stream = Stream::from_owned_string(program.into(), &mut self.machine_st.arena);
|
let stream = Stream::from_owned_string(program.into(), &mut self.machine_st.arena);
|
||||||
self.machine_st.registers[1] = stream.into();
|
self.machine_st.registers[1] = stream_as_cell!(stream);
|
||||||
self.machine_st.registers[2] = atom_as_cell!(&atom_table::AtomTable::build_with(
|
self.machine_st.registers[2] = atom_as_cell!(&atom_table::AtomTable::build_with(
|
||||||
&self.machine_st.atom_tbl,
|
&self.machine_st.atom_tbl,
|
||||||
module_name
|
module_name
|
||||||
@@ -588,7 +556,7 @@ impl Machine {
|
|||||||
or_frame.prelude.attr_var_queue_len = 0;
|
or_frame.prelude.attr_var_queue_len = 0;
|
||||||
|
|
||||||
self.machine_st.b = stub_b;
|
self.machine_st.b = stub_b;
|
||||||
self.machine_st.hb = self.machine_st.heap.len();
|
self.machine_st.hb = self.machine_st.heap.cell_len();
|
||||||
self.machine_st.block = stub_b;
|
self.machine_st.block = stub_b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -606,9 +574,8 @@ impl Machine {
|
|||||||
self.allocate_stub_choice_point();
|
self.allocate_stub_choice_point();
|
||||||
|
|
||||||
// Write parsed term to heap
|
// Write parsed term to heap
|
||||||
let term_write_result =
|
let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap)
|
||||||
write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl)
|
.expect("couldn't write term to heap");
|
||||||
.expect("couldn't write term to heap");
|
|
||||||
|
|
||||||
let var_names: IndexMap<_, _> = term_write_result
|
let var_names: IndexMap<_, _> = term_write_result
|
||||||
.var_dict
|
.var_dict
|
||||||
@@ -630,9 +597,15 @@ impl Machine {
|
|||||||
.indices
|
.indices
|
||||||
.code_dir
|
.code_dir
|
||||||
.get(&(atom!("call"), 1))
|
.get(&(atom!("call"), 1))
|
||||||
.expect("couldn't get code index")
|
.cloned()
|
||||||
.local()
|
.map(|offset| {
|
||||||
.unwrap();
|
self.machine_st
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(offset.into())
|
||||||
|
.p() as usize
|
||||||
|
})
|
||||||
|
.expect("couldn't get code index");
|
||||||
|
|
||||||
self.machine_st.execute_at_index(1, call_index_p);
|
self.machine_st.execute_at_index(1, call_index_p);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use crate::forms::*;
|
|||||||
use crate::machine::loader::*;
|
use crate::machine::loader::*;
|
||||||
use crate::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::machine::preprocessor::*;
|
|
||||||
use crate::machine::term_stream::*;
|
use crate::machine::term_stream::*;
|
||||||
use crate::machine::*;
|
use crate::machine::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
@@ -16,35 +15,38 @@ use std::mem;
|
|||||||
|
|
||||||
pub(super) type ModuleOpExports = Vec<(OpDecl, Option<OpDesc>)>;
|
pub(super) type ModuleOpExports = Vec<(OpDecl, Option<OpDesc>)>;
|
||||||
|
|
||||||
pub(super) fn set_code_index(
|
pub(super) fn set_code_index<'a, LS: LoadState<'a>>(
|
||||||
retraction_info: &mut RetractionInfo,
|
payload: &mut <LS as LoadState<'a>>::LoaderFieldType,
|
||||||
compilation_target: &CompilationTarget,
|
compilation_target: &CompilationTarget,
|
||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
mut code_index: CodeIndex,
|
code_idx: CodeIndex,
|
||||||
code_ptr: IndexPtr,
|
code_ptr: IndexPtr,
|
||||||
) {
|
) {
|
||||||
let record = match compilation_target {
|
let record = LS::machine_st(payload).arena.code_index_tbl.with_entry_mut(
|
||||||
CompilationTarget::User => {
|
code_idx.into(),
|
||||||
if IndexPtrTag::Undefined == code_index.get().tag() {
|
|code_idx_ptr| match compilation_target {
|
||||||
code_index.set(code_ptr);
|
CompilationTarget::User => {
|
||||||
RetractionRecord::AddedUserPredicate(key)
|
if IndexPtrTag::Undefined == code_idx_ptr.tag() {
|
||||||
} else {
|
*code_idx_ptr = code_ptr;
|
||||||
let replaced = code_index.replace(code_ptr);
|
RetractionRecord::AddedUserPredicate(key)
|
||||||
RetractionRecord::ReplacedUserPredicate(key, replaced)
|
} else {
|
||||||
|
let replaced = mem::replace(code_idx_ptr, code_ptr);
|
||||||
|
RetractionRecord::ReplacedUserPredicate(key, replaced)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
CompilationTarget::Module(ref module_name) => {
|
||||||
CompilationTarget::Module(ref module_name) => {
|
if IndexPtrTag::Undefined == code_idx_ptr.tag() {
|
||||||
if IndexPtrTag::Undefined == code_index.get().tag() {
|
*code_idx_ptr = code_ptr;
|
||||||
code_index.set(code_ptr);
|
RetractionRecord::AddedModulePredicate(*module_name, key)
|
||||||
RetractionRecord::AddedModulePredicate(*module_name, key)
|
} else {
|
||||||
} else {
|
let replaced = mem::replace(code_idx_ptr, code_ptr);
|
||||||
let replaced = code_index.replace(code_ptr);
|
RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced)
|
||||||
RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced)
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
);
|
||||||
|
|
||||||
retraction_info.push_record(record);
|
payload.retraction_info.push_record(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_op_decl_as_module_export<'a, LS: LoadState<'a>>(
|
fn add_op_decl_as_module_export<'a, LS: LoadState<'a>>(
|
||||||
@@ -134,21 +136,28 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
|
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
|
||||||
let arena = &mut LS::machine_st(payload).arena;
|
let code_idx_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
||||||
|
|
||||||
let target_code_index = *code_dir
|
let target_code_index = *code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::default(arena));
|
.or_insert_with(|| CodeIndex::default(code_idx_tbl));
|
||||||
|
|
||||||
set_code_index(
|
let src_code_index_ptr = code_idx_tbl.get_entry(src_code_index.into());
|
||||||
&mut payload.retraction_info,
|
|
||||||
|
set_code_index::<LS>(
|
||||||
|
payload,
|
||||||
compilation_target,
|
compilation_target,
|
||||||
key,
|
key,
|
||||||
target_code_index,
|
target_code_index,
|
||||||
src_code_index.get(),
|
src_code_index_ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
if src_code_index.is_dynamic_undefined() {
|
if LS::machine_st(payload)
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(src_code_index.into())
|
||||||
|
.is_dynamic_undefined()
|
||||||
|
{
|
||||||
code_dir.insert(key, src_code_index);
|
code_dir.insert(key, src_code_index);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -190,19 +199,20 @@ fn import_module_exports_into_module<'a, LS: LoadState<'a>>(
|
|||||||
meta_predicates.insert(key, meta_specs.clone());
|
meta_predicates.insert(key, meta_specs.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
|
||||||
let arena = &mut LS::machine_st(payload).arena;
|
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
||||||
|
|
||||||
|
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
|
||||||
let target_code_index = *code_dir
|
let target_code_index = *code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::default(arena));
|
.or_insert_with(|| CodeIndex::default(code_index_tbl));
|
||||||
|
|
||||||
set_code_index(
|
set_code_index::<LS>(
|
||||||
&mut payload.retraction_info,
|
payload,
|
||||||
compilation_target,
|
compilation_target,
|
||||||
key,
|
key,
|
||||||
target_code_index,
|
target_code_index,
|
||||||
src_code_index.get(),
|
src_code_ptr,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Err(SessionError::ModuleDoesNotContainExport(
|
return Err(SessionError::ModuleDoesNotContainExport(
|
||||||
@@ -243,21 +253,21 @@ fn import_qualified_module_exports<'a, LS: LoadState<'a>>(
|
|||||||
.insert(key, meta_specs.clone());
|
.insert(key, meta_specs.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
|
||||||
let arena = &mut LS::machine_st(payload).arena;
|
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
||||||
|
|
||||||
let target_code_index = *wam_prelude
|
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
|
||||||
.indices
|
let target_code_index =
|
||||||
.code_dir
|
*wam_prelude.indices.code_dir.entry(key).or_insert_with(|| {
|
||||||
.entry(key)
|
CodeIndex::new(IndexPtr::undefined(), code_index_tbl)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
|
});
|
||||||
|
|
||||||
set_code_index(
|
set_code_index::<LS>(
|
||||||
&mut payload.retraction_info,
|
payload,
|
||||||
compilation_target,
|
compilation_target,
|
||||||
key,
|
key,
|
||||||
target_code_index,
|
target_code_index,
|
||||||
src_code_index.get(),
|
src_code_ptr,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Err(SessionError::ModuleDoesNotContainExport(
|
return Err(SessionError::ModuleDoesNotContainExport(
|
||||||
@@ -304,19 +314,20 @@ fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>(
|
|||||||
meta_predicates.insert(key, meta_specs.clone());
|
meta_predicates.insert(key, meta_specs.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
|
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
|
||||||
let arena = &mut LS::machine_st(payload).arena;
|
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
||||||
|
|
||||||
|
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
|
||||||
let target_code_index = *code_dir
|
let target_code_index = *code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl));
|
||||||
|
|
||||||
set_code_index(
|
set_code_index::<LS>(
|
||||||
&mut payload.retraction_info,
|
payload,
|
||||||
&payload_compilation_target,
|
&payload_compilation_target,
|
||||||
key,
|
key,
|
||||||
target_code_index,
|
target_code_index,
|
||||||
src_code_index.get(),
|
src_code_ptr,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Err(SessionError::ModuleDoesNotContainExport(
|
return Err(SessionError::ModuleDoesNotContainExport(
|
||||||
@@ -434,19 +445,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
self.retract_local_clauses_impl(clause_clause_compilation_target, key, clause_locs);
|
self.retract_local_clauses_impl(clause_clause_compilation_target, key, clause_locs);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn try_term_to_tl(
|
|
||||||
&mut self,
|
|
||||||
term: Term,
|
|
||||||
preprocessor: &mut Preprocessor,
|
|
||||||
) -> Result<PredicateClause, SessionError> {
|
|
||||||
let tl = preprocessor.try_term_to_tl(self, term)?;
|
|
||||||
|
|
||||||
Ok(match tl {
|
|
||||||
TopLevel::Fact(fact, var_data) => PredicateClause::Fact(fact, var_data),
|
|
||||||
TopLevel::Rule(rule, var_data) => PredicateClause::Rule(rule, var_data),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn remove_module_op_exports(&mut self) {
|
pub(super) fn remove_module_op_exports(&mut self) {
|
||||||
for (mut op_decl, record) in self.payload.module_op_exports.drain(0..) {
|
for (mut op_decl, record) in self.payload.module_op_exports.drain(0..) {
|
||||||
@@ -482,11 +480,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.indices
|
.indices
|
||||||
.get_predicate_skeleton(local_compilation_target, key)
|
.get_predicate_skeleton(local_compilation_target, key)
|
||||||
{
|
{
|
||||||
let old_index_ptr = code_index.replace(if global_skeleton.core.is_dynamic {
|
let old_index_ptr = code_index.replace(
|
||||||
IndexPtr::dynamic_undefined()
|
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
|
||||||
} else {
|
if global_skeleton.core.is_dynamic {
|
||||||
IndexPtr::undefined()
|
IndexPtr::dynamic_undefined()
|
||||||
});
|
} else {
|
||||||
|
IndexPtr::undefined()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
self.payload.retraction_info.push_record(
|
self.payload.retraction_info.push_record(
|
||||||
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
|
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
|
||||||
@@ -500,8 +501,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !code_index.is_undefined() && !code_index.is_dynamic_undefined() {
|
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
|
||||||
let old_index_ptr = code_index.replace(IndexPtr::undefined());
|
let code_ptr = code_index_tbl.get_entry((*code_index).into());
|
||||||
|
|
||||||
|
if !code_ptr.is_undefined() && !code_ptr.is_dynamic_undefined() {
|
||||||
|
let old_index_ptr = code_index.replace(code_index_tbl, IndexPtr::undefined());
|
||||||
|
|
||||||
self.payload.retraction_info.push_record(
|
self.payload.retraction_info.push_record(
|
||||||
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
|
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
|
||||||
@@ -531,27 +535,32 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn remove_module_exports(
|
fn remove_module_exports<'b, LS: LoadState<'b>>(
|
||||||
|
payload: &mut <LS as LoadState<'b>>::LoaderFieldType,
|
||||||
removed_module: &Module,
|
removed_module: &Module,
|
||||||
code_dir: &mut CodeDir,
|
code_dir: &mut CodeDir,
|
||||||
op_dir: &mut OpDir,
|
op_dir: &mut OpDir,
|
||||||
retraction_info: &mut RetractionInfo,
|
|
||||||
predicate_retractor: impl Fn(PredicateKey, IndexPtr) -> RetractionRecord,
|
predicate_retractor: impl Fn(PredicateKey, IndexPtr) -> RetractionRecord,
|
||||||
op_retractor: impl Fn(OpDecl, OpDesc) -> RetractionRecord,
|
op_retractor: impl Fn(OpDecl, OpDesc) -> RetractionRecord,
|
||||||
) {
|
) {
|
||||||
for export in removed_module.module_decl.exports.iter() {
|
for export in removed_module.module_decl.exports.iter() {
|
||||||
match export {
|
match export {
|
||||||
ModuleExport::PredicateKey(ref key) => {
|
ModuleExport::PredicateKey(ref key) => {
|
||||||
match (removed_module.code_dir.get(key), code_dir.get_mut(key)) {
|
if let (Some(module_code_idx), Some(target_code_idx)) = (
|
||||||
(Some(module_code_index), Some(target_code_index))
|
removed_module.code_dir.get(key).cloned(),
|
||||||
if module_code_index.get() == target_code_index.get() =>
|
code_dir.get_mut(key).cloned(),
|
||||||
{
|
) {
|
||||||
|
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
||||||
|
let module_code_ptr = code_index_tbl.get_entry(module_code_idx.into());
|
||||||
|
let target_code_ptr = code_index_tbl.get_entry(target_code_idx.into());
|
||||||
|
|
||||||
|
if module_code_ptr == target_code_ptr {
|
||||||
let old_index_ptr =
|
let old_index_ptr =
|
||||||
target_code_index.replace(IndexPtr::undefined());
|
target_code_idx.replace(code_index_tbl, IndexPtr::undefined());
|
||||||
retraction_info
|
payload
|
||||||
|
.retraction_info
|
||||||
.push_record(predicate_retractor(*key, old_index_ptr));
|
.push_record(predicate_retractor(*key, old_index_ptr));
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ModuleExport::OpDecl(op_decl) => {
|
ModuleExport::OpDecl(op_decl) => {
|
||||||
@@ -559,7 +568,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.swap_remove(&(op_decl.name, op_decl.op_desc.get_spec().fixity()));
|
.swap_remove(&(op_decl.name, op_decl.op_desc.get_spec().fixity()));
|
||||||
|
|
||||||
if let Some(op_desc) = op_dir_value_opt {
|
if let Some(op_desc) = op_dir_value_opt {
|
||||||
retraction_info.push_record(op_retractor(*op_decl, op_desc));
|
payload
|
||||||
|
.retraction_info
|
||||||
|
.push_record(op_retractor(*op_decl, op_desc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -568,11 +579,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
match self.payload.compilation_target {
|
match self.payload.compilation_target {
|
||||||
CompilationTarget::User => {
|
CompilationTarget::User => {
|
||||||
remove_module_exports(
|
remove_module_exports::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
&removed_module,
|
&removed_module,
|
||||||
&mut self.wam_prelude.indices.code_dir,
|
&mut self.wam_prelude.indices.code_dir,
|
||||||
&mut self.wam_prelude.indices.op_dir,
|
&mut self.wam_prelude.indices.op_dir,
|
||||||
&mut self.payload.retraction_info,
|
|
||||||
RetractionRecord::ReplacedUserPredicate,
|
RetractionRecord::ReplacedUserPredicate,
|
||||||
RetractionRecord::ReplacedUserOp,
|
RetractionRecord::ReplacedUserOp,
|
||||||
);
|
);
|
||||||
@@ -592,11 +603,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.modules
|
.modules
|
||||||
.get_mut(&target_module_name)
|
.get_mut(&target_module_name)
|
||||||
{
|
{
|
||||||
remove_module_exports(
|
remove_module_exports::<LS>(
|
||||||
|
&mut self.payload,
|
||||||
&removed_module,
|
&removed_module,
|
||||||
&mut module.code_dir,
|
&mut module.code_dir,
|
||||||
&mut module.op_dir,
|
&mut module.op_dir,
|
||||||
&mut self.payload.retraction_info,
|
|
||||||
predicate_retractor,
|
predicate_retractor,
|
||||||
op_retractor,
|
op_retractor,
|
||||||
);
|
);
|
||||||
@@ -622,7 +633,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| {
|
Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| {
|
||||||
CodeIndex::new(
|
CodeIndex::new(
|
||||||
IndexPtr::undefined(),
|
IndexPtr::undefined(),
|
||||||
&mut LS::machine_st(&mut self.payload).arena,
|
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
None => {
|
None => {
|
||||||
@@ -632,7 +643,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| {
|
Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| {
|
||||||
CodeIndex::new(
|
CodeIndex::new(
|
||||||
IndexPtr::undefined(),
|
IndexPtr::undefined(),
|
||||||
&mut LS::machine_st(&mut self.payload).arena,
|
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
None => {
|
None => {
|
||||||
@@ -648,7 +659,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
compilation_target: CompilationTarget,
|
compilation_target: CompilationTarget,
|
||||||
) -> CodeIndex {
|
) -> CodeIndex {
|
||||||
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
|
||||||
|
|
||||||
match compilation_target {
|
match compilation_target {
|
||||||
CompilationTarget::User => *self
|
CompilationTarget::User => *self
|
||||||
@@ -656,7 +667,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.indices
|
.indices
|
||||||
.code_dir
|
.code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)),
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl)),
|
||||||
CompilationTarget::Module(module_name) => {
|
CompilationTarget::Module(module_name) => {
|
||||||
self.get_or_insert_local_code_index(module_name, key)
|
self.get_or_insert_local_code_index(module_name, key)
|
||||||
}
|
}
|
||||||
@@ -668,15 +679,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
module_name: Atom,
|
module_name: Atom,
|
||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
) -> CodeIndex {
|
) -> CodeIndex {
|
||||||
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
|
||||||
|
|
||||||
if module_name == atom!("user") {
|
if module_name == atom!("user") {
|
||||||
return *self
|
*self
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.code_dir
|
.code_dir
|
||||||
.entry(key)
|
.entry(key)
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl))
|
||||||
} else {
|
} else {
|
||||||
self.get_or_insert_local_code_index(module_name, key)
|
self.get_or_insert_local_code_index(module_name, key)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use std::collections::VecDeque;
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The loader compiles Prolog terms read from a TermStream instance,
|
* The loader compiles Prolog terms read from a TermStream instance,
|
||||||
@@ -382,7 +383,6 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
|
|||||||
let repo_len = loader.wam_prelude.code.len();
|
let repo_len = loader.wam_prelude.code.len();
|
||||||
|
|
||||||
loader.payload.retraction_info.reset(repo_len);
|
loader.payload.retraction_info.reset(repo_len);
|
||||||
|
|
||||||
loader.remove_module_op_exports();
|
loader.remove_module_op_exports();
|
||||||
|
|
||||||
Ok(loader.payload.compilation_target)
|
Ok(loader.payload.compilation_target)
|
||||||
@@ -720,7 +720,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
self.wam_prelude.indices.modules.get_mut(&module_name)
|
self.wam_prelude.indices.modules.get_mut(&module_name)
|
||||||
{
|
{
|
||||||
if let Some(code_idx) = module.code_dir.get_mut(&key) {
|
if let Some(code_idx) = module.code_dir.get_mut(&key) {
|
||||||
code_idx.set(old_code_idx)
|
let code_index_tbl =
|
||||||
|
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
|
||||||
|
code_idx.set(code_index_tbl, old_code_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -741,7 +743,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
}
|
}
|
||||||
RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => {
|
RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => {
|
||||||
if let Some(code_idx) = self.wam_prelude.indices.code_dir.get_mut(&key) {
|
if let Some(code_idx) = self.wam_prelude.indices.code_dir.get_mut(&key) {
|
||||||
code_idx.set(old_code_idx)
|
let code_index_tbl =
|
||||||
|
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
|
||||||
|
code_idx.set(code_index_tbl, old_code_idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RetractionRecord::AddedIndex(index_key, clause_loc) => {
|
RetractionRecord::AddedIndex(index_key, clause_loc) => {
|
||||||
@@ -762,7 +766,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
) => {
|
) => {
|
||||||
remove_constant_indices(
|
remove_constant_indices(
|
||||||
constant,
|
constant,
|
||||||
&overlapping_constants,
|
overlapping_constants,
|
||||||
indexing_code,
|
indexing_code,
|
||||||
clause_loc - index_loc, // WAS: &inner_index_locs,
|
clause_loc - index_loc, // WAS: &inner_index_locs,
|
||||||
);
|
);
|
||||||
@@ -1046,8 +1050,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
let cell = machine_st[r];
|
let cell = machine_st[r];
|
||||||
|
|
||||||
let export_list = machine_st.read_term_from_heap(cell);
|
let export_list = machine_st.read_term_from_heap(cell);
|
||||||
let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl;
|
let export_list = setup_module_export_list(export_list)?;
|
||||||
let export_list = setup_module_export_list(export_list, atom_tbl)?;
|
|
||||||
|
|
||||||
Ok(export_list.into_iter().collect())
|
Ok(export_list.into_iter().collect())
|
||||||
}
|
}
|
||||||
@@ -1060,7 +1063,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
self.payload.clause_clauses.push((head, body));
|
self.payload.clause_clauses.push((head, body));
|
||||||
}
|
}
|
||||||
head @ Term::Literal(_, Literal::Atom(..)) | head @ Term::Clause(..) => {
|
head @ (Term::Clause(..) | Term::Literal(_, Literal::Atom(_))) => {
|
||||||
let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
|
let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
|
||||||
self.payload.clause_clauses.push((head, body));
|
self.payload.clause_clauses.push((head, body));
|
||||||
}
|
}
|
||||||
@@ -1218,14 +1221,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
* but to multifile and discontiguous predicates as well.
|
* but to multifile and discontiguous predicates as well.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let code_index = self.get_or_insert_code_index(key, compilation_target);
|
let offset = self.get_or_insert_code_index(key, compilation_target);
|
||||||
|
let code_idx_ptr = LS::machine_st(&mut self.payload)
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(offset.into());
|
||||||
|
|
||||||
if code_index.is_undefined() {
|
if code_idx_ptr.is_undefined() {
|
||||||
set_code_index(
|
set_code_index::<LS>(
|
||||||
&mut self.payload.retraction_info,
|
&mut self.payload,
|
||||||
&compilation_target,
|
&compilation_target,
|
||||||
key,
|
key,
|
||||||
code_index,
|
offset,
|
||||||
IndexPtr::dynamic_undefined(),
|
IndexPtr::dynamic_undefined(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1289,13 +1296,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
|
fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
|
||||||
if let Some(predicate_name) = ClauseInfo::name(term) {
|
if let Some(predicate_name) = ClauseInfo::name(term) {
|
||||||
let arity = ClauseInfo::arity(term);
|
let predicate_arity = ClauseInfo::arity(term);
|
||||||
let predicates_compilation_target = self.payload.predicates.compilation_target;
|
let predicates_compilation_target = self.payload.predicates.compilation_target;
|
||||||
|
|
||||||
let is_dynamic = self
|
let is_dynamic = self
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_skeleton(&predicates_compilation_target, &(predicate_name, arity))
|
.get_predicate_skeleton(
|
||||||
|
&predicates_compilation_target,
|
||||||
|
&(predicate_name, predicate_arity),
|
||||||
|
)
|
||||||
.map(|skeleton| skeleton.core.is_dynamic)
|
.map(|skeleton| skeleton.core.is_dynamic)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
@@ -1369,8 +1379,9 @@ impl<'a> MachinePreludeView<'a> {
|
|||||||
impl MachineState {
|
impl MachineState {
|
||||||
pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term {
|
pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term {
|
||||||
let mut term_stack = vec![];
|
let mut term_stack = vec![];
|
||||||
|
self.heap[0] = term_addr;
|
||||||
let mut iter =
|
let mut iter =
|
||||||
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term_addr);
|
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
|
||||||
|
|
||||||
while let Some(addr) = iter.next() {
|
while let Some(addr) = iter.next() {
|
||||||
let addr = unmark_cell_bits!(addr);
|
let addr = unmark_cell_bits!(addr);
|
||||||
@@ -1384,45 +1395,31 @@ impl MachineState {
|
|||||||
|
|
||||||
match as_partial_string(head, tail) {
|
match as_partial_string(head, tail) {
|
||||||
Ok((string, Some(tail))) => {
|
Ok((string, Some(tail))) => {
|
||||||
term_stack.push(Term::PartialString(Cell::default(), string, tail));
|
term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail));
|
||||||
}
|
}
|
||||||
Ok((string, None)) => {
|
Ok((string, None)) => {
|
||||||
let atom = AtomTable::build_with(&self.atom_tbl, &string);
|
term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string)));
|
||||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
|
||||||
}
|
}
|
||||||
Err(cons_term) => term_stack.push(cons_term),
|
Err(cons_term) => term_stack.push(cons_term),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64Offset) => {
|
||||||
|
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
|
||||||
|
}
|
||||||
(HeapCellValueTag::StackVar, h) => {
|
(HeapCellValueTag::StackVar, h) => {
|
||||||
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h))));
|
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{h}"))));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
||||||
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
|
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{h}"))));
|
||||||
}
|
|
||||||
(HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
|
|
||||||
HeapCellValueTag::Char | HeapCellValueTag::F64) => {
|
|
||||||
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
|
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
let h = iter.focus().value() as usize;
|
let h = iter.focus().value() as usize;
|
||||||
let mut arity = arity;
|
let mut arity = arity;
|
||||||
|
let value = iter.heap[h.saturating_sub(1)];
|
||||||
|
|
||||||
if iter.heap.len() > h + arity + 1 {
|
if let Some(idx) = get_structure_index(value) {
|
||||||
let value = iter.heap[h + arity + 1];
|
term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndexOffset(idx.into())));
|
||||||
|
arity += 1;
|
||||||
if let Some(idx) = get_structure_index(value) {
|
|
||||||
// in the second condition, arity == 0,
|
|
||||||
// meaning idx cannot pertain to this atom
|
|
||||||
// if it is the direct subterm of a larger
|
|
||||||
// structure.
|
|
||||||
if arity > 0 || !iter.direct_subterm_of_str(h) {
|
|
||||||
term_stack.push(
|
|
||||||
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
|
|
||||||
);
|
|
||||||
|
|
||||||
arity += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if arity == 0 {
|
if arity == 0 {
|
||||||
@@ -1435,28 +1432,22 @@ impl MachineState {
|
|||||||
term_stack.push(Term::Clause(Cell::default(), name, subterms));
|
term_stack.push(Term::Clause(Cell::default(), name, subterms));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStr, atom) => {
|
|
||||||
let tail = term_stack.pop().unwrap();
|
|
||||||
|
|
||||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
|
|
||||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
|
||||||
} else {
|
|
||||||
term_stack.push(Term::PartialString(
|
|
||||||
Cell::default(),
|
|
||||||
atom.as_str().to_owned(),
|
|
||||||
Box::new(tail),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::PStrLoc, h) => {
|
(HeapCellValueTag::PStrLoc, h) => {
|
||||||
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
|
let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h);
|
||||||
let tail = term_stack.pop().unwrap();
|
let tail = term_stack.pop().unwrap();
|
||||||
|
|
||||||
term_stack.push(Term::PartialString(
|
term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) {
|
||||||
Cell::default(),
|
Term::CompleteString(
|
||||||
atom.as_str().to_owned(),
|
Cell::default(),
|
||||||
Box::new(tail),
|
Rc::new(string.to_owned()),
|
||||||
));
|
)
|
||||||
|
} else {
|
||||||
|
Term::PartialString(
|
||||||
|
Cell::default(),
|
||||||
|
Rc::new(string.to_owned()),
|
||||||
|
Box::new(tail),
|
||||||
|
)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
}
|
}
|
||||||
@@ -1605,7 +1596,7 @@ impl Machine {
|
|||||||
let predicate_name = cell_as_atom!(self.deref_register(2));
|
let predicate_name = cell_as_atom!(self.deref_register(2));
|
||||||
|
|
||||||
let arity = self.deref_register(3);
|
let arity = self.deref_register(3);
|
||||||
let arity = match Number::try_from(arity) {
|
let arity = match Number::try_from((arity, &self.machine_st.arena.f64_tbl)) {
|
||||||
Ok(Number::Integer(n)) if *n >= Integer::ZERO && *n <= Integer::from(MAX_ARITY) => {
|
Ok(Number::Integer(n)) if *n >= Integer::ZERO && *n <= Integer::from(MAX_ARITY) => {
|
||||||
let value: usize = (&*n).try_into().unwrap();
|
let value: usize = (&*n).try_into().unwrap();
|
||||||
Ok(value)
|
Ok(value)
|
||||||
@@ -1981,7 +1972,6 @@ impl Machine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let stub_gen = || functor_stub(key.0, key.1);
|
let stub_gen = || functor_stub(key.0, key.1);
|
||||||
|
|
||||||
let head = self.deref_register(2);
|
let head = self.deref_register(2);
|
||||||
|
|
||||||
if head.is_var() {
|
if head.is_var() {
|
||||||
@@ -2017,7 +2007,14 @@ impl Machine {
|
|||||||
.wam_prelude
|
.wam_prelude
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_code_index(name, arity, module_name)
|
.get_predicate_code_index(name, arity, module_name)
|
||||||
.map(|code_idx| code_idx.get_tag())
|
.map(|offset| {
|
||||||
|
loader
|
||||||
|
.payload
|
||||||
|
.machine_st
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.with_entry(offset.into(), |idx| idx.tag())
|
||||||
|
})
|
||||||
.unwrap_or(IndexPtrTag::DynamicUndefined);
|
.unwrap_or(IndexPtrTag::DynamicUndefined);
|
||||||
|
|
||||||
if idx_tag == IndexPtrTag::Index {
|
if idx_tag == IndexPtrTag::Index {
|
||||||
@@ -2123,14 +2120,16 @@ impl Machine {
|
|||||||
.indices
|
.indices
|
||||||
.remove_predicate_skeleton(&compilation_target, &key)
|
.remove_predicate_skeleton(&compilation_target, &key)
|
||||||
.map(|skeleton| {
|
.map(|skeleton| {
|
||||||
let mut clause_clause_skeleton = loader
|
let mut clause_clause_skeleton =
|
||||||
.wam_prelude
|
match loader.wam_prelude.indices.remove_predicate_skeleton(
|
||||||
.indices
|
|
||||||
.remove_predicate_skeleton(
|
|
||||||
&clause_clause_compilation_target,
|
&clause_clause_compilation_target,
|
||||||
&(atom!("$clause"), 2),
|
&(atom!("$clause"), 2),
|
||||||
)
|
) {
|
||||||
.unwrap();
|
Some(skeleton) => skeleton,
|
||||||
|
None => {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let result = skeleton
|
let result = skeleton
|
||||||
.core
|
.core
|
||||||
@@ -2160,9 +2159,16 @@ impl Machine {
|
|||||||
.indices
|
.indices
|
||||||
.remove_predicate_skeleton(&compilation_target, &key);
|
.remove_predicate_skeleton(&compilation_target, &key);
|
||||||
|
|
||||||
let mut code_index = loader.get_or_insert_code_index(key, compilation_target);
|
let offset = loader.get_or_insert_code_index(key, compilation_target);
|
||||||
|
|
||||||
code_index.set(IndexPtr::undefined());
|
loader
|
||||||
|
.payload
|
||||||
|
.machine_st
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.with_entry_mut(offset.into(), |code_idx| {
|
||||||
|
*code_idx = IndexPtr::undefined();
|
||||||
|
});
|
||||||
|
|
||||||
loader.payload.compilation_target = clause_clause_compilation_target;
|
loader.payload.compilation_target = clause_clause_compilation_target;
|
||||||
|
|
||||||
@@ -2192,7 +2198,7 @@ impl Machine {
|
|||||||
.machine_st
|
.machine_st
|
||||||
.store(self.machine_st.deref(self.machine_st[temp_v!(3)]));
|
.store(self.machine_st.deref(self.machine_st[temp_v!(3)]));
|
||||||
|
|
||||||
let target_pos = match Number::try_from(target_pos) {
|
let target_pos = match Number::try_from((target_pos, &self.machine_st.arena.f64_tbl)) {
|
||||||
Ok(Number::Integer(n)) => {
|
Ok(Number::Integer(n)) => {
|
||||||
let value: usize = (&*n).try_into().unwrap();
|
let value: usize = (&*n).try_into().unwrap();
|
||||||
value
|
value
|
||||||
@@ -2342,29 +2348,38 @@ impl Machine {
|
|||||||
.get_meta_predicate_spec(predicate_name, arity, &compilation_target)
|
.get_meta_predicate_spec(predicate_name, arity, &compilation_target)
|
||||||
{
|
{
|
||||||
Some(meta_specs) => {
|
Some(meta_specs) => {
|
||||||
let term_loc = self.machine_st.heap.len();
|
let term_loc = self.machine_st.heap.cell_len();
|
||||||
|
|
||||||
self.machine_st
|
let mut writer = match self.machine_st.heap.reserve(3 + meta_specs.len()) {
|
||||||
.heap
|
Ok(writer) => writer,
|
||||||
.push(atom_as_cell!(predicate_name, arity));
|
Err(err_loc) => {
|
||||||
self.machine_st
|
self.machine_st.throw_resource_error(err_loc);
|
||||||
.heap
|
return;
|
||||||
.extend(meta_specs.iter().map(|meta_spec| match meta_spec {
|
}
|
||||||
MetaSpec::Minus => atom_as_cell!(atom!("+")),
|
};
|
||||||
MetaSpec::Plus => atom_as_cell!(atom!("-")),
|
|
||||||
MetaSpec::Either => atom_as_cell!(atom!("?")),
|
|
||||||
MetaSpec::Colon => atom_as_cell!(atom!(":")),
|
|
||||||
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
|
|
||||||
fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
let heap_loc = self.machine_st.heap.len();
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(atom_as_cell!(predicate_name, arity));
|
||||||
|
|
||||||
self.machine_st
|
for meta_spec in meta_specs.iter() {
|
||||||
.heap
|
section.push_cell(match meta_spec {
|
||||||
.push(atom_as_cell!(atom!("meta_predicate"), 1));
|
MetaSpec::Minus => atom_as_cell!(atom!("+")),
|
||||||
self.machine_st.heap.push(str_loc_as_cell!(term_loc));
|
MetaSpec::Plus => atom_as_cell!(atom!("-")),
|
||||||
|
MetaSpec::Either => atom_as_cell!(atom!("?")),
|
||||||
|
MetaSpec::Colon => atom_as_cell!(atom!(":")),
|
||||||
|
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
|
||||||
|
fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
|
||||||
|
Fixnum::build_with_unchecked(*arg_num as i64)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
section.push_cell(atom_as_cell!(atom!("meta_predicate"), 1));
|
||||||
|
section.push_cell(str_loc_as_cell!(term_loc));
|
||||||
|
});
|
||||||
|
|
||||||
|
let heap_loc = self.machine_st.heap.cell_len() - 2;
|
||||||
|
|
||||||
unify!(
|
unify!(
|
||||||
self.machine_st,
|
self.machine_st,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::parser::ast::*;
|
|||||||
#[cfg(feature = "ffi")]
|
#[cfg(feature = "ffi")]
|
||||||
use crate::ffi::FFIError;
|
use crate::ffi::FFIError;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
|
use crate::functor_macro::*;
|
||||||
use crate::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
use crate::machine::loader::CompilationTarget;
|
use crate::machine::loader::CompilationTarget;
|
||||||
use crate::machine::machine_state::*;
|
use crate::machine::machine_state::*;
|
||||||
@@ -12,20 +13,13 @@ use crate::machine::streams::*;
|
|||||||
use crate::machine::system_calls::BrentAlgState;
|
use crate::machine::system_calls::BrentAlgState;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
pub type MachineStub = Vec<HeapCellValue>;
|
pub type MachineStub = Vec<FunctorElement>;
|
||||||
pub type MachineStubGen = Box<dyn Fn(&mut MachineState) -> MachineStub>;
|
pub type MachineStubGen = Box<dyn Fn(&mut MachineState) -> MachineStub>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum ErrorProvenance {
|
|
||||||
Constructed, // if constructed, offset the addresses.
|
|
||||||
Received, // otherwise, preserve the addresses.
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct MachineError {
|
pub(crate) struct MachineError {
|
||||||
stub: MachineStub,
|
stub: MachineStub,
|
||||||
location: Option<(usize, usize)>, // line_num, col_num
|
location: Option<(usize, usize)>, // line_num, col_num
|
||||||
from: ErrorProvenance,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// from 7.12.2 b) of 13211-1:1995
|
// from 7.12.2 b) of 13211-1:1995
|
||||||
@@ -50,6 +44,7 @@ pub(crate) enum ValidType {
|
|||||||
// PredicateIndicator,
|
// PredicateIndicator,
|
||||||
// Variable
|
// Variable
|
||||||
TcpListener,
|
TcpListener,
|
||||||
|
Process,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValidType {
|
impl ValidType {
|
||||||
@@ -73,6 +68,7 @@ impl ValidType {
|
|||||||
// ValidType::PredicateIndicator => atom!("predicate_indicator"),
|
// ValidType::PredicateIndicator => atom!("predicate_indicator"),
|
||||||
// ValidType::Variable => atom!("variable")
|
// ValidType::Variable => atom!("variable")
|
||||||
ValidType::TcpListener => atom!("tcp_listener"),
|
ValidType::TcpListener => atom!("tcp_listener"),
|
||||||
|
ValidType::Process => atom!("process"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,45 +87,26 @@ impl TypeError for HeapCellValue {
|
|||||||
fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
|
fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("type_error"),
|
atom!("type_error"),
|
||||||
[atom(valid_type.as_atom()), cell(self)]
|
[atom_as_cell((valid_type.as_atom())), cell(self)]
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeError for MachineStub {
|
impl TypeError for MachineStub {
|
||||||
fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
|
fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("type_error"),
|
atom!("type_error"),
|
||||||
[atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
|
[atom_as_cell((valid_type.as_atom())), functor(self)]
|
||||||
[self]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Constructed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeError for FunctorStub {
|
|
||||||
fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
|
|
||||||
let stub = functor!(
|
|
||||||
atom!("type_error"),
|
|
||||||
[atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
|
|
||||||
[self]
|
|
||||||
);
|
|
||||||
|
|
||||||
MachineError {
|
|
||||||
stub,
|
|
||||||
location: None,
|
|
||||||
from: ErrorProvenance::Constructed,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,15 +116,14 @@ impl TypeError for Number {
|
|||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("type_error"),
|
atom!("type_error"),
|
||||||
[
|
[
|
||||||
atom(valid_type.as_atom()),
|
atom_as_cell((valid_type.as_atom())),
|
||||||
number(&mut machine_st.arena, self)
|
number(self, (&mut machine_st.arena))
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,16 +147,15 @@ impl PermissionError for Atom {
|
|||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("permission_error"),
|
atom!("permission_error"),
|
||||||
[
|
[
|
||||||
atom(perm.as_atom()),
|
atom_as_cell((perm.as_atom())),
|
||||||
atom(index_atom),
|
atom_as_cell(index_atom),
|
||||||
cell(atom_as_cell!(self))
|
atom_as_cell(self)
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,13 +189,16 @@ impl PermissionError for HeapCellValue {
|
|||||||
|
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("permission_error"),
|
atom!("permission_error"),
|
||||||
[atom(perm.as_atom()), atom(index_atom), cell(cell)]
|
[
|
||||||
|
atom_as_cell((perm.as_atom())),
|
||||||
|
atom_as_cell(index_atom),
|
||||||
|
cell(cell)
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,24 +206,22 @@ impl PermissionError for HeapCellValue {
|
|||||||
impl PermissionError for MachineStub {
|
impl PermissionError for MachineStub {
|
||||||
fn permission_error(
|
fn permission_error(
|
||||||
self,
|
self,
|
||||||
machine_st: &mut MachineState,
|
_machine_st: &mut MachineState,
|
||||||
index_atom: Atom,
|
index_atom: Atom,
|
||||||
perm: Permission,
|
perm: Permission,
|
||||||
) -> MachineError {
|
) -> MachineError {
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("permission_error"),
|
atom!("permission_error"),
|
||||||
[
|
[
|
||||||
atom(perm.as_atom()),
|
atom_as_cell((perm.as_atom())),
|
||||||
atom(index_atom),
|
atom_as_cell(index_atom),
|
||||||
str(machine_st.heap.len(), 0)
|
functor(self)
|
||||||
],
|
]
|
||||||
[self]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Constructed,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -256,32 +232,14 @@ pub(super) trait DomainError {
|
|||||||
|
|
||||||
impl DomainError for HeapCellValue {
|
impl DomainError for HeapCellValue {
|
||||||
fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
|
fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
|
||||||
let stub = functor!(atom!("domain_error"), [atom(error.as_atom()), cell(self)]);
|
|
||||||
|
|
||||||
MachineError {
|
|
||||||
stub,
|
|
||||||
location: None,
|
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DomainError for FunctorStub {
|
|
||||||
fn domain_error(
|
|
||||||
self,
|
|
||||||
machine_st: &mut MachineState,
|
|
||||||
valid_type: DomainErrorType,
|
|
||||||
) -> MachineError {
|
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("domain_error"),
|
atom!("domain_error"),
|
||||||
[atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
|
[atom_as_cell((error.as_atom())), cell(self)]
|
||||||
[self]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Constructed,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,26 +248,36 @@ impl DomainError for Number {
|
|||||||
fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
|
fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("domain_error"),
|
atom!("domain_error"),
|
||||||
[atom(error.as_atom()), number(&mut machine_st.arena, self)]
|
[
|
||||||
|
atom_as_cell((error.as_atom())),
|
||||||
|
number(self, (&mut machine_st.arena))
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) type FunctorStub = [HeapCellValue; 3];
|
impl DomainError for MachineStub {
|
||||||
|
fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
|
||||||
|
let stub = functor!(
|
||||||
|
atom!("domain_error"),
|
||||||
|
[atom_as_cell((error.as_atom())), functor(self)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub {
|
pub(super) fn functor_stub(name: Atom, arity: usize) -> MachineStub {
|
||||||
[
|
functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)])
|
||||||
atom_as_cell!(atom!("/"), 2),
|
|
||||||
atom_as_cell!(name),
|
|
||||||
fixnum_as_cell!(Fixnum::build_with(arity as i64)),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
@@ -320,37 +288,40 @@ impl MachineState {
|
|||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError {
|
pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError {
|
||||||
let stub = functor!(atom!("evaluation_error"), [atom(eval_error.as_atom())]);
|
let stub = functor!(
|
||||||
|
atom!("evaluation_error"),
|
||||||
|
[atom_as_cell((eval_error.as_atom()))]
|
||||||
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn resource_error(&mut self, err: ResourceError) -> MachineError {
|
pub(super) fn resource_error(err: ResourceError) -> MachineError {
|
||||||
let stub = match err {
|
let stub = match err {
|
||||||
ResourceError::FiniteMemory(size_requested) => {
|
ResourceError::FiniteMemory(size_requested) => {
|
||||||
functor!(
|
functor!(
|
||||||
atom!("resource_error"),
|
atom!("resource_error"),
|
||||||
[atom(atom!("finite_memory")), cell(size_requested)]
|
[atom_as_cell((atom!("finite_memory"))), cell(size_requested)]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ResourceError::OutOfFiles => {
|
ResourceError::OutOfFiles => {
|
||||||
functor!(atom!("resource_error"), [atom(atom!("file_descriptors"))])
|
functor!(
|
||||||
|
atom!("resource_error"),
|
||||||
|
[atom_as_cell((atom!("file_descriptors")))]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,13 +338,12 @@ impl MachineState {
|
|||||||
ExistenceError::Module(name) => {
|
ExistenceError::Module(name) => {
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("existence_error"),
|
atom!("existence_error"),
|
||||||
[atom(atom!("source_sink")), atom(name)]
|
[atom_as_cell((atom!("source_sink"))), atom_as_cell(name)]
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExistenceError::QualifiedProcedure {
|
ExistenceError::QualifiedProcedure {
|
||||||
@@ -381,36 +351,30 @@ impl MachineState {
|
|||||||
name,
|
name,
|
||||||
arity,
|
arity,
|
||||||
} => {
|
} => {
|
||||||
let h = self.heap.len();
|
let ind_stub = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
|
||||||
|
let res_stub = functor!(atom!(":"), [atom_as_cell(module_name), functor(ind_stub)]);
|
||||||
let ind_stub = functor!(atom!("/"), [atom(name), fixnum(arity)]);
|
|
||||||
let res_stub = functor!(atom!(":"), [atom(module_name), str(h + 3, 0)], [ind_stub]);
|
|
||||||
|
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("existence_error"),
|
atom!("existence_error"),
|
||||||
[atom(atom!("procedure")), str(h, 0)],
|
[atom_as_cell((atom!("procedure"))), functor(res_stub)]
|
||||||
[res_stub]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Constructed,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExistenceError::Procedure(name, arity) => {
|
ExistenceError::Procedure(name, arity) => {
|
||||||
let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]);
|
let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
|
||||||
|
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("existence_error"),
|
atom!("existence_error"),
|
||||||
[atom(atom!("procedure")), str(self.heap.len(), 0)],
|
[atom_as_cell((atom!("procedure"))), functor(culprit)]
|
||||||
[culprit]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Constructed,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExistenceError::ModuleSource(source) => {
|
ExistenceError::ModuleSource(source) => {
|
||||||
@@ -418,40 +382,83 @@ impl MachineState {
|
|||||||
|
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("existence_error"),
|
atom!("existence_error"),
|
||||||
[atom(atom!("source_sink")), str(self.heap.len(), 0)],
|
[atom_as_cell((atom!("source_sink"))), functor(source_stub)]
|
||||||
[source_stub]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Constructed,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExistenceError::SourceSink(culprit) => {
|
ExistenceError::SourceSink(culprit) => {
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("existence_error"),
|
atom!("existence_error"),
|
||||||
[atom(atom!("source_sink")), cell(culprit)]
|
[atom_as_cell((atom!("source_sink"))), cell(culprit)]
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExistenceError::Stream(culprit) => {
|
ExistenceError::Stream(culprit) => {
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("existence_error"),
|
atom!("existence_error"),
|
||||||
[atom(atom!("stream")), cell(culprit)]
|
[atom_as_cell((atom!("stream"))), cell(culprit)]
|
||||||
);
|
);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ExistenceError::Process(culprit) => {
|
||||||
|
let stub = functor!(
|
||||||
|
atom!("existence_error"),
|
||||||
|
[atom_as_cell((atom!("process"))), cell(culprit)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn directive_error(&mut self, err: DirectiveError) -> MachineError {
|
||||||
|
match err {
|
||||||
|
DirectiveError::ExpectedDirective(_term) => self.domain_error(
|
||||||
|
DomainErrorType::Directive,
|
||||||
|
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
||||||
|
),
|
||||||
|
DirectiveError::InvalidDirective(name, arity) => {
|
||||||
|
self.domain_error(DomainErrorType::Directive, functor_stub(name, arity))
|
||||||
|
}
|
||||||
|
DirectiveError::InvalidOpDeclNameType(_term) => self.type_error(
|
||||||
|
ValidType::List,
|
||||||
|
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
||||||
|
),
|
||||||
|
DirectiveError::InvalidOpDeclSpecDomain(_term) => self.domain_error(
|
||||||
|
DomainErrorType::OperatorSpecifier,
|
||||||
|
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
||||||
|
),
|
||||||
|
DirectiveError::InvalidOpDeclSpecValue(atom) => {
|
||||||
|
self.domain_error(DomainErrorType::OperatorSpecifier, atom_as_cell!(atom))
|
||||||
|
}
|
||||||
|
DirectiveError::InvalidOpDeclPrecType(_term) => self.type_error(
|
||||||
|
ValidType::Integer,
|
||||||
|
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
||||||
|
),
|
||||||
|
DirectiveError::InvalidOpDeclPrecDomain(num) => {
|
||||||
|
self.domain_error(DomainErrorType::OperatorPriority, fixnum_as_cell!(num))
|
||||||
|
}
|
||||||
|
DirectiveError::ShallNotCreate(atom) => {
|
||||||
|
self.permission_error(Permission::Create, atom!("operator"), atom)
|
||||||
|
}
|
||||||
|
DirectiveError::ShallNotModify(atom) => {
|
||||||
|
self.permission_error(Permission::Modify, atom!("operator"), atom)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,12 +478,11 @@ impl MachineState {
|
|||||||
|
|
||||||
fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
|
fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
|
||||||
match err {
|
match err {
|
||||||
ArithmeticError::UninstantiatedVar => self.instantiation_error(),
|
ArithmeticError::NonEvaluableFunctor(cell, arity) => {
|
||||||
ArithmeticError::NonEvaluableFunctor(literal, arity) => {
|
let culprit = functor!(atom!("/"), [literal(cell), fixnum(arity)]);
|
||||||
let culprit = functor!(atom!("/"), [literal(literal), fixnum(arity)]);
|
|
||||||
|
|
||||||
self.type_error(ValidType::Evaluable, culprit)
|
self.type_error(ValidType::Evaluable, culprit)
|
||||||
}
|
}
|
||||||
|
ArithmeticError::UninstantiatedVar => self.instantiation_error(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +501,6 @@ impl MachineState {
|
|||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,16 +509,12 @@ impl MachineState {
|
|||||||
SessionError::CannotOverwriteBuiltIn(key) => self.permission_error(
|
SessionError::CannotOverwriteBuiltIn(key) => self.permission_error(
|
||||||
Permission::Modify,
|
Permission::Modify,
|
||||||
atom!("static_procedure"),
|
atom!("static_procedure"),
|
||||||
functor_stub(key.0, key.1)
|
functor_stub(key.0, key.1),
|
||||||
.into_iter()
|
|
||||||
.collect::<MachineStub>(),
|
|
||||||
),
|
),
|
||||||
SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error(
|
SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error(
|
||||||
Permission::Modify,
|
Permission::Modify,
|
||||||
atom!("static_procedure"),
|
atom!("static_procedure"),
|
||||||
functor_stub(key.0, key.1)
|
functor_stub(key.0, key.1),
|
||||||
.into_iter()
|
|
||||||
.collect::<MachineStub>(),
|
|
||||||
),
|
),
|
||||||
SessionError::CannotOverwriteBuiltInModule(module) => {
|
SessionError::CannotOverwriteBuiltInModule(module) => {
|
||||||
self.permission_error(Permission::Modify, atom!("static_module"), module)
|
self.permission_error(Permission::Modify, atom!("static_module"), module)
|
||||||
@@ -524,8 +525,7 @@ impl MachineState {
|
|||||||
|
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!("module_does_not_contain_claimed_export"),
|
atom!("module_does_not_contain_claimed_export"),
|
||||||
[atom(module_name), str(self.heap.len() + 4, 0)],
|
[atom_as_cell(module_name), functor(functor_stub)]
|
||||||
[functor_stub]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
self.permission_error(Permission::Access, atom!("private_procedure"), stub)
|
self.permission_error(Permission::Access, atom!("private_procedure"), stub)
|
||||||
@@ -536,7 +536,7 @@ impl MachineState {
|
|||||||
self.permission_error(
|
self.permission_error(
|
||||||
Permission::Modify,
|
Permission::Modify,
|
||||||
atom!("module"),
|
atom!("module"),
|
||||||
functor!(error_atom, [atom(module_name)]),
|
functor!(error_atom, [atom_as_cell(module_name)]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
SessionError::NamelessEntry => {
|
SessionError::NamelessEntry => {
|
||||||
@@ -555,15 +555,12 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
SessionError::CompilationError(err) => self.syntax_error(err),
|
SessionError::CompilationError(err) => self.syntax_error(err),
|
||||||
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
|
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
|
||||||
let functor_stub = functor_stub(key.0, key.1);
|
|
||||||
|
|
||||||
let stub = functor!(
|
let stub = functor!(
|
||||||
atom!(":"),
|
atom!(":"),
|
||||||
[
|
[
|
||||||
atom(compilation_target.module_name()),
|
atom_as_cell((compilation_target.module_name())),
|
||||||
str(self.heap.len() + 4, 0)
|
functor((key.0), [fixnum((key.1))])
|
||||||
],
|
]
|
||||||
[functor_stub]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
self.permission_error(
|
self.permission_error(
|
||||||
@@ -587,30 +584,36 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let location = err.line_and_col_num();
|
let location = err.line_and_col_num();
|
||||||
let len = self.heap.len();
|
|
||||||
let stub = err.as_functor();
|
let stub = err.as_functor();
|
||||||
|
|
||||||
let stub = functor!(atom!("syntax_error"), [str(len, 0)], [stub]);
|
let stub = functor!(atom!("syntax_error"), [functor(stub)]);
|
||||||
|
|
||||||
MachineError {
|
MachineError { stub, location }
|
||||||
stub,
|
|
||||||
location,
|
|
||||||
from: ErrorProvenance::Constructed,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn representation_error(&mut self, flag: RepFlag) -> MachineError {
|
pub(super) fn representation_error(&self, flag: RepFlag) -> MachineError {
|
||||||
let stub = functor!(atom!("representation_error"), [atom(flag.as_atom())]);
|
let stub = functor!(
|
||||||
|
atom!("representation_error"),
|
||||||
|
[atom_as_cell((flag.as_atom()))]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn unreachable_error(&self) -> MachineError {
|
||||||
|
let stub = functor!(atom!("system_error"));
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Received,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ffi")]
|
#[cfg(feature = "ffi")]
|
||||||
pub(super) fn ffi_error(&mut self, err: FFIError) -> MachineError {
|
pub(super) fn ffi_error(&self, err: FFIError) -> MachineError {
|
||||||
let error_atom = match err {
|
let error_atom = match err {
|
||||||
FFIError::ValueCast => atom!("value_cast"),
|
FFIError::ValueCast => atom!("value_cast"),
|
||||||
FFIError::ValueDontFit => atom!("value_dont_fit"),
|
FFIError::ValueDontFit => atom!("value_dont_fit"),
|
||||||
@@ -619,62 +622,50 @@ impl MachineState {
|
|||||||
FFIError::FunctionNotFound => atom!("function_not_found"),
|
FFIError::FunctionNotFound => atom!("function_not_found"),
|
||||||
FFIError::StructNotFound => atom!("struct_not_found"),
|
FFIError::StructNotFound => atom!("struct_not_found"),
|
||||||
};
|
};
|
||||||
let stub = functor!(atom!("ffi_error"), [atom(error_atom)]);
|
let stub = functor!(atom!("ffi_error"), [atom_as_cell(error_atom)]);
|
||||||
|
|
||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Constructed,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub {
|
pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub {
|
||||||
let h = self.heap.len();
|
if let Some((line_num, _col_num)) = err.location {
|
||||||
let location = err.location;
|
functor!(
|
||||||
let stub_addition_len = if err.len() == 1 {
|
atom!("error"),
|
||||||
0 // if err contains 1 cell, it can be inlined at stub[1].
|
[
|
||||||
|
functor((err.stub)),
|
||||||
|
functor(
|
||||||
|
(atom!(":")),
|
||||||
|
[functor(src), number(line_num, (&mut self.arena))]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
err.len()
|
functor!(atom!("error"), [functor((err.stub)), functor(src)])
|
||||||
};
|
|
||||||
|
|
||||||
let mut stub = vec![
|
|
||||||
atom_as_cell!(atom!("error"), 2),
|
|
||||||
str_loc_as_cell!(h + 3),
|
|
||||||
str_loc_as_cell!(h + 3 + stub_addition_len),
|
|
||||||
];
|
|
||||||
|
|
||||||
if stub_addition_len > 0 {
|
|
||||||
stub.extend(err.into_iter(3));
|
|
||||||
} else {
|
|
||||||
stub[1] = err.stub[0];
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((line_num, _)) = location {
|
// throw an error pre-allocated in the heap
|
||||||
stub.push(atom_as_cell!(atom!(":"), 2));
|
pub(super) fn throw_resource_error(&mut self, err_loc: usize) {
|
||||||
stub.push(str_loc_as_cell!(h + 6 + stub_addition_len));
|
self.registers[1] = str_loc_as_cell!(err_loc);
|
||||||
stub.push(integer_as_cell!(Number::arena_from(
|
self.set_ball();
|
||||||
line_num,
|
self.unwind_stack();
|
||||||
&mut self.arena
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
stub.extend(src.iter());
|
|
||||||
stub
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn throw_exception(&mut self, err: MachineStub) {
|
pub(super) fn throw_exception(&mut self, err: MachineStub) {
|
||||||
let h = self.heap.len();
|
|
||||||
let err_len = err.len();
|
|
||||||
|
|
||||||
self.ball.boundary = 0;
|
self.ball.boundary = 0;
|
||||||
self.ball.stub.truncate(0);
|
self.ball.stub.truncate(0);
|
||||||
|
|
||||||
self.heap.extend(err);
|
let mut writer = Heap::functor_writer(err);
|
||||||
|
|
||||||
self.registers[1] = if err_len == 1 {
|
self.registers[1] = match writer(&mut self.heap) {
|
||||||
heap_loc_as_cell!(h)
|
Ok(loc) => loc,
|
||||||
} else {
|
Err(resource_err_loc) => {
|
||||||
str_loc_as_cell!(h)
|
self.throw_resource_error(resource_err_loc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.set_ball();
|
self.set_ball();
|
||||||
@@ -682,21 +673,6 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineError {
|
|
||||||
fn into_iter(self, offset: usize) -> Box<dyn Iterator<Item = HeapCellValue>> {
|
|
||||||
match self.from {
|
|
||||||
ErrorProvenance::Constructed => {
|
|
||||||
Box::new(self.stub.into_iter().map(move |hcv| hcv + offset))
|
|
||||||
}
|
|
||||||
ErrorProvenance::Received => Box::new(self.stub.into_iter()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.stub.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CompilationError {
|
pub enum CompilationError {
|
||||||
Arithmetic(ArithmeticError),
|
Arithmetic(ArithmeticError),
|
||||||
@@ -711,6 +687,7 @@ pub enum CompilationError {
|
|||||||
InvalidRuleHead,
|
InvalidRuleHead,
|
||||||
InvalidUseModuleDecl,
|
InvalidUseModuleDecl,
|
||||||
InvalidModuleResolution(Atom),
|
InvalidModuleResolution(Atom),
|
||||||
|
FiniteMemoryInHeap(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -757,11 +734,9 @@ impl CompilationError {
|
|||||||
functor!(atom!("exceeded_max_arity"))
|
functor!(atom!("exceeded_max_arity"))
|
||||||
}
|
}
|
||||||
CompilationError::InadmissibleFact => {
|
CompilationError::InadmissibleFact => {
|
||||||
// TODO: type_error(callable, _).
|
|
||||||
functor!(atom!("inadmissible_fact"))
|
functor!(atom!("inadmissible_fact"))
|
||||||
}
|
}
|
||||||
CompilationError::InadmissibleQueryTerm => {
|
CompilationError::InadmissibleQueryTerm => {
|
||||||
// TODO: type_error(callable, _).
|
|
||||||
functor!(atom!("inadmissible_query_term"))
|
functor!(atom!("inadmissible_query_term"))
|
||||||
}
|
}
|
||||||
CompilationError::InvalidDirective(_) => {
|
CompilationError::InvalidDirective(_) => {
|
||||||
@@ -776,8 +751,8 @@ impl CompilationError {
|
|||||||
CompilationError::InvalidModuleExport => {
|
CompilationError::InvalidModuleExport => {
|
||||||
functor!(atom!("invalid_module_export"))
|
functor!(atom!("invalid_module_export"))
|
||||||
}
|
}
|
||||||
CompilationError::InvalidModuleResolution(ref module_name) => {
|
&CompilationError::InvalidModuleResolution(module_name) => {
|
||||||
functor!(atom!("no_such_module"), [atom(module_name)])
|
functor!(atom!("no_such_module"), [atom_as_cell(module_name)])
|
||||||
}
|
}
|
||||||
CompilationError::InvalidRuleHead => {
|
CompilationError::InvalidRuleHead => {
|
||||||
functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
|
functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
|
||||||
@@ -788,6 +763,9 @@ impl CompilationError {
|
|||||||
CompilationError::ParserError(ref err) => {
|
CompilationError::ParserError(ref err) => {
|
||||||
functor!(err.as_atom())
|
functor!(err.as_atom())
|
||||||
}
|
}
|
||||||
|
CompilationError::FiniteMemoryInHeap(h) => {
|
||||||
|
vec![FunctorElement::AbsoluteCell(str_loc_as_cell!(*h))]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -896,14 +874,29 @@ impl EvalError {
|
|||||||
// used by '$skip_max_list'.
|
// used by '$skip_max_list'.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum CycleSearchResult {
|
pub enum CycleSearchResult {
|
||||||
Cyclic(usize),
|
Cyclic {
|
||||||
|
lambda: usize,
|
||||||
|
}, // number of steps
|
||||||
EmptyList,
|
EmptyList,
|
||||||
NotList(usize, HeapCellValue), // the list length until the second argument in the heap
|
NotList {
|
||||||
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
|
num_steps: usize,
|
||||||
ProperList(usize), // the list length.
|
heap_loc: HeapCellValue,
|
||||||
PStrLocation(usize, usize, usize), // list length (up to max), the heap address of the PStr, the offset
|
},
|
||||||
UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address).
|
PartialList {
|
||||||
UntouchedCStr(Atom, usize),
|
num_steps: usize,
|
||||||
|
heap_loc: HeapCellValue,
|
||||||
|
},
|
||||||
|
ProperList {
|
||||||
|
num_steps: usize,
|
||||||
|
},
|
||||||
|
PStrLocation {
|
||||||
|
num_steps: usize,
|
||||||
|
pstr_loc: HeapCellValue,
|
||||||
|
},
|
||||||
|
UntouchedList {
|
||||||
|
num_steps: usize,
|
||||||
|
list_loc: usize,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
@@ -915,11 +908,11 @@ impl MachineState {
|
|||||||
let sorted = self.store(self.deref(self.registers[2]));
|
let sorted = self.store(self.deref(self.registers[2]));
|
||||||
|
|
||||||
match BrentAlgState::detect_cycles(&self.heap, list) {
|
match BrentAlgState::detect_cycles(&self.heap, list) {
|
||||||
CycleSearchResult::PartialList(..) => {
|
CycleSearchResult::PartialList { .. } => {
|
||||||
let err = self.instantiation_error();
|
let err = self.instantiation_error();
|
||||||
return Err(self.error_form(err, stub_gen()));
|
return Err(self.error_form(err, stub_gen()));
|
||||||
}
|
}
|
||||||
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
|
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => {
|
||||||
let err = self.type_error(ValidType::List, list);
|
let err = self.type_error(ValidType::List, list);
|
||||||
return Err(self.error_form(err, stub_gen()));
|
return Err(self.error_form(err, stub_gen()));
|
||||||
}
|
}
|
||||||
@@ -927,7 +920,9 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match BrentAlgState::detect_cycles(&self.heap, sorted) {
|
match BrentAlgState::detect_cycles(&self.heap, sorted) {
|
||||||
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !sorted.is_var() => {
|
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. }
|
||||||
|
if !sorted.is_var() =>
|
||||||
|
{
|
||||||
let err = self.type_error(ValidType::List, sorted);
|
let err = self.type_error(ValidType::List, sorted);
|
||||||
Err(self.error_form(err, stub_gen()))
|
Err(self.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
@@ -939,7 +934,9 @@ impl MachineState {
|
|||||||
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
||||||
|
|
||||||
match BrentAlgState::detect_cycles(&self.heap, list) {
|
match BrentAlgState::detect_cycles(&self.heap, list) {
|
||||||
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !list.is_var() => {
|
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. }
|
||||||
|
if !list.is_var() =>
|
||||||
|
{
|
||||||
let err = self.type_error(ValidType::List, list);
|
let err = self.type_error(ValidType::List, list);
|
||||||
Err(self.error_form(err, stub_gen()))
|
Err(self.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
@@ -1001,11 +998,11 @@ impl MachineState {
|
|||||||
let sorted = self.store(self.deref(self[temp_v!(2)]));
|
let sorted = self.store(self.deref(self[temp_v!(2)]));
|
||||||
|
|
||||||
match BrentAlgState::detect_cycles(&self.heap, pairs) {
|
match BrentAlgState::detect_cycles(&self.heap, pairs) {
|
||||||
CycleSearchResult::PartialList(..) => {
|
CycleSearchResult::PartialList { .. } => {
|
||||||
let err = self.instantiation_error();
|
let err = self.instantiation_error();
|
||||||
Err(self.error_form(err, stub_gen()))
|
Err(self.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
|
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => {
|
||||||
let err = self.type_error(ValidType::List, pairs);
|
let err = self.type_error(ValidType::List, pairs);
|
||||||
Err(self.error_form(err, stub_gen()))
|
Err(self.error_form(err, stub_gen()))
|
||||||
}
|
}
|
||||||
@@ -1028,6 +1025,7 @@ pub enum ExistenceError {
|
|||||||
},
|
},
|
||||||
SourceSink(HeapCellValue),
|
SourceSink(HeapCellValue),
|
||||||
Stream(HeapCellValue),
|
Stream(HeapCellValue),
|
||||||
|
Process(HeapCellValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
|
|
||||||
use crate::arena::*;
|
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::machine::loader::*;
|
use crate::machine::loader::*;
|
||||||
@@ -10,6 +9,7 @@ use crate::machine::machine_state::*;
|
|||||||
use crate::machine::streams::{Stream, StreamOptions};
|
use crate::machine::streams::{Stream, StreamOptions};
|
||||||
use crate::machine::ClauseType;
|
use crate::machine::ClauseType;
|
||||||
use crate::machine::MachineStubGen;
|
use crate::machine::MachineStubGen;
|
||||||
|
use crate::offset_table::*;
|
||||||
|
|
||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
@@ -18,7 +18,6 @@ use scryer_modular_bitfield::{bitfield, BitfieldSpecifier};
|
|||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
|
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
@@ -126,10 +125,19 @@ impl IndexPtr {
|
|||||||
pub(crate) fn is_dynamic_undefined(&self) -> bool {
|
pub(crate) fn is_dynamic_undefined(&self) -> bool {
|
||||||
matches!(self.tag(), IndexPtrTag::DynamicUndefined)
|
matches!(self.tag(), IndexPtrTag::DynamicUndefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn local(&self) -> Option<usize> {
|
||||||
|
match self.tag() {
|
||||||
|
IndexPtrTag::Index => Some(self.p() as usize),
|
||||||
|
IndexPtrTag::DynamicIndex => Some(self.p() as usize),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy)] // , Ord, Hash, PartialOrd, Eq, PartialEq)]
|
||||||
pub struct CodeIndex(TypedArenaPtr<IndexPtr>);
|
pub struct CodeIndex(CodeIndexOffset);
|
||||||
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
const_assert!(std::mem::align_of::<CodeIndex>() == 4);
|
const_assert!(std::mem::align_of::<CodeIndex>() == 4);
|
||||||
@@ -137,78 +145,53 @@ const_assert!(std::mem::align_of::<CodeIndex>() == 4);
|
|||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
const_assert!(std::mem::align_of::<CodeIndex>() == 8);
|
const_assert!(std::mem::align_of::<CodeIndex>() == 8);
|
||||||
|
|
||||||
impl Deref for CodeIndex {
|
impl From<CodeIndex> for HeapCellValue {
|
||||||
type Target = TypedArenaPtr<IndexPtr>;
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn deref(&self) -> &TypedArenaPtr<IndexPtr> {
|
fn from(idx: CodeIndex) -> HeapCellValue {
|
||||||
&self.0
|
HeapCellValue::from(idx.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for CodeIndex {
|
impl From<CodeIndexOffset> for CodeIndex {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn deref_mut(&mut self) -> &mut TypedArenaPtr<IndexPtr> {
|
fn from(offset: CodeIndexOffset) -> CodeIndex {
|
||||||
&mut self.0
|
CodeIndex(offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CodeIndex> for UntypedArenaPtr {
|
impl From<CodeIndex> for CodeIndexOffset {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(ptr: CodeIndex) -> UntypedArenaPtr {
|
fn from(value: CodeIndex) -> CodeIndexOffset {
|
||||||
UntypedArenaPtr::build_with(ptr.0.as_ptr() as usize)
|
value.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TypedArenaPtr<IndexPtr>> for CodeIndex {
|
impl From<&'_ CodeIndex> for CodeIndexOffset {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(ptr: TypedArenaPtr<IndexPtr>) -> CodeIndex {
|
fn from(value: &'_ CodeIndex) -> CodeIndexOffset {
|
||||||
CodeIndex(ptr)
|
value.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeIndex {
|
impl CodeIndex {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self {
|
pub(crate) fn new(ptr: IndexPtr, code_index_tbl: &mut CodeIndexTable) -> Self {
|
||||||
CodeIndex(arena_alloc!(ptr, arena))
|
CodeIndex(code_index_tbl.build_with(ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn default(arena: &mut Arena) -> Self {
|
pub(crate) fn default(code_index_tbl: &mut CodeIndexTable) -> Self {
|
||||||
CodeIndex::new(IndexPtr::undefined(), arena)
|
CodeIndex::new(IndexPtr::undefined(), code_index_tbl)
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn local(&self) -> Option<usize> {
|
|
||||||
match self.0.tag() {
|
|
||||||
IndexPtrTag::Index => Some(self.0.p() as usize),
|
|
||||||
IndexPtrTag::DynamicIndex => Some(self.0.p() as usize),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get(&self) -> IndexPtr {
|
pub(crate) fn set(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) {
|
||||||
*self.0.deref()
|
code_index_tbl.with_entry_mut(self.0, |idx| *idx = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn set(&mut self, value: IndexPtr) {
|
pub(crate) fn replace(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) -> IndexPtr {
|
||||||
*self.0.deref_mut() = value;
|
code_index_tbl.with_entry_mut(self.0, |idx| std::mem::replace(idx, value))
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) fn get_tag(self) -> IndexPtrTag {
|
|
||||||
self.0.tag()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr {
|
|
||||||
std::mem::replace(self.0.deref_mut(), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) fn as_ptr(&self) -> *const IndexPtr {
|
|
||||||
self.0.as_ptr()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +206,7 @@ impl VarKey {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn to_string(&self) -> String {
|
pub(crate) fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
VarKey::AnonVar(h) => format!("_{}", h),
|
VarKey::AnonVar(h) => format!("_{h}"),
|
||||||
VarKey::VarPtr(var) => var.borrow().to_string(),
|
VarKey::VarPtr(var) => var.borrow().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -543,7 +526,7 @@ impl IndexStore {
|
|||||||
&'a self,
|
&'a self,
|
||||||
range: R,
|
range: R,
|
||||||
) -> impl Iterator<Item = Stream> + 'a {
|
) -> impl Iterator<Item = Stream> + 'a {
|
||||||
self.streams.range(range).into_iter().copied()
|
self.streams.range(range).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forcibly sets `alias` to `stream`.
|
/// Forcibly sets `alias` to `stream`.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
|
use crate::functor_macro::*;
|
||||||
use crate::heap_iter::*;
|
use crate::heap_iter::*;
|
||||||
use crate::heap_print::*;
|
use crate::heap_print::*;
|
||||||
use crate::machine::attributed_variables::*;
|
use crate::machine::attributed_variables::*;
|
||||||
@@ -21,7 +22,7 @@ use indexmap::IndexMap;
|
|||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut, Range};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
|
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
|
||||||
@@ -35,8 +36,8 @@ pub(super) enum MachineMode {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) enum HeapPtr {
|
pub(super) enum HeapPtr {
|
||||||
HeapCell(usize),
|
HeapCell(usize),
|
||||||
PStrChar(usize, usize),
|
PStr(usize), // Char(usize),
|
||||||
PStrLocation(usize, usize),
|
// PStrLocation(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HeapPtr {
|
impl Default for HeapPtr {
|
||||||
@@ -183,47 +184,62 @@ impl IndexMut<RegType> for MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type CallResult = Result<(), Vec<HeapCellValue>>;
|
pub type CallResult = Result<(), Vec<FunctorElement>>;
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) {
|
|
||||||
read_heap_cell!(heap[index],
|
|
||||||
(HeapCellValueTag::PStr | HeapCellValueTag::CStr) => {
|
|
||||||
(index, Fixnum::build_with(0))
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::PStrOffset, h) => {
|
|
||||||
(h, cell_as_fixnum!(heap[index+1]))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// size may be an upper bound.
|
||||||
|
// true_size is calculated to compute the exact offset.
|
||||||
fn push_var_eq_functors<'a>(
|
fn push_var_eq_functors<'a>(
|
||||||
heap: &mut Heap,
|
heap: &mut Heap,
|
||||||
|
size: usize,
|
||||||
iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
|
iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
|
||||||
atom_tbl: &AtomTable,
|
atom_tbl: &AtomTable,
|
||||||
) -> Vec<HeapCellValue> {
|
) -> Result<HeapCellValue, usize> {
|
||||||
let mut list_of_var_eqs = vec![];
|
let src_h = heap.cell_len();
|
||||||
|
|
||||||
for (var, binding) in iter {
|
let true_size = if size > 0 {
|
||||||
let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
|
let mut writer = heap.reserve(2 + 5 * size)?;
|
||||||
let h = heap.len();
|
|
||||||
|
|
||||||
heap.push(atom_as_cell!(atom!("="), 2));
|
writer
|
||||||
heap.push(atom_as_cell!(var_atom));
|
.write_with(|section| {
|
||||||
heap.push(*binding);
|
let mut size = 0;
|
||||||
|
|
||||||
list_of_var_eqs.push(str_loc_as_cell!(h));
|
for (var, binding) in iter {
|
||||||
}
|
let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
|
||||||
|
|
||||||
list_of_var_eqs
|
section.push_cell(atom_as_cell!(atom!("="), 2));
|
||||||
|
section.push_cell(atom_as_cell!(var_atom));
|
||||||
|
section.push_cell(*binding);
|
||||||
|
|
||||||
|
size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx in 0..size {
|
||||||
|
section.push_cell(list_loc_as_cell!(section.cell_len() + 1));
|
||||||
|
section.push_cell(str_loc_as_cell!(src_h + 3 * idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
if size > 0 {
|
||||||
|
section.push_cell(empty_list_as_cell!());
|
||||||
|
}
|
||||||
|
|
||||||
|
size
|
||||||
|
})
|
||||||
|
.result
|
||||||
|
} else {
|
||||||
|
size
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(if true_size > 0 {
|
||||||
|
heap_loc_as_cell!(src_h + 3 * true_size)
|
||||||
|
} else {
|
||||||
|
empty_list_as_cell!()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Ball {
|
pub struct Ball {
|
||||||
pub(super) boundary: usize,
|
pub(super) boundary: usize,
|
||||||
|
pub(super) pstr_boundary: usize,
|
||||||
pub(super) stub: Heap,
|
pub(super) stub: Heap,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,23 +247,44 @@ impl Ball {
|
|||||||
pub(super) fn new() -> Self {
|
pub(super) fn new() -> Self {
|
||||||
Ball {
|
Ball {
|
||||||
boundary: 0,
|
boundary: 0,
|
||||||
|
pstr_boundary: 0,
|
||||||
stub: Heap::new(),
|
stub: Heap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn reset(&mut self) {
|
pub(super) fn reset(&mut self) {
|
||||||
self.boundary = 0;
|
self.boundary = 0;
|
||||||
|
self.pstr_boundary = 0;
|
||||||
self.stub.clear();
|
self.stub.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn copy_and_align(&self, h: usize) -> Heap {
|
pub(super) fn copy_and_align_to(&self, dest: &mut Heap) -> Result<usize, usize> {
|
||||||
|
let h = dest.cell_len();
|
||||||
let diff = self.boundary as i64 - h as i64;
|
let diff = self.boundary as i64 - h as i64;
|
||||||
|
|
||||||
self.stub
|
let mut dest_writer = dest.reserve(self.stub.cell_len())?;
|
||||||
.iter()
|
|
||||||
.cloned()
|
dest_writer.write_with(|section| {
|
||||||
.map(|heap_value| heap_value - diff)
|
for idx in 0..self.pstr_boundary {
|
||||||
.collect()
|
section.push_cell(self.stub[idx] - diff);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut pstr_threshold = heap_index!(self.pstr_boundary);
|
||||||
|
|
||||||
|
while pstr_threshold < heap_index!(self.stub.cell_len()) {
|
||||||
|
let HeapStringScan { string, tail_idx } = self.stub.scan_slice_to_str(pstr_threshold);
|
||||||
|
|
||||||
|
pstr_threshold += dest_writer
|
||||||
|
.write_with(|section| {
|
||||||
|
if section.push_pstr(string).is_some() {
|
||||||
|
section.push_cell(self.stub[tail_idx] - diff);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,21 +316,6 @@ impl<'a> IndexMut<usize> for CopyTerm<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CopierTarget for CopyTerm<'a> {
|
impl<'a> CopierTarget for CopyTerm<'a> {
|
||||||
#[inline(always)]
|
|
||||||
fn threshold(&self) -> usize {
|
|
||||||
self.state.heap.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn push(&mut self, hcv: HeapCellValue) {
|
|
||||||
self.state.heap.push(hcv);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
|
||||||
self.state.attr_var_init.attr_var_queue.push(attr_var_loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
||||||
self.state.store(value)
|
self.state.store(value)
|
||||||
@@ -304,10 +326,40 @@ impl<'a> CopierTarget for CopyTerm<'a> {
|
|||||||
self.state.deref(value)
|
self.state.deref(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
||||||
|
self.state.attr_var_init.attr_var_queue.push(attr_var_loc);
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn stack(&mut self) -> &mut Stack {
|
fn stack(&mut self) -> &mut Stack {
|
||||||
&mut self.state.stack
|
&mut self.state.stack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn threshold(&self) -> usize {
|
||||||
|
self.state.heap.cell_len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_slice_from<'b>(&'b self, from: usize) -> Box<dyn Iterator<Item = u8> + 'b> {
|
||||||
|
Box::new(self.state.heap.as_slice()[from..].iter().cloned())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
|
||||||
|
self.state.heap.copy_pstr_within(pstr_loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize> {
|
||||||
|
self.state.heap.reserve(num_cells)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
|
||||||
|
self.state.heap.copy_slice_to_end(bounds)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -315,7 +367,6 @@ pub(super) struct CopyBallTerm<'a> {
|
|||||||
attr_var_queue: &'a mut Vec<usize>,
|
attr_var_queue: &'a mut Vec<usize>,
|
||||||
stack: &'a mut Stack,
|
stack: &'a mut Stack,
|
||||||
heap: &'a mut Heap,
|
heap: &'a mut Heap,
|
||||||
heap_boundary: usize,
|
|
||||||
stub: &'a mut Heap,
|
stub: &'a mut Heap,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,13 +377,10 @@ impl<'a> CopyBallTerm<'a> {
|
|||||||
heap: &'a mut Heap,
|
heap: &'a mut Heap,
|
||||||
stub: &'a mut Heap,
|
stub: &'a mut Heap,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let hb = heap.len();
|
|
||||||
|
|
||||||
CopyBallTerm {
|
CopyBallTerm {
|
||||||
attr_var_queue,
|
attr_var_queue,
|
||||||
stack,
|
stack,
|
||||||
heap,
|
heap,
|
||||||
heap_boundary: hb,
|
|
||||||
stub,
|
stub,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,10 +390,10 @@ impl<'a> Index<usize> for CopyBallTerm<'a> {
|
|||||||
type Output = HeapCellValue;
|
type Output = HeapCellValue;
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
if index < self.heap_boundary {
|
if index < self.heap.cell_len() {
|
||||||
&self.heap[index]
|
&self.heap[index]
|
||||||
} else {
|
} else {
|
||||||
let index = index - self.heap_boundary;
|
let index = index - self.heap.cell_len();
|
||||||
&self.stub[index]
|
&self.stub[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,10 +401,10 @@ impl<'a> Index<usize> for CopyBallTerm<'a> {
|
|||||||
|
|
||||||
impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
|
impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
if index < self.heap_boundary {
|
if index < self.heap.cell_len() {
|
||||||
&mut self.heap[index]
|
&mut self.heap[index]
|
||||||
} else {
|
} else {
|
||||||
let index = index - self.heap_boundary;
|
let index = index - self.heap.cell_len();
|
||||||
&mut self.stub[index]
|
&mut self.stub[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,11 +412,7 @@ impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
|
|||||||
|
|
||||||
impl<'a> CopierTarget for CopyBallTerm<'a> {
|
impl<'a> CopierTarget for CopyBallTerm<'a> {
|
||||||
fn threshold(&self) -> usize {
|
fn threshold(&self) -> usize {
|
||||||
self.heap_boundary + self.stub.len()
|
self.heap.cell_len() + self.stub.cell_len()
|
||||||
}
|
|
||||||
|
|
||||||
fn push(&mut self, value: HeapCellValue) {
|
|
||||||
self.stub.push(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -379,10 +423,10 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
|
|||||||
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
||||||
read_heap_cell!(value,
|
read_heap_cell!(value,
|
||||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
||||||
if h < self.heap_boundary {
|
if h < self.heap.cell_len() {
|
||||||
self.heap[h]
|
self.heap[h]
|
||||||
} else {
|
} else {
|
||||||
let index = h - self.heap_boundary;
|
let index = h - self.heap.cell_len();
|
||||||
self.stub[index]
|
self.stub[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,6 +455,45 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
|
|||||||
fn stack(&mut self) -> &mut Stack {
|
fn stack(&mut self) -> &mut Stack {
|
||||||
self.stack
|
self.stack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
|
||||||
|
debug_assert!(pstr_loc < self.heap.byte_len());
|
||||||
|
|
||||||
|
let HeapStringScan { string, tail_idx } = self.heap.scan_slice_to_str(pstr_loc);
|
||||||
|
self.stub.allocate_pstr(string)?;
|
||||||
|
Ok(tail_idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_slice_from<'b>(&'b self, from: usize) -> Box<dyn Iterator<Item = u8> + 'b> {
|
||||||
|
if from < self.heap.byte_len() {
|
||||||
|
Box::new(
|
||||||
|
self.heap.as_slice()[from..]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.chain(self.stub.as_slice().iter().cloned()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Box::new(self.stub.as_slice()[from..].iter().cloned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize> {
|
||||||
|
self.stub.reserve(num_cells)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
|
||||||
|
let len = bounds.end - bounds.start;
|
||||||
|
let mut stub_writer = self.stub.reserve(len)?;
|
||||||
|
|
||||||
|
stub_writer.write_with(|section| {
|
||||||
|
for idx in bounds {
|
||||||
|
section.push_cell(self.heap[idx]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
@@ -461,10 +544,6 @@ impl MachineState {
|
|||||||
let addr = self.store(self.deref(addr));
|
let addr = self.store(self.deref(addr));
|
||||||
|
|
||||||
read_heap_cell!(addr,
|
read_heap_cell!(addr,
|
||||||
(HeapCellValueTag::Char, c) => {
|
|
||||||
chars.push(c);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
if arity == 0 {
|
if arity == 0 {
|
||||||
if let Some(c) = name.as_char() {
|
if let Some(c) = name.as_char() {
|
||||||
@@ -537,39 +616,26 @@ impl MachineState {
|
|||||||
pub fn write_read_term_options(
|
pub fn write_read_term_options(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
|
mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
|
||||||
singleton_var_list: Vec<HeapCellValue>,
|
singleton_heap_list: HeapCellValue,
|
||||||
) -> CallResult {
|
) -> CallResult {
|
||||||
var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2));
|
var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2));
|
||||||
|
|
||||||
let list_of_var_eqs = push_var_eq_functors(
|
|
||||||
&mut self.heap,
|
|
||||||
var_list.iter().filter_map(|(var_name, var, _)| {
|
|
||||||
if var_name.is_anon() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some((var_name, var))
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
&self.atom_tbl,
|
|
||||||
);
|
|
||||||
|
|
||||||
let singleton_addr = self.registers[3];
|
let singleton_addr = self.registers[3];
|
||||||
let singletons_offset = heap_loc_as_cell!(iter_to_heap_list(
|
unify_fn!(*self, singleton_heap_list, singleton_addr);
|
||||||
&mut self.heap,
|
|
||||||
singleton_var_list.into_iter()
|
|
||||||
));
|
|
||||||
|
|
||||||
unify_fn!(*self, singletons_offset, singleton_addr);
|
|
||||||
|
|
||||||
if self.fail {
|
if self.fail {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let vars_addr = self.registers[4];
|
let vars_addr = self.registers[4];
|
||||||
let vars_offset = heap_loc_as_cell!(iter_to_heap_list(
|
let vars_offset = resource_error_call_result!(
|
||||||
&mut self.heap,
|
self,
|
||||||
var_list.into_iter().map(|(_, cell, _)| cell)
|
sized_iter_to_heap_list(
|
||||||
));
|
&mut self.heap,
|
||||||
|
var_list.len(),
|
||||||
|
var_list.iter().map(|(_, cell, _)| *cell),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
unify_fn!(*self, vars_offset, vars_addr);
|
unify_fn!(*self, vars_offset, vars_addr);
|
||||||
|
|
||||||
@@ -578,24 +644,27 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let var_names_addr = self.registers[5];
|
let var_names_addr = self.registers[5];
|
||||||
let var_names_offset = heap_loc_as_cell!(iter_to_heap_list(
|
let var_names_offset = resource_error_call_result!(
|
||||||
&mut self.heap,
|
self,
|
||||||
list_of_var_eqs.into_iter()
|
push_var_eq_functors(
|
||||||
));
|
&mut self.heap,
|
||||||
|
var_list.len(),
|
||||||
Ok(unify_fn!(*self, var_names_offset, var_names_addr))
|
var_list.iter().filter_map(|(var_name, var, _)| {
|
||||||
|
if var_name.is_anon() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((var_name, var))
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
&self.atom_tbl,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
unify_fn!(*self, var_names_offset, var_names_addr);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
|
pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
|
||||||
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
|
let heap_loc = heap_loc_as_cell!(term_write_result.heap_loc);
|
||||||
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
|
|
||||||
pstr_loc_as_cell!(term_write_result.heap_loc)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
heap_loc_as_cell!(term_write_result.heap_loc)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
unify_fn!(*self, heap_loc, self.registers[2]);
|
unify_fn!(*self, heap_loc, self.registers[2]);
|
||||||
|
|
||||||
if self.fail {
|
if self.fail {
|
||||||
@@ -607,10 +676,9 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
|
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
|
||||||
|
self.heap[0] = heap_loc;
|
||||||
|
|
||||||
for cell in
|
for cell in stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0) {
|
||||||
stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, heap_loc)
|
|
||||||
{
|
|
||||||
let cell = unmark_cell_bits!(cell);
|
let cell = unmark_cell_bits!(cell);
|
||||||
|
|
||||||
if let Some(var) = cell.as_var() {
|
if let Some(var) = cell.as_var() {
|
||||||
@@ -622,29 +690,29 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let singleton_var_list = push_var_eq_functors(
|
let singleton_var_list = resource_error_call_result!(
|
||||||
&mut self.heap,
|
self,
|
||||||
term_write_result
|
push_var_eq_functors(
|
||||||
.var_dict
|
&mut self.heap,
|
||||||
.iter()
|
term_write_result.var_dict.len(),
|
||||||
.filter(|(var_name, binding)| {
|
term_write_result
|
||||||
if var_name.is_anon() {
|
.var_dict
|
||||||
return false;
|
.iter()
|
||||||
}
|
.filter(|(var_name, binding)| {
|
||||||
|
if var_name.is_anon() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(r) = binding.as_var() {
|
if let Some(r) = binding.as_var() {
|
||||||
*singleton_var_set.get(&r).unwrap_or(&false)
|
*singleton_var_set.get(&r).unwrap_or(&false)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
&self.atom_tbl,
|
&self.atom_tbl,
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
for var in term_write_result.var_dict.values_mut() {
|
|
||||||
*var = heap_bound_deref(&self.heap, *var);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut var_list = Vec::with_capacity(singleton_var_set.len());
|
let mut var_list = Vec::with_capacity(singleton_var_set.len());
|
||||||
|
|
||||||
for (var_name, addr) in term_write_result.var_dict {
|
for (var_name, addr) in term_write_result.var_dict {
|
||||||
@@ -741,7 +809,8 @@ impl MachineState {
|
|||||||
CompilationError::ParserError(e) if e.is_unexpected_eof() => {
|
CompilationError::ParserError(e) if e.is_unexpected_eof() => {
|
||||||
match eof_handler(self, stream)? {
|
match eof_handler(self, stream)? {
|
||||||
OnEOF::Return => {
|
OnEOF::Return => {
|
||||||
return self.write_read_term_options(vec![], vec![])
|
return self
|
||||||
|
.write_read_term_options(vec![], empty_list_as_cell!());
|
||||||
}
|
}
|
||||||
OnEOF::Continue => continue,
|
OnEOF::Continue => continue,
|
||||||
}
|
}
|
||||||
@@ -790,19 +859,16 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
read_heap_cell!(atom,
|
read_heap_cell!(atom,
|
||||||
(HeapCellValueTag::Char, c) => {
|
|
||||||
var_names.insert(var, VarPtr::from(c.to_string()));
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Atom, (name, _arity)) => {
|
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||||
debug_assert_eq!(_arity, 0);
|
debug_assert_eq!(_arity, 0);
|
||||||
var_names.insert(var, VarPtr::from(&*name.as_str()));
|
var_names.insert(var, VarPtr::from(name.as_str().to_owned()));
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
.get_name_and_arity();
|
.get_name_and_arity();
|
||||||
|
|
||||||
debug_assert_eq!(arity, 0);
|
debug_assert_eq!(arity, 0);
|
||||||
var_names.insert(var, VarPtr::from(&*name.as_str()));
|
var_names.insert(var, VarPtr::from(name.as_str().to_owned()));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
@@ -881,13 +947,15 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.heap[0] = term_to_be_printed;
|
||||||
|
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut self.heap,
|
&mut self.heap,
|
||||||
Arc::clone(&self.atom_tbl),
|
|
||||||
&mut self.stack,
|
&mut self.stack,
|
||||||
|
&self.arena,
|
||||||
op_dir,
|
op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
term_to_be_printed,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
printer.ignore_ops = ignore_ops;
|
printer.ignore_ops = ignore_ops;
|
||||||
@@ -895,7 +963,7 @@ impl MachineState {
|
|||||||
printer.quoted = quoted;
|
printer.quoted = quoted;
|
||||||
printer.double_quotes = double_quotes;
|
printer.double_quotes = double_quotes;
|
||||||
|
|
||||||
match Number::try_from(max_depth) {
|
match Number::try_from((max_depth, &self.arena.f64_tbl)) {
|
||||||
Ok(Number::Fixnum(n)) => {
|
Ok(Number::Fixnum(n)) => {
|
||||||
if let Ok(n) = usize::try_from(n.get_num()) {
|
if let Ok(n) = usize::try_from(n.get_num()) {
|
||||||
printer.max_depth = n;
|
printer.max_depth = n;
|
||||||
@@ -920,7 +988,6 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
printer.var_names = var_names;
|
printer.var_names = var_names;
|
||||||
|
|
||||||
printer
|
printer
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -937,7 +1004,10 @@ impl MachineState {
|
|||||||
arity: HeapCellValue,
|
arity: HeapCellValue,
|
||||||
) -> (Atom, usize) {
|
) -> (Atom, usize) {
|
||||||
let name = cell_as_atom!(self.store(self.deref(name)));
|
let name = cell_as_atom!(self.store(self.deref(name)));
|
||||||
let arity = cell_as_fixnum!(self.store(self.deref(arity)));
|
let arity = unsafe {
|
||||||
|
self.store(self.deref(arity))
|
||||||
|
.to_fixnum_or_cut_point_unchecked()
|
||||||
|
};
|
||||||
|
|
||||||
(name, usize::try_from(arity.get_num()).unwrap())
|
(name, usize::try_from(arity.get_num()).unwrap())
|
||||||
}
|
}
|
||||||
@@ -978,42 +1048,6 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn directive_error(&mut self, err: DirectiveError) -> MachineError {
|
|
||||||
match err {
|
|
||||||
DirectiveError::ExpectedDirective(_term) => self.domain_error(
|
|
||||||
DomainErrorType::Directive,
|
|
||||||
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
|
||||||
),
|
|
||||||
DirectiveError::InvalidDirective(name, arity) => {
|
|
||||||
self.domain_error(DomainErrorType::Directive, functor_stub(name, arity))
|
|
||||||
}
|
|
||||||
DirectiveError::InvalidOpDeclNameType(_term) => self.type_error(
|
|
||||||
ValidType::List,
|
|
||||||
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
|
||||||
),
|
|
||||||
DirectiveError::InvalidOpDeclSpecDomain(_term) => self.domain_error(
|
|
||||||
DomainErrorType::OperatorSpecifier,
|
|
||||||
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
|
||||||
),
|
|
||||||
DirectiveError::InvalidOpDeclSpecValue(atom) => {
|
|
||||||
self.domain_error(DomainErrorType::OperatorSpecifier, atom_as_cell!(atom))
|
|
||||||
}
|
|
||||||
DirectiveError::InvalidOpDeclPrecType(_term) => self.type_error(
|
|
||||||
ValidType::Integer,
|
|
||||||
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
|
||||||
),
|
|
||||||
DirectiveError::InvalidOpDeclPrecDomain(num) => {
|
|
||||||
self.domain_error(DomainErrorType::OperatorPriority, fixnum_as_cell!(num))
|
|
||||||
}
|
|
||||||
DirectiveError::ShallNotCreate(atom) => {
|
|
||||||
self.permission_error(Permission::Create, atom!("operator"), atom)
|
|
||||||
}
|
|
||||||
DirectiveError::ShallNotModify(atom) => {
|
|
||||||
self.permission_error(Permission::Modify, atom!("operator"), atom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,16 +4,13 @@ pub use crate::machine::machine_state::*;
|
|||||||
pub use crate::machine::streams::*;
|
pub use crate::machine::streams::*;
|
||||||
pub use crate::machine::*;
|
pub use crate::machine::*;
|
||||||
pub use crate::parser::ast::*;
|
pub use crate::parser::ast::*;
|
||||||
use crate::read::*;
|
|
||||||
pub use crate::types::*;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::machine::copier::CopierTarget;
|
use crate::machine::copier::CopierTarget;
|
||||||
|
use crate::read::TermWriteResult;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
|
||||||
|
|
||||||
// a mini-WAM for test purposes.
|
// a mini-WAM for test purposes.
|
||||||
|
|
||||||
@@ -31,7 +28,6 @@ impl MockWAM {
|
|||||||
Self {
|
Self {
|
||||||
machine_st: MachineState::new(),
|
machine_st: MachineState::new(),
|
||||||
op_dir,
|
op_dir,
|
||||||
//flags: MachineFlags::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,16 +51,15 @@ impl MockWAM {
|
|||||||
term_string: &'static str,
|
term_string: &'static str,
|
||||||
) -> Result<String, CompilationError> {
|
) -> Result<String, CompilationError> {
|
||||||
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
|
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
|
||||||
|
print_heap_terms(&self.machine_st.heap, term_write_result.heap_loc);
|
||||||
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
|
|
||||||
|
|
||||||
let mut printer = HCPrinter::new(
|
let mut printer = HCPrinter::new(
|
||||||
&mut self.machine_st.heap,
|
&mut self.machine_st.heap,
|
||||||
Arc::clone(&self.machine_st.atom_tbl),
|
|
||||||
&mut self.machine_st.stack,
|
&mut self.machine_st.stack,
|
||||||
|
&self.machine_st.arena,
|
||||||
&self.op_dir,
|
&self.op_dir,
|
||||||
PrinterOutputter::new(),
|
PrinterOutputter::new(),
|
||||||
heap_loc_as_cell!(term_write_result.heap_loc),
|
term_write_result.heap_loc,
|
||||||
);
|
);
|
||||||
|
|
||||||
printer.var_names = term_write_result
|
printer.var_names = term_write_result
|
||||||
@@ -95,6 +90,7 @@ pub struct TermCopyingMockWAM<'a> {
|
|||||||
impl<'a> Index<usize> for TermCopyingMockWAM<'a> {
|
impl<'a> Index<usize> for TermCopyingMockWAM<'a> {
|
||||||
type Output = HeapCellValue;
|
type Output = HeapCellValue;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn index(&self, index: usize) -> &HeapCellValue {
|
fn index(&self, index: usize) -> &HeapCellValue {
|
||||||
&self.wam.machine_st.heap[index]
|
&self.wam.machine_st.heap[index]
|
||||||
}
|
}
|
||||||
@@ -112,6 +108,7 @@ impl<'a> IndexMut<usize> for TermCopyingMockWAM<'a> {
|
|||||||
impl<'a> Deref for TermCopyingMockWAM<'a> {
|
impl<'a> Deref for TermCopyingMockWAM<'a> {
|
||||||
type Target = MockWAM;
|
type Target = MockWAM;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.wam
|
self.wam
|
||||||
}
|
}
|
||||||
@@ -119,6 +116,7 @@ impl<'a> Deref for TermCopyingMockWAM<'a> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
impl<'a> DerefMut for TermCopyingMockWAM<'a> {
|
impl<'a> DerefMut for TermCopyingMockWAM<'a> {
|
||||||
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.wam
|
self.wam
|
||||||
}
|
}
|
||||||
@@ -153,10 +151,6 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, val: HeapCellValue) {
|
|
||||||
self.wam.machine_st.heap.push(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
||||||
self.wam
|
self.wam
|
||||||
.machine_st
|
.machine_st
|
||||||
@@ -170,43 +164,66 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn threshold(&self) -> usize {
|
fn threshold(&self) -> usize {
|
||||||
self.wam.machine_st.heap.len()
|
self.wam.machine_st.heap.cell_len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
|
||||||
|
self.wam.machine_st.heap.copy_pstr_within(pstr_loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_slice_from<'b>(&'b self, from: usize) -> Box<dyn Iterator<Item = u8> + 'b> {
|
||||||
|
Box::new(self.wam.machine_st.heap.as_slice()[from..].iter().cloned())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize> {
|
||||||
|
self.wam.machine_st.heap.reserve(num_cells)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
|
||||||
|
self.wam.machine_st.heap.copy_slice_to_end(bounds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
|
pub fn all_cells_marked_and_unforwarded(heap: &Heap, offset: usize) {
|
||||||
for (idx, cell) in heap.iter().enumerate() {
|
for curr_idx in offset..heap.cell_len() {
|
||||||
|
let cell = heap[curr_idx];
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
cell.get_mark_bit(),
|
cell.get_mark_bit(),
|
||||||
"cell {:?} at index {} is not marked",
|
"cell {cell:?} at index {curr_idx} is not marked"
|
||||||
cell,
|
|
||||||
idx
|
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!cell.get_forwarding_bit(),
|
!cell.get_forwarding_bit(),
|
||||||
"cell {:?} at index {} is forwarded",
|
"cell {cell:?} at index {curr_idx} is forwarded"
|
||||||
cell,
|
|
||||||
idx
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn all_cells_unmarked(heap: &Heap) {
|
pub fn unmark_all_cells(heap: &mut Heap, offset: usize) {
|
||||||
for (idx, cell) in heap.iter().enumerate() {
|
for idx in offset..heap.cell_len() {
|
||||||
assert!(
|
heap[idx].set_mark_bit(false);
|
||||||
!cell.get_mark_bit(),
|
}
|
||||||
"cell {:?} at index {} is still marked",
|
}
|
||||||
cell,
|
|
||||||
idx
|
#[cfg(test)]
|
||||||
);
|
pub fn all_cells_unmarked(iter: &impl SizedHeap) {
|
||||||
|
let mut idx = 0;
|
||||||
|
let cell_len = iter.cell_len();
|
||||||
|
|
||||||
|
while idx < cell_len {
|
||||||
|
let curr_idx = idx;
|
||||||
|
idx += 1;
|
||||||
|
let cell = iter[curr_idx];
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
!cell.get_forwarding_bit(),
|
!cell.get_mark_bit(),
|
||||||
"cell {:?} at index {} is still forwarded",
|
"cell {cell:?} at index {curr_idx} is still marked"
|
||||||
cell,
|
|
||||||
idx
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,6 +249,7 @@ pub(crate) fn parse_and_write_parsed_term_to_heap(
|
|||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
/// For use in tests.
|
/// For use in tests.
|
||||||
|
#[allow(clippy::unbuffered_bytes)]
|
||||||
pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
|
pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
|
||||||
let stream = Stream::from_owned_string(
|
let stream = Stream::from_owned_string(
|
||||||
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
|
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
|
||||||
@@ -243,6 +261,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// For use in tests.
|
/// For use in tests.
|
||||||
|
#[allow(clippy::unbuffered_bytes)]
|
||||||
pub fn test_load_string(&mut self, code: &str) -> Vec<u8> {
|
pub fn test_load_string(&mut self, code: &str) -> Vec<u8> {
|
||||||
let stream = Stream::from_owned_string(code.to_owned(), &mut self.machine_st.arena);
|
let stream = Stream::from_owned_string(code.to_owned(), &mut self.machine_st.arena);
|
||||||
|
|
||||||
@@ -255,6 +274,8 @@ impl Machine {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use crate::functor_macro::FunctorElement;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unify_tests() {
|
fn unify_tests() {
|
||||||
let mut wam = MachineState::new();
|
let mut wam = MachineState::new();
|
||||||
@@ -387,36 +408,66 @@ mod tests {
|
|||||||
|
|
||||||
wam.heap.clear();
|
wam.heap.clear();
|
||||||
|
|
||||||
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
|
let mut writer = wam.heap.reserve(96).unwrap();
|
||||||
wam.heap.push(heap_loc_as_cell!(1));
|
|
||||||
|
|
||||||
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
|
writer.write_with(|section| {
|
||||||
wam.heap.push(pstr_loc_as_cell!(4));
|
section.push_pstr("this is a string"); // 0
|
||||||
|
|
||||||
wam.heap.push(pstr_offset_as_cell!(0));
|
let h = section.cell_len();
|
||||||
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6)));
|
assert_eq!(h, 3);
|
||||||
|
|
||||||
unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2));
|
section.push_cell(heap_loc_as_cell!(h)); // 3
|
||||||
|
section.push_pstr("this is a string"); // 4
|
||||||
|
|
||||||
|
let h = section.cell_len();
|
||||||
|
assert_eq!(h + 1, 8);
|
||||||
|
|
||||||
|
section.push_cell(pstr_loc_as_cell!(heap_index!(h + 1))); // 7
|
||||||
|
section.push_pstr("this is a string"); // 8
|
||||||
|
|
||||||
|
section.push_cell(pstr_loc_as_cell!(heap_index!(h + 1)));
|
||||||
|
});
|
||||||
|
|
||||||
|
unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(heap_index!(4)));
|
||||||
|
|
||||||
assert!(!wam.fail);
|
assert!(!wam.fail);
|
||||||
|
|
||||||
assert_eq!(wam.heap[1], pstr_loc_as_cell!(4));
|
assert_eq!(
|
||||||
|
wam.heap
|
||||||
all_cells_unmarked(&wam.heap);
|
.slice_to_str(heap_index!(0), "this is a string".len()),
|
||||||
|
"this is a string"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.heap[3], pstr_loc_as_cell!(heap_index!(8)));
|
||||||
|
assert_eq!(
|
||||||
|
wam.heap
|
||||||
|
.slice_to_str(heap_index!(4), "this is a string".len()),
|
||||||
|
"this is a string"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.heap[7], pstr_loc_as_cell!(heap_index!(8)));
|
||||||
|
assert_eq!(
|
||||||
|
wam.heap
|
||||||
|
.slice_to_str(heap_index!(8), "this is a string".len()),
|
||||||
|
"this is a string"
|
||||||
|
);
|
||||||
|
assert_eq!(wam.heap[11], pstr_loc_as_cell!(heap_index!(8)));
|
||||||
|
|
||||||
wam.heap.clear();
|
wam.heap.clear();
|
||||||
|
|
||||||
wam.heap.push(list_loc_as_cell!(1));
|
let mut writer = wam.heap.reserve(96).unwrap();
|
||||||
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));
|
writer.write_with(|section| {
|
||||||
wam.heap.push(atom_as_cell!(atom!("a")));
|
section.push_cell(list_loc_as_cell!(1));
|
||||||
wam.heap.push(list_loc_as_cell!(8));
|
section.push_cell(atom_as_cell!(atom!("a")));
|
||||||
wam.heap.push(atom_as_cell!(atom!("b")));
|
section.push_cell(list_loc_as_cell!(3));
|
||||||
wam.heap.push(heap_loc_as_cell!(5));
|
section.push_cell(atom_as_cell!(atom!("b")));
|
||||||
|
section.push_cell(heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
section.push_cell(list_loc_as_cell!(6));
|
||||||
|
section.push_cell(atom_as_cell!(atom!("a")));
|
||||||
|
section.push_cell(list_loc_as_cell!(8));
|
||||||
|
section.push_cell(atom_as_cell!(atom!("b")));
|
||||||
|
section.push_cell(heap_loc_as_cell!(5));
|
||||||
|
});
|
||||||
|
|
||||||
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
||||||
|
|
||||||
@@ -426,17 +477,21 @@ mod tests {
|
|||||||
|
|
||||||
wam.heap.clear();
|
wam.heap.clear();
|
||||||
|
|
||||||
wam.heap.push(list_loc_as_cell!(1));
|
let mut writer = wam.heap.reserve(96).unwrap();
|
||||||
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));
|
writer.write_with(|section| {
|
||||||
wam.heap.push(atom_as_cell!(atom!("a")));
|
section.push_cell(list_loc_as_cell!(1));
|
||||||
wam.heap.push(list_loc_as_cell!(8));
|
section.push_cell(atom_as_cell!(atom!("a")));
|
||||||
wam.heap.push(atom_as_cell!(atom!("c")));
|
section.push_cell(list_loc_as_cell!(3));
|
||||||
wam.heap.push(heap_loc_as_cell!(5));
|
section.push_cell(atom_as_cell!(atom!("b")));
|
||||||
|
section.push_cell(heap_loc_as_cell!(0));
|
||||||
|
|
||||||
|
section.push_cell(list_loc_as_cell!(6));
|
||||||
|
section.push_cell(atom_as_cell!(atom!("a")));
|
||||||
|
section.push_cell(list_loc_as_cell!(8));
|
||||||
|
section.push_cell(atom_as_cell!(atom!("c")));
|
||||||
|
section.push_cell(heap_loc_as_cell!(5));
|
||||||
|
});
|
||||||
|
|
||||||
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
||||||
|
|
||||||
@@ -444,19 +499,24 @@ mod tests {
|
|||||||
|
|
||||||
wam.fail = false;
|
wam.fail = false;
|
||||||
all_cells_unmarked(&wam.heap);
|
all_cells_unmarked(&wam.heap);
|
||||||
|
|
||||||
wam.heap.clear();
|
wam.heap.clear();
|
||||||
|
|
||||||
wam.heap.push(list_loc_as_cell!(1));
|
let mut writer = wam.heap.reserve(96).unwrap();
|
||||||
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));
|
writer.write_with(|section| {
|
||||||
wam.heap.push(atom_as_cell!(atom!("a")));
|
section.push_cell(list_loc_as_cell!(1));
|
||||||
wam.heap.push(list_loc_as_cell!(8));
|
section.push_cell(atom_as_cell!(atom!("a")));
|
||||||
wam.heap.push(atom_as_cell!(atom!("b")));
|
section.push_cell(list_loc_as_cell!(3));
|
||||||
wam.heap.push(heap_loc_as_cell!(0));
|
section.push_cell(atom_as_cell!(atom!("b")));
|
||||||
|
section.push_cell(heap_loc_as_cell!(5));
|
||||||
|
|
||||||
|
section.push_cell(list_loc_as_cell!(6));
|
||||||
|
section.push_cell(atom_as_cell!(atom!("a")));
|
||||||
|
section.push_cell(list_loc_as_cell!(8));
|
||||||
|
section.push_cell(atom_as_cell!(atom!("b")));
|
||||||
|
section.push_cell(heap_loc_as_cell!(0));
|
||||||
|
});
|
||||||
|
|
||||||
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
||||||
|
|
||||||
@@ -468,7 +528,7 @@ mod tests {
|
|||||||
let term_write_result_1 =
|
let term_write_result_1 =
|
||||||
parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
|
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);
|
print_heap_terms(&wam.heap, term_write_result_1.heap_loc);
|
||||||
|
|
||||||
unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
|
unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
|
||||||
|
|
||||||
@@ -510,8 +570,15 @@ mod tests {
|
|||||||
|
|
||||||
let mut wam = MachineState::new();
|
let mut wam = MachineState::new();
|
||||||
|
|
||||||
wam.heap.push(heap_loc_as_cell!(0));
|
// clear the heap of resource error data etc
|
||||||
wam.heap.push(heap_loc_as_cell!(1));
|
wam.heap.clear();
|
||||||
|
|
||||||
|
let mut writer = wam.heap.reserve(96).unwrap();
|
||||||
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(heap_loc_as_cell!(0));
|
||||||
|
section.push_cell(heap_loc_as_cell!(1));
|
||||||
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, wam.heap[0], wam.heap[1]),
|
compare_term_test!(wam, wam.heap[0], wam.heap[1]),
|
||||||
@@ -533,12 +600,10 @@ mod tests {
|
|||||||
Some(Ordering::Equal)
|
Some(Ordering::Equal)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(
|
compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell),
|
||||||
wam,
|
|
||||||
atom_as_cell!(atom!("atom")),
|
|
||||||
atom_as_cstr_cell!(atom!("string"))
|
|
||||||
),
|
|
||||||
Some(Ordering::Less)
|
Some(Ordering::Less)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -571,8 +636,12 @@ mod tests {
|
|||||||
|
|
||||||
wam.heap.clear();
|
wam.heap.clear();
|
||||||
|
|
||||||
wam.heap.push(atom_as_cell!(atom!("f"), 1));
|
let mut writer = wam.heap.reserve(96).unwrap();
|
||||||
wam.heap.push(heap_loc_as_cell!(1));
|
|
||||||
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(atom_as_cell!(atom!("f"), 1));
|
||||||
|
section.push_cell(heap_loc_as_cell!(1));
|
||||||
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(0)),
|
compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(0)),
|
||||||
@@ -586,21 +655,25 @@ mod tests {
|
|||||||
|
|
||||||
wam.heap.clear();
|
wam.heap.clear();
|
||||||
|
|
||||||
// [1,2,3]
|
let mut writer = wam.heap.reserve(96).unwrap();
|
||||||
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]
|
writer.write_with(|section| {
|
||||||
wam.heap.push(list_loc_as_cell!(8));
|
// [1,2,3]
|
||||||
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
|
section.push_cell(list_loc_as_cell!(1));
|
||||||
wam.heap.push(list_loc_as_cell!(10));
|
section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
|
section.push_cell(list_loc_as_cell!(3));
|
||||||
wam.heap.push(empty_list_as_cell!());
|
section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
section.push_cell(list_loc_as_cell!(5));
|
||||||
|
section.push_cell(fixnum_as_cell!(Fixnum::build_with(3)));
|
||||||
|
section.push_cell(empty_list_as_cell!());
|
||||||
|
|
||||||
|
// [1,2]
|
||||||
|
section.push_cell(list_loc_as_cell!(8));
|
||||||
|
section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
section.push_cell(list_loc_as_cell!(10));
|
||||||
|
section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
section.push_cell(empty_list_as_cell!());
|
||||||
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(wam, heap_loc_as_cell!(7), heap_loc_as_cell!(7)),
|
compare_term_test!(wam, heap_loc_as_cell!(7), heap_loc_as_cell!(7)),
|
||||||
@@ -626,12 +699,10 @@ mod tests {
|
|||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
compare_term_test!(
|
compare_term_test!(wam, empty_list_as_cell!(), cstr_cell),
|
||||||
wam,
|
|
||||||
empty_list_as_cell!(),
|
|
||||||
atom_as_cstr_cell!(atom!("string"))
|
|
||||||
),
|
|
||||||
Some(Ordering::Less)
|
Some(Ordering::Less)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -662,55 +733,63 @@ mod tests {
|
|||||||
fn is_cyclic_term_tests() {
|
fn is_cyclic_term_tests() {
|
||||||
let mut wam = MachineState::new();
|
let mut wam = MachineState::new();
|
||||||
|
|
||||||
assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f"))));
|
let mut writer = wam.heap.reserve(96).unwrap();
|
||||||
assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555))));
|
|
||||||
|
|
||||||
wam.heap.push(heap_loc_as_cell!(0));
|
writer.write_with(|section| {
|
||||||
|
section.push_cell(atom_as_cell!(atom!("f")));
|
||||||
|
section.push_cell(fixnum_as_cell!(Fixnum::build_with(555)));
|
||||||
|
section.push_cell(heap_loc_as_cell!(0));
|
||||||
|
});
|
||||||
|
|
||||||
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0)));
|
assert!(!wam.is_cyclic_term(0));
|
||||||
|
assert!(!wam.is_cyclic_term(1));
|
||||||
|
assert!(!wam.is_cyclic_term(2));
|
||||||
|
|
||||||
all_cells_unmarked(&wam.heap);
|
all_cells_unmarked(&wam.heap);
|
||||||
wam.heap.clear();
|
wam.heap.clear();
|
||||||
|
|
||||||
wam.heap
|
let mut functor_writer = Heap::functor_writer(functor!(
|
||||||
.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))]));
|
atom!("f"),
|
||||||
|
[atom_as_cell((atom!("a"))), atom_as_cell((atom!("b")))]
|
||||||
|
));
|
||||||
|
|
||||||
assert!(!wam.is_cyclic_term(str_loc_as_cell!(0)));
|
functor_writer(&mut wam.heap).unwrap();
|
||||||
|
|
||||||
|
let h = wam.heap.cell_len();
|
||||||
|
wam.heap.push_cell(str_loc_as_cell!(0)).unwrap();
|
||||||
|
|
||||||
|
assert!(!wam.is_cyclic_term(h));
|
||||||
|
|
||||||
all_cells_unmarked(&wam.heap);
|
all_cells_unmarked(&wam.heap);
|
||||||
|
|
||||||
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1)));
|
assert!(!wam.is_cyclic_term(1));
|
||||||
|
|
||||||
all_cells_unmarked(&wam.heap);
|
all_cells_unmarked(&wam.heap);
|
||||||
|
|
||||||
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2)));
|
assert!(!wam.is_cyclic_term(2));
|
||||||
|
|
||||||
all_cells_unmarked(&wam.heap);
|
all_cells_unmarked(&wam.heap);
|
||||||
|
|
||||||
wam.heap[2] = str_loc_as_cell!(0);
|
wam.heap[2] = str_loc_as_cell!(0);
|
||||||
|
|
||||||
print_heap_terms(wam.heap.iter(), 0);
|
print_heap_terms(&wam.heap, 0);
|
||||||
|
|
||||||
assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
|
assert!(wam.is_cyclic_term(2));
|
||||||
|
|
||||||
all_cells_unmarked(&wam.heap);
|
all_cells_unmarked(&wam.heap);
|
||||||
|
|
||||||
wam.heap[2] = atom_as_cell!(atom!("b"));
|
wam.heap[2] = atom_as_cell!(atom!("b"));
|
||||||
wam.heap[1] = str_loc_as_cell!(0);
|
wam.heap[1] = str_loc_as_cell!(0);
|
||||||
|
|
||||||
assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
|
assert!(wam.is_cyclic_term(1));
|
||||||
|
|
||||||
all_cells_unmarked(&wam.heap);
|
|
||||||
|
|
||||||
assert!(wam.is_cyclic_term(heap_loc_as_cell!(1)));
|
|
||||||
|
|
||||||
all_cells_unmarked(&wam.heap);
|
all_cells_unmarked(&wam.heap);
|
||||||
|
|
||||||
wam.heap.clear();
|
wam.heap.clear();
|
||||||
|
|
||||||
wam.heap.push(pstr_as_cell!(atom!("a string")));
|
let h = wam.heap.cell_len();
|
||||||
wam.heap.push(empty_list_as_cell!());
|
wam.heap.allocate_cstr("a string").unwrap();
|
||||||
|
|
||||||
assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0)));
|
assert!(!wam.is_cyclic_term(h));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ use crate::machine::machine_indices::*;
|
|||||||
use crate::machine::machine_state::*;
|
use crate::machine::machine_state::*;
|
||||||
use crate::machine::stack::*;
|
use crate::machine::stack::*;
|
||||||
use crate::machine::streams::*;
|
use crate::machine::streams::*;
|
||||||
|
use crate::offset_table::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::dashu::{Integer, Rational};
|
use crate::parser::dashu::{Integer, Rational};
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
@@ -207,13 +208,8 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
|
pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
|
||||||
read_heap_cell!(value,
|
read_heap_cell!(value,
|
||||||
(HeapCellValueTag::Cons, cons_ptr) => {
|
(HeapCellValueTag::CodeIndexOffset, offset) => {
|
||||||
match_untyped_arena_ptr!(cons_ptr,
|
return Some(CodeIndex::from(offset));
|
||||||
(ArenaHeaderTag::IndexPtr, ip) => {
|
|
||||||
return Some(CodeIndex::from(ip));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
}
|
}
|
||||||
@@ -246,7 +242,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the predicate `key` in `module_name` until completion.
|
/// Runs the predicate `key` in `module_name` until completion.
|
||||||
/// Siltently ignores failure, thrown errors and choice points.
|
/// Silently ignores failure, thrown errors and choice points.
|
||||||
///
|
///
|
||||||
/// Consider using [`Machine::run_query`] if you wish to handle
|
/// Consider using [`Machine::run_query`] if you wish to handle
|
||||||
/// predicates that may fail, leave a choice point or throw.
|
/// predicates that may fail, leave a choice point or throw.
|
||||||
@@ -256,8 +252,14 @@ impl Machine {
|
|||||||
key: PredicateKey,
|
key: PredicateKey,
|
||||||
) -> std::process::ExitCode {
|
) -> std::process::ExitCode {
|
||||||
if let Some(module) = self.indices.modules.get(&module_name) {
|
if let Some(module) = self.indices.modules.get(&module_name) {
|
||||||
if let Some(code_index) = module.code_dir.get(&key) {
|
if let Some(code_idx) = module.code_dir.get(&key) {
|
||||||
let p = code_index.local().unwrap();
|
let index_ptr = self
|
||||||
|
.machine_st
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(code_idx.into());
|
||||||
|
let p = index_ptr.local().unwrap();
|
||||||
|
|
||||||
// Leave a halting choice point to backtrack to in case the predicate fails or throws.
|
// Leave a halting choice point to backtrack to in case the predicate fails or throws.
|
||||||
self.allocate_stub_choice_point();
|
self.allocate_stub_choice_point();
|
||||||
|
|
||||||
@@ -328,8 +330,13 @@ impl Machine {
|
|||||||
self.load_file(path_buf.to_str().unwrap(), stream);
|
self.load_file(path_buf.to_str().unwrap(), stream);
|
||||||
|
|
||||||
if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
|
if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
|
||||||
if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) {
|
if let Some(code_idx) = module.code_dir.get(&(atom!("driver"), 2)) {
|
||||||
self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap();
|
let index_ptr = self
|
||||||
|
.machine_st
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(code_idx.into());
|
||||||
|
self.machine_st.attr_var_init.verify_attrs_loc = index_ptr.local().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -343,13 +350,16 @@ impl Machine {
|
|||||||
for arity in 1..66 {
|
for arity in 1..66 {
|
||||||
let key = (atom!("call"), arity);
|
let key = (atom!("call"), arity);
|
||||||
|
|
||||||
match loader.code_dir.get(&key) {
|
match loader.code_dir.get(&key).cloned() {
|
||||||
Some(src_code_index) => {
|
Some(src_code_index) => {
|
||||||
let target_code_index = target_code_dir
|
let code_index_tbl = &mut arena.code_index_tbl;
|
||||||
.entry(key)
|
|
||||||
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
|
|
||||||
|
|
||||||
target_code_index.set(src_code_index.get());
|
let target_code_index = target_code_dir.entry(key).or_insert_with(|| {
|
||||||
|
CodeIndex::new(IndexPtr::undefined(), code_index_tbl)
|
||||||
|
});
|
||||||
|
|
||||||
|
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
|
||||||
|
target_code_index.set(code_index_tbl, src_code_ptr);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
@@ -458,7 +468,7 @@ impl Machine {
|
|||||||
key,
|
key,
|
||||||
CodeIndex::new(
|
CodeIndex::new(
|
||||||
IndexPtr::index(p + impls_offset),
|
IndexPtr::index(p + impls_offset),
|
||||||
&mut self.machine_st.arena,
|
&mut self.machine_st.arena.code_index_tbl,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -485,7 +495,10 @@ impl Machine {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn run_verify_attr_interrupt(&mut self, arity: usize) {
|
pub(crate) fn run_verify_attr_interrupt(&mut self, arity: usize) {
|
||||||
let p = self.machine_st.attr_var_init.verify_attrs_loc;
|
let p = self.machine_st.attr_var_init.verify_attrs_loc;
|
||||||
self.machine_st.verify_attr_interrupt(p, arity);
|
step_or_resource_error!(
|
||||||
|
self.machine_st,
|
||||||
|
self.machine_st.verify_attr_interrupt(p, arity)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_clause_applicable(&mut self, mut offset: usize) -> bool {
|
fn next_clause_applicable(&mut self, mut offset: usize) -> bool {
|
||||||
@@ -509,8 +522,8 @@ impl Machine {
|
|||||||
.select_switch_on_term_index(cell, v, c, l, s)
|
.select_switch_on_term_index(cell, v, c, l, s)
|
||||||
}
|
}
|
||||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
|
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
|
||||||
let lit = self.machine_st.constant_to_literal(cell);
|
// let lit = self.machine_st.constant_to_literal(cell);
|
||||||
hm.get(&lit).cloned().unwrap_or(IndexingCodePtr::Fail)
|
hm.get(&cell).cloned().unwrap_or(IndexingCodePtr::Fail)
|
||||||
}
|
}
|
||||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
|
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
|
||||||
self.machine_st.select_switch_on_structure_index(cell, hm)
|
self.machine_st.select_switch_on_structure_index(cell, hm)
|
||||||
@@ -536,34 +549,8 @@ impl Machine {
|
|||||||
|
|
||||||
if cell.is_var() {
|
if cell.is_var() {
|
||||||
offset += 1;
|
offset += 1;
|
||||||
} else if lit.get_tag() == HeapCellValueTag::CStr {
|
|
||||||
read_heap_cell!(cell,
|
|
||||||
(HeapCellValueTag::CStr) => {
|
|
||||||
if cell == lit {
|
|
||||||
offset += 1;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
|
|
||||||
offset += 1;
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s) => {
|
|
||||||
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
|
|
||||||
.get_name_and_arity();
|
|
||||||
|
|
||||||
if name == atom!(".") && arity == 2 {
|
|
||||||
offset += 1;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
self.machine_st.write_literal_to_var(cell, lit);
|
unify!(self.machine_st, cell, lit);
|
||||||
|
|
||||||
if self.machine_st.fail {
|
if self.machine_st.fail {
|
||||||
self.machine_st.fail = false;
|
self.machine_st.fail = false;
|
||||||
@@ -577,7 +564,7 @@ impl Machine {
|
|||||||
let cell = self.deref_register(t);
|
let cell = self.deref_register(t);
|
||||||
|
|
||||||
read_heap_cell!(cell,
|
read_heap_cell!(cell,
|
||||||
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
|
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {// | HeapCellValueTag::CStr) => {
|
||||||
offset += 1;
|
offset += 1;
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
@@ -616,27 +603,24 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
&Instruction::GetPartialString(
|
&Instruction::GetPartialString(Level::Shallow, ref string, RegType::Temp(t)) => {
|
||||||
Level::Shallow,
|
|
||||||
string,
|
|
||||||
RegType::Temp(t),
|
|
||||||
has_tail,
|
|
||||||
) => {
|
|
||||||
let cell = self.deref_register(t);
|
let cell = self.deref_register(t);
|
||||||
|
|
||||||
read_heap_cell!(cell,
|
read_heap_cell!(cell,
|
||||||
(HeapCellValueTag::CStr, cstr) => {
|
(HeapCellValueTag::PStrLoc, pstr_loc) => {
|
||||||
if !has_tail && string != cstr {
|
let heap_slice = &self.machine_st.heap.as_slice()[pstr_loc ..];
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += 1;
|
match compare_pstr_slices(heap_slice, string.as_bytes()) {
|
||||||
|
PStrSegmentCmpResult::Continue(..) => offset += 1,
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
|
(HeapCellValueTag::Lis) => {
|
||||||
offset += 1;
|
offset += 1;
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity();
|
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
if name == atom!(".") && arity == 2 {
|
if name == atom!(".") && arity == 2 {
|
||||||
offset += 1;
|
offset += 1;
|
||||||
@@ -759,7 +743,7 @@ impl Machine {
|
|||||||
or_frame.prelude.boip = 0;
|
or_frame.prelude.boip = 0;
|
||||||
or_frame.prelude.biip = 0;
|
or_frame.prelude.biip = 0;
|
||||||
or_frame.prelude.tr = self.machine_st.tr;
|
or_frame.prelude.tr = self.machine_st.tr;
|
||||||
or_frame.prelude.h = self.machine_st.heap.len();
|
or_frame.prelude.h = self.machine_st.heap.cell_len();
|
||||||
or_frame.prelude.b0 = self.machine_st.b0;
|
or_frame.prelude.b0 = self.machine_st.b0;
|
||||||
or_frame.prelude.attr_var_queue_len =
|
or_frame.prelude.attr_var_queue_len =
|
||||||
self.machine_st.attr_var_init.attr_var_queue.len();
|
self.machine_st.attr_var_init.attr_var_queue.len();
|
||||||
@@ -770,7 +754,7 @@ impl Machine {
|
|||||||
or_frame[i] = self.machine_st.registers[i + 1];
|
or_frame[i] = self.machine_st.registers[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
self.machine_st.hb = self.machine_st.heap.len();
|
self.machine_st.hb = self.machine_st.heap.cell_len();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.machine_st.p += 1;
|
self.machine_st.p += 1;
|
||||||
@@ -791,7 +775,7 @@ impl Machine {
|
|||||||
or_frame.prelude.boip = self.machine_st.oip;
|
or_frame.prelude.boip = self.machine_st.oip;
|
||||||
or_frame.prelude.biip = self.machine_st.iip + iip_offset; // 1
|
or_frame.prelude.biip = self.machine_st.iip + iip_offset; // 1
|
||||||
or_frame.prelude.tr = self.machine_st.tr;
|
or_frame.prelude.tr = self.machine_st.tr;
|
||||||
or_frame.prelude.h = self.machine_st.heap.len();
|
or_frame.prelude.h = self.machine_st.heap.cell_len();
|
||||||
or_frame.prelude.b0 = self.machine_st.b0;
|
or_frame.prelude.b0 = self.machine_st.b0;
|
||||||
or_frame.prelude.attr_var_queue_len =
|
or_frame.prelude.attr_var_queue_len =
|
||||||
self.machine_st.attr_var_init.attr_var_queue.len();
|
self.machine_st.attr_var_init.attr_var_queue.len();
|
||||||
@@ -802,7 +786,7 @@ impl Machine {
|
|||||||
or_frame[i] = self.machine_st.registers[i + 1];
|
or_frame[i] = self.machine_st.registers[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
self.machine_st.hb = self.machine_st.heap.len();
|
self.machine_st.hb = self.machine_st.heap.cell_len();
|
||||||
|
|
||||||
// self.machine_st.oip = 0;
|
// self.machine_st.oip = 0;
|
||||||
// self.machine_st.iip = 0;
|
// self.machine_st.iip = 0;
|
||||||
@@ -1069,13 +1053,15 @@ impl Machine {
|
|||||||
|
|
||||||
if module_name == atom!("user") {
|
if module_name == atom!("user") {
|
||||||
if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
|
if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
|
||||||
self.try_call(name, arity, idx.get())
|
let index_ptr = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
|
||||||
|
self.try_call(name, arity, index_ptr)
|
||||||
} else {
|
} else {
|
||||||
Err(self.machine_st.throw_undefined_error(name, arity))
|
Err(self.machine_st.throw_undefined_error(name, arity))
|
||||||
}
|
}
|
||||||
} else if let Some(module) = self.indices.modules.get(&module_name) {
|
} else if let Some(module) = self.indices.modules.get(&module_name) {
|
||||||
if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
|
if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
|
||||||
self.try_call(name, arity, idx.get())
|
let index_ptr = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
|
||||||
|
self.try_call(name, arity, index_ptr)
|
||||||
} else {
|
} else {
|
||||||
self.undefined_procedure(name, arity)
|
self.undefined_procedure(name, arity)
|
||||||
}
|
}
|
||||||
@@ -1098,14 +1084,24 @@ impl Machine {
|
|||||||
let (name, arity) = key;
|
let (name, arity) = key;
|
||||||
|
|
||||||
if module_name == atom!("user") {
|
if module_name == atom!("user") {
|
||||||
if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
|
if let Some(offset) = self.indices.code_dir.get(&(name, arity)).cloned() {
|
||||||
self.try_execute(name, arity, idx.get())
|
let index_ptr = self
|
||||||
|
.machine_st
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(offset.into());
|
||||||
|
self.try_execute(name, arity, index_ptr)
|
||||||
} else {
|
} else {
|
||||||
self.undefined_procedure(name, arity)
|
self.undefined_procedure(name, arity)
|
||||||
}
|
}
|
||||||
} else if let Some(module) = self.indices.modules.get(&module_name) {
|
} else if let Some(module) = self.indices.modules.get(&module_name) {
|
||||||
if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
|
if let Some(offset) = module.code_dir.get(&(name, arity)).cloned() {
|
||||||
self.try_execute(name, arity, idx.get())
|
let index_ptr = self
|
||||||
|
.machine_st
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(offset.into());
|
||||||
|
self.try_execute(name, arity, index_ptr)
|
||||||
} else {
|
} else {
|
||||||
self.undefined_procedure(name, arity)
|
self.undefined_procedure(name, arity)
|
||||||
}
|
}
|
||||||
@@ -1147,12 +1143,24 @@ impl Machine {
|
|||||||
let r_c_w_h = self
|
let r_c_w_h = self
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_code_index(r_c_w_h_atom, 0, iso_ext)
|
.get_predicate_code_index(r_c_w_h_atom, 0, iso_ext)
|
||||||
.and_then(|item| item.local())
|
.and_then(|code_idx| {
|
||||||
|
self.machine_st
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(code_idx.into())
|
||||||
|
.local()
|
||||||
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let r_c_wo_h = self
|
let r_c_wo_h = self
|
||||||
.indices
|
.indices
|
||||||
.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext)
|
.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext)
|
||||||
.and_then(|item| item.local())
|
.and_then(|code_idx| {
|
||||||
|
self.machine_st
|
||||||
|
.arena
|
||||||
|
.code_index_tbl
|
||||||
|
.get_entry(code_idx.into())
|
||||||
|
.local()
|
||||||
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
(r_c_w_h, r_c_wo_h)
|
(r_c_w_h, r_c_wo_h)
|
||||||
});
|
});
|
||||||
@@ -1162,8 +1170,10 @@ impl Machine {
|
|||||||
let (idx, arity) = if self.machine_st.effective_block() > prev_block {
|
let (idx, arity) = if self.machine_st.effective_block() > prev_block {
|
||||||
(r_c_w_h, 0)
|
(r_c_w_h, 0)
|
||||||
} else {
|
} else {
|
||||||
self.machine_st.registers[1] =
|
self.machine_st.registers[1] = fixnum_as_cell!(
|
||||||
fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64));
|
/* FIXME this is not safe */
|
||||||
|
unsafe { Fixnum::build_with_unchecked(b_cutoff as i64) }
|
||||||
|
);
|
||||||
|
|
||||||
(r_c_wo_h, 1)
|
(r_c_wo_h, 1)
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -21,11 +21,10 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result<OpDeclSpec, CompilationError
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_op_decl(mut terms: Vec<Term>, atom_tbl: &AtomTable) -> Result<OpDecl, CompilationError> {
|
fn setup_op_decl(mut terms: Vec<Term>) -> Result<OpDecl, CompilationError> {
|
||||||
// should allow non-partial lists?
|
// should allow non-partial lists?
|
||||||
let name = match terms.pop().unwrap() {
|
let name = match terms.pop().unwrap() {
|
||||||
Term::Literal(_, Literal::Atom(name)) => name,
|
Term::Literal(_, Literal::Atom(name)) => name,
|
||||||
Term::Literal(_, Literal::Char(c)) => AtomTable::build_with(atom_tbl, &c.to_string()),
|
|
||||||
other => {
|
other => {
|
||||||
return Err(CompilationError::InvalidDirective(
|
return Err(CompilationError::InvalidDirective(
|
||||||
DirectiveError::InvalidOpDeclNameType(other),
|
DirectiveError::InvalidOpDeclNameType(other),
|
||||||
@@ -112,16 +111,13 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, Compilatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_module_export(
|
fn setup_module_export(mut term: Term) -> Result<ModuleExport, CompilationError> {
|
||||||
mut term: Term,
|
|
||||||
atom_tbl: &AtomTable,
|
|
||||||
) -> Result<ModuleExport, CompilationError> {
|
|
||||||
setup_predicate_indicator(&mut term)
|
setup_predicate_indicator(&mut term)
|
||||||
.map(ModuleExport::PredicateKey)
|
.map(ModuleExport::PredicateKey)
|
||||||
.or_else(|_| {
|
.or_else(|_| {
|
||||||
if let Term::Clause(_, name, terms) = term {
|
if let Term::Clause(_, name, terms) = term {
|
||||||
if terms.len() == 3 && name == atom!("op") {
|
if terms.len() == 3 && name == atom!("op") {
|
||||||
Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?))
|
Ok(ModuleExport::OpDecl(setup_op_decl(terms)?))
|
||||||
} else {
|
} else {
|
||||||
Err(CompilationError::InvalidModuleDecl)
|
Err(CompilationError::InvalidModuleDecl)
|
||||||
}
|
}
|
||||||
@@ -140,12 +136,11 @@ pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
|||||||
|
|
||||||
pub(super) fn setup_module_export_list(
|
pub(super) fn setup_module_export_list(
|
||||||
mut export_list: Term,
|
mut export_list: Term,
|
||||||
atom_tbl: &AtomTable,
|
|
||||||
) -> Result<Vec<ModuleExport>, CompilationError> {
|
) -> Result<Vec<ModuleExport>, CompilationError> {
|
||||||
let mut exports = vec![];
|
let mut exports = vec![];
|
||||||
|
|
||||||
while let Term::Cons(_, t1, t2) = export_list {
|
while let Term::Cons(_, t1, t2) = export_list {
|
||||||
let module_export = setup_module_export(*t1, atom_tbl)?;
|
let module_export = setup_module_export(*t1)?;
|
||||||
|
|
||||||
exports.push(module_export);
|
exports.push(module_export);
|
||||||
export_list = *t2;
|
export_list = *t2;
|
||||||
@@ -158,10 +153,7 @@ pub(super) fn setup_module_export_list(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_module_decl(
|
fn setup_module_decl(mut terms: Vec<Term>) -> Result<ModuleDecl, CompilationError> {
|
||||||
mut terms: Vec<Term>,
|
|
||||||
atom_tbl: &AtomTable,
|
|
||||||
) -> Result<ModuleDecl, CompilationError> {
|
|
||||||
let export_list = terms.pop().unwrap();
|
let export_list = terms.pop().unwrap();
|
||||||
let name = terms.pop().unwrap();
|
let name = terms.pop().unwrap();
|
||||||
|
|
||||||
@@ -171,8 +163,7 @@ fn setup_module_decl(
|
|||||||
}
|
}
|
||||||
.ok_or(CompilationError::InvalidModuleDecl)?;
|
.ok_or(CompilationError::InvalidModuleDecl)?;
|
||||||
|
|
||||||
let exports = setup_module_export_list(export_list, atom_tbl)?;
|
let exports = setup_module_export_list(export_list)?;
|
||||||
|
|
||||||
Ok(ModuleDecl { name, exports })
|
Ok(ModuleDecl { name, exports })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,10 +182,7 @@ fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, Compilati
|
|||||||
|
|
||||||
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
|
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
|
||||||
|
|
||||||
fn setup_qualified_import(
|
fn setup_qualified_import(mut terms: Vec<Term>) -> Result<UseModuleExport, CompilationError> {
|
||||||
mut terms: Vec<Term>,
|
|
||||||
atom_tbl: &AtomTable,
|
|
||||||
) -> Result<UseModuleExport, CompilationError> {
|
|
||||||
let mut export_list = terms.pop().unwrap();
|
let mut export_list = terms.pop().unwrap();
|
||||||
let module_src = match terms.pop().unwrap() {
|
let module_src = match terms.pop().unwrap() {
|
||||||
Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
|
Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
|
||||||
@@ -210,7 +198,7 @@ fn setup_qualified_import(
|
|||||||
let mut exports = IndexSet::new();
|
let mut exports = IndexSet::new();
|
||||||
|
|
||||||
while let Term::Cons(_, t1, t2) = export_list {
|
while let Term::Cons(_, t1, t2) = export_list {
|
||||||
exports.insert(setup_module_export(*t1, atom_tbl)?);
|
exports.insert(setup_module_export(*t1)?);
|
||||||
export_list = *t2;
|
export_list = *t2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +240,7 @@ fn setup_qualified_import(
|
|||||||
* contained in src/lib/ops_and_meta_predicates.pl, which is loaded before
|
* contained in src/lib/ops_and_meta_predicates.pl, which is loaded before
|
||||||
* src/lib/builtins.pl.
|
* src/lib/builtins.pl.
|
||||||
*
|
*
|
||||||
* Meta-specs have three forms:
|
* Meta-specs have four forms:
|
||||||
*
|
*
|
||||||
* (:) (the argument should be expanded with (:)/2 as described above)
|
* (:) (the argument should be expanded with (:)/2 as described above)
|
||||||
* + (mode declarations under the mode syntax, which currently have no effect)
|
* + (mode declarations under the mode syntax, which currently have no effect)
|
||||||
@@ -340,23 +328,15 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
|
|||||||
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
||||||
Ok(Declaration::Dynamic(name, arity))
|
Ok(Declaration::Dynamic(name, arity))
|
||||||
}
|
}
|
||||||
(atom!("module"), 2) => {
|
(atom!("module"), 2) => Ok(Declaration::Module(setup_module_decl(terms)?)),
|
||||||
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
|
(atom!("op"), 3) => Ok(Declaration::Op(setup_op_decl(terms)?)),
|
||||||
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) => {
|
(atom!("non_counted_backtracking"), 1) => {
|
||||||
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
||||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||||
}
|
}
|
||||||
(atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
|
(atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
|
||||||
(atom!("use_module"), 2) => {
|
(atom!("use_module"), 2) => {
|
||||||
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
|
let (name, exports) = setup_qualified_import(terms)?;
|
||||||
let (name, exports) = setup_qualified_import(terms, atom_tbl)?;
|
|
||||||
|
|
||||||
Ok(Declaration::UseQualifiedModule(name, exports))
|
Ok(Declaration::UseQualifiedModule(name, exports))
|
||||||
}
|
}
|
||||||
(atom!("meta_predicate"), 1) => {
|
(atom!("meta_predicate"), 1) => {
|
||||||
@@ -444,7 +424,7 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
|
|||||||
|
|
||||||
let term = match term {
|
let term = match term {
|
||||||
Term::Clause(cell, name, mut terms) => {
|
Term::Clause(cell, name, mut terms) => {
|
||||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() {
|
||||||
arg_terms
|
arg_terms
|
||||||
.push(process_term(module_name, Term::Clause(cell, name, terms)));
|
.push(process_term(module_name, Term::Clause(cell, name, terms)));
|
||||||
|
|
||||||
@@ -453,7 +433,10 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
|
|||||||
|
|
||||||
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
|
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
|
||||||
|
|
||||||
terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
|
terms.push(Term::Literal(
|
||||||
|
Cell::default(),
|
||||||
|
Literal::CodeIndexOffset(idx.into()),
|
||||||
|
));
|
||||||
process_term(module_name, Term::Clause(cell, name, terms))
|
process_term(module_name, Term::Clause(cell, name, terms))
|
||||||
}
|
}
|
||||||
Term::Literal(cell, Literal::Atom(name)) => {
|
Term::Literal(cell, Literal::Atom(name)) => {
|
||||||
@@ -464,7 +447,10 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
|
|||||||
Term::Clause(
|
Term::Clause(
|
||||||
cell,
|
cell,
|
||||||
name,
|
name,
|
||||||
vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
|
vec![Term::Literal(
|
||||||
|
Cell::default(),
|
||||||
|
Literal::CodeIndexOffset(idx.into()),
|
||||||
|
)],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -489,7 +475,7 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
|||||||
mut terms: Vec<Term>,
|
mut terms: Vec<Term>,
|
||||||
call_policy: CallPolicy,
|
call_policy: CallPolicy,
|
||||||
) -> QueryTerm {
|
) -> QueryTerm {
|
||||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() {
|
||||||
// supplementary code vector indices are unnecessary for
|
// supplementary code vector indices are unnecessary for
|
||||||
// root-level clauses.
|
// root-level clauses.
|
||||||
terms.pop();
|
terms.pop();
|
||||||
@@ -524,7 +510,7 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
|||||||
mut terms: Vec<Term>,
|
mut terms: Vec<Term>,
|
||||||
call_policy: CallPolicy,
|
call_policy: CallPolicy,
|
||||||
) -> QueryTerm {
|
) -> QueryTerm {
|
||||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() {
|
||||||
// supplementary code vector indices are unnecessary for
|
// supplementary code vector indices are unnecessary for
|
||||||
// root-level clauses.
|
// root-level clauses.
|
||||||
terms.pop();
|
terms.pop();
|
||||||
@@ -605,7 +591,7 @@ impl Preprocessor {
|
|||||||
&mut self,
|
&mut self,
|
||||||
loader: &mut Loader<'a, LS>,
|
loader: &mut Loader<'a, LS>,
|
||||||
term: Term,
|
term: Term,
|
||||||
) -> Result<TopLevel, CompilationError> {
|
) -> Result<PredicateClause, CompilationError> {
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(r, name, mut terms) => {
|
Term::Clause(r, name, mut terms) => {
|
||||||
let is_rule = name == atom!(":-") && terms.len() == 2;
|
let is_rule = name == atom!(":-") && terms.len() == 2;
|
||||||
@@ -615,16 +601,16 @@ impl Preprocessor {
|
|||||||
let head = terms.pop().unwrap();
|
let head = terms.pop().unwrap();
|
||||||
|
|
||||||
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
|
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
|
||||||
Ok(TopLevel::Rule(rule, var_data))
|
Ok(PredicateClause::Rule(rule, var_data))
|
||||||
} else {
|
} else {
|
||||||
let term = Term::Clause(r, name, terms);
|
let term = Term::Clause(r, name, terms);
|
||||||
let (fact, var_data) = self.setup_fact(term)?;
|
let (fact, var_data) = self.setup_fact(term)?;
|
||||||
Ok(TopLevel::Fact(fact, var_data))
|
Ok(PredicateClause::Fact(fact, var_data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
term => {
|
term => {
|
||||||
let (fact, var_data) = self.setup_fact(term)?;
|
let (fact, var_data) = self.setup_fact(term)?;
|
||||||
Ok(TopLevel::Fact(fact, var_data))
|
Ok(PredicateClause::Fact(fact, var_data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,9 +59,10 @@ impl Index<usize> for AndFrame {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self as *const crate::machine::stack::AndFrame as *const u8;
|
let ptr = self as *const crate::machine::stack::AndFrame as *const u8;
|
||||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
|
||||||
|
|
||||||
&*(ptr as *const HeapCellValue)
|
// This address falls outside the provenance for self, therefore we have to get it
|
||||||
|
// from exposed provenance.
|
||||||
|
&*std::ptr::with_exposed_provenance(ptr.addr() + prelude_offset + index_offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,10 +73,11 @@ impl IndexMut<usize> for AndFrame {
|
|||||||
let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
|
let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self as *mut crate::machine::stack::AndFrame as *const u8;
|
let ptr = self as *mut crate::machine::stack::AndFrame as *mut u8;
|
||||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
|
||||||
|
|
||||||
&mut *(ptr as *mut HeapCellValue)
|
// This address falls outside the provenance for self, therefore we have to get it
|
||||||
|
// from exposed provenance.
|
||||||
|
&mut *std::ptr::with_exposed_provenance_mut(ptr.addr() + prelude_offset + index_offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,20 +87,14 @@ impl Index<usize> for Stack {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
unsafe {
|
unsafe { &*self.buf.base.add(index).cast() }
|
||||||
let ptr = self.buf.base as usize + index;
|
|
||||||
&*(ptr as *const HeapCellValue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexMut<usize> for Stack {
|
impl IndexMut<usize> for Stack {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
unsafe {
|
unsafe { &mut *self.buf.base.add(index).cast_mut().cast() }
|
||||||
let ptr = self.buf.base as usize + index;
|
|
||||||
&mut *(ptr as *mut HeapCellValue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,9 +128,10 @@ impl Index<usize> for OrFrame {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self as *const crate::machine::stack::OrFrame as *const u8;
|
let ptr = self as *const crate::machine::stack::OrFrame as *const u8;
|
||||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
|
||||||
|
|
||||||
&*(ptr as *const HeapCellValue)
|
// This address falls outside the provenance for self, therefore we have to get it
|
||||||
|
// from exposed provenance.
|
||||||
|
&*std::ptr::with_exposed_provenance(ptr.addr() + prelude_offset + index_offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,10 +143,11 @@ impl IndexMut<usize> for OrFrame {
|
|||||||
let index_offset = index * mem::size_of::<HeapCellValue>();
|
let index_offset = index * mem::size_of::<HeapCellValue>();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self as *mut crate::machine::stack::OrFrame as *const u8;
|
let ptr = self as *mut crate::machine::stack::OrFrame as *mut u8;
|
||||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
|
||||||
|
|
||||||
&mut *(ptr as *mut HeapCellValue)
|
// This address falls outside the provenance for self, therefore we have to get it
|
||||||
|
// from exposed provenance.
|
||||||
|
&mut *std::ptr::with_exposed_provenance_mut(ptr.addr() + prelude_offset + index_offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,15 +185,19 @@ impl Stack {
|
|||||||
let frame_size = AndFrame::size_of(num_cells);
|
let frame_size = AndFrame::size_of(num_cells);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let e = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
|
let e = (*self.buf.ptr.get_mut()).addr() - self.buf.base.addr();
|
||||||
let new_ptr = self.alloc(frame_size);
|
let new_ptr = self.alloc(frame_size);
|
||||||
let mut offset = prelude_size::<AndFramePrelude>();
|
let mut offset = prelude_size::<AndFramePrelude>();
|
||||||
|
|
||||||
for idx in 0..num_cells {
|
for idx in 0..num_cells {
|
||||||
ptr::write(
|
let cell_ptr = new_ptr.add(offset) as *mut HeapCellValue;
|
||||||
new_ptr.add(offset) as *mut HeapCellValue,
|
ptr::write(cell_ptr, stack_loc_as_cell!(AndFrame, e, idx + 1));
|
||||||
stack_loc_as_cell!(AndFrame, e, idx + 1),
|
|
||||||
);
|
// Because in the Index and IndexMut inplementations we need to get this from
|
||||||
|
// exposed provenance, we need to expose the provenance here, even though we don't
|
||||||
|
// actually use the value for anything. This is a reminder that `expose_provenance`
|
||||||
|
// isn't just a cast from a pointer to an integer but has actual side effects.
|
||||||
|
cell_ptr.expose_provenance();
|
||||||
|
|
||||||
offset += mem::size_of::<HeapCellValue>();
|
offset += mem::size_of::<HeapCellValue>();
|
||||||
}
|
}
|
||||||
@@ -208,22 +210,26 @@ impl Stack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn top(&self) -> usize {
|
pub(crate) fn top(&self) -> usize {
|
||||||
unsafe { (*self.buf.ptr.get()) as usize - self.buf.base as usize }
|
unsafe { (*self.buf.ptr.get()).addr() - self.buf.base.addr() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
|
pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
|
||||||
let frame_size = OrFrame::size_of(num_cells);
|
let frame_size = OrFrame::size_of(num_cells);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let b = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
|
let b = (*self.buf.ptr.get_mut()).addr() - self.buf.base.addr();
|
||||||
let new_ptr = self.alloc(frame_size);
|
let new_ptr = self.alloc(frame_size);
|
||||||
let mut offset = prelude_size::<OrFramePrelude>();
|
let mut offset = prelude_size::<OrFramePrelude>();
|
||||||
|
|
||||||
for idx in 0..num_cells {
|
for idx in 0..num_cells {
|
||||||
ptr::write(
|
let cell_ptr = new_ptr.byte_add(offset) as *mut HeapCellValue;
|
||||||
(new_ptr as usize + offset) as *mut HeapCellValue,
|
ptr::write(cell_ptr, stack_loc_as_cell!(OrFrame, b, idx));
|
||||||
stack_loc_as_cell!(OrFrame, b, idx),
|
|
||||||
);
|
// Because in the Index and IndexMut inplementations we need to get this from
|
||||||
|
// exposed provenance, we need to expose the provenance here, even though we don't
|
||||||
|
// actually use the value for anything. This is a reminder that `expose_provenance`
|
||||||
|
// isn't just a cast from a pointer to an integer but has actual side effects.
|
||||||
|
cell_ptr.expose_provenance();
|
||||||
|
|
||||||
offset += mem::size_of::<HeapCellValue>();
|
offset += mem::size_of::<HeapCellValue>();
|
||||||
}
|
}
|
||||||
@@ -237,10 +243,7 @@ impl Stack {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame {
|
pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame {
|
||||||
unsafe {
|
unsafe { &*self.buf.base.add(e).cast() }
|
||||||
let ptr = self.buf.base as usize + e;
|
|
||||||
&*(ptr as *const AndFrame)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -254,26 +257,20 @@ impl Stack {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame {
|
pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame {
|
||||||
unsafe {
|
unsafe { &*self.buf.base.add(b).cast() }
|
||||||
let ptr = self.buf.base as usize + b;
|
|
||||||
&*(ptr as *const OrFrame)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
|
pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
|
||||||
unsafe {
|
unsafe { &mut *self.buf.base.add(b).cast_mut().cast() }
|
||||||
let ptr = self.buf.base as usize + b;
|
|
||||||
&mut *(ptr as *mut OrFrame)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn truncate(&mut self, b: usize) {
|
pub(crate) fn truncate(&mut self, b: usize) {
|
||||||
let base = self.buf.base as usize + b;
|
let base = unsafe { self.buf.base.add(b) };
|
||||||
|
|
||||||
if base < (*self.buf.ptr.get_mut()) as usize {
|
if base < (*self.buf.ptr.get_mut()) {
|
||||||
*self.buf.ptr.get_mut() = base as *mut _;
|
*self.buf.ptr.get_mut() = base.cast_mut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
|
use crate::functor_macro::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::char_reader::*;
|
use crate::parser::char_reader::*;
|
||||||
use crate::read::*;
|
use crate::read::*;
|
||||||
|
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
use crate::http::HttpResponse;
|
use crate::http::HttpResponse;
|
||||||
use crate::machine::heap::*;
|
|
||||||
use crate::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::machine::machine_state::*;
|
use crate::machine::machine_state::*;
|
||||||
@@ -23,6 +23,8 @@ use std::fmt::Debug;
|
|||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::io::PipeReader;
|
||||||
|
use std::io::PipeWriter;
|
||||||
use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||||
use std::mem::ManuallyDrop;
|
use std::mem::ManuallyDrop;
|
||||||
use std::net::{Shutdown, TcpStream};
|
use std::net::{Shutdown, TcpStream};
|
||||||
@@ -476,7 +478,7 @@ impl StreamOptions {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_alias(self) -> Option<Atom> {
|
pub fn get_alias(self) -> Option<Atom> {
|
||||||
if self.has_alias() {
|
if self.has_alias() {
|
||||||
Some(Atom::from(self.alias() << 3))
|
Some(Atom::from(self.alias()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -487,7 +489,7 @@ impl StreamOptions {
|
|||||||
self.set_has_alias(alias.is_some());
|
self.set_has_alias(alias.is_some());
|
||||||
|
|
||||||
if let Some(alias) = alias {
|
if let Some(alias) = alias {
|
||||||
self.set_alias(alias.flat_index());
|
self.set_alias(alias.index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -588,6 +590,8 @@ arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream);
|
|||||||
arena_allocated_impl_for_stream!(StandardErrorStream, StandardErrorStream);
|
arena_allocated_impl_for_stream!(StandardErrorStream, StandardErrorStream);
|
||||||
arena_allocated_impl_for_stream!(CharReader<CallbackStream>, CallbackStream);
|
arena_allocated_impl_for_stream!(CharReader<CallbackStream>, CallbackStream);
|
||||||
arena_allocated_impl_for_stream!(CharReader<InputChannelStream>, InputChannelStream);
|
arena_allocated_impl_for_stream!(CharReader<InputChannelStream>, InputChannelStream);
|
||||||
|
arena_allocated_impl_for_stream!(CharReader<PipeReader>, PipeReader);
|
||||||
|
arena_allocated_impl_for_stream!(CharReader<PipeWriter>, PipeWriter);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Stream {
|
pub enum Stream {
|
||||||
@@ -608,6 +612,8 @@ pub enum Stream {
|
|||||||
StandardError(TypedArenaPtr<StandardErrorStream>),
|
StandardError(TypedArenaPtr<StandardErrorStream>),
|
||||||
Callback(TypedArenaPtr<CallbackStream>),
|
Callback(TypedArenaPtr<CallbackStream>),
|
||||||
InputChannel(TypedArenaPtr<InputChannelStream>),
|
InputChannel(TypedArenaPtr<InputChannelStream>),
|
||||||
|
PipeReader(TypedArenaPtr<PipeReader>),
|
||||||
|
PipeWriter(TypedArenaPtr<PipeWriter>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TypedArenaPtr<ReadlineStream>> for Stream {
|
impl From<TypedArenaPtr<ReadlineStream>> for Stream {
|
||||||
@@ -688,6 +694,8 @@ impl Stream {
|
|||||||
ArenaHeaderTag::InputChannelStream => {
|
ArenaHeaderTag::InputChannelStream => {
|
||||||
Stream::InputChannel(unsafe { ptr.as_typed_ptr() })
|
Stream::InputChannel(unsafe { ptr.as_typed_ptr() })
|
||||||
}
|
}
|
||||||
|
ArenaHeaderTag::PipeReader => Stream::PipeReader(unsafe { ptr.as_typed_ptr() }),
|
||||||
|
ArenaHeaderTag::PipeWriter => Stream::PipeWriter(unsafe { ptr.as_typed_ptr() }),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -726,6 +734,8 @@ impl Stream {
|
|||||||
Stream::StandardError(ptr) => ptr.header_ptr(),
|
Stream::StandardError(ptr) => ptr.header_ptr(),
|
||||||
Stream::Callback(ptr) => ptr.header_ptr(),
|
Stream::Callback(ptr) => ptr.header_ptr(),
|
||||||
Stream::InputChannel(ptr) => ptr.header_ptr(),
|
Stream::InputChannel(ptr) => ptr.header_ptr(),
|
||||||
|
Stream::PipeReader(ptr) => ptr.header_ptr(),
|
||||||
|
Stream::PipeWriter(ptr) => ptr.header_ptr(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,6 +758,8 @@ impl Stream {
|
|||||||
Stream::StandardError(ref ptr) => &ptr.options,
|
Stream::StandardError(ref ptr) => &ptr.options,
|
||||||
Stream::Callback(ref ptr) => &ptr.options,
|
Stream::Callback(ref ptr) => &ptr.options,
|
||||||
Stream::InputChannel(ref ptr) => &ptr.options,
|
Stream::InputChannel(ref ptr) => &ptr.options,
|
||||||
|
Stream::PipeReader(ref ptr) => &ptr.options,
|
||||||
|
Stream::PipeWriter(ref ptr) => &ptr.options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,6 +782,8 @@ impl Stream {
|
|||||||
Stream::StandardError(ref mut ptr) => &mut ptr.options,
|
Stream::StandardError(ref mut ptr) => &mut ptr.options,
|
||||||
Stream::Callback(ref mut ptr) => &mut ptr.options,
|
Stream::Callback(ref mut ptr) => &mut ptr.options,
|
||||||
Stream::InputChannel(ref mut ptr) => &mut ptr.options,
|
Stream::InputChannel(ref mut ptr) => &mut ptr.options,
|
||||||
|
Stream::PipeReader(ref mut ptr) => &mut ptr.options,
|
||||||
|
Stream::PipeWriter(ref mut ptr) => &mut ptr.options,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -793,6 +807,8 @@ impl Stream {
|
|||||||
Stream::StandardError(ptr) => ptr.lines_read += incr_num_lines_read,
|
Stream::StandardError(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
Stream::Callback(ptr) => ptr.lines_read += incr_num_lines_read,
|
Stream::Callback(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
Stream::InputChannel(ptr) => ptr.lines_read += incr_num_lines_read,
|
Stream::InputChannel(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
|
Stream::PipeReader(ptr) => ptr.lines_read += incr_num_lines_read,
|
||||||
|
Stream::PipeWriter(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -816,6 +832,8 @@ impl Stream {
|
|||||||
Stream::StandardError(ptr) => ptr.lines_read = value,
|
Stream::StandardError(ptr) => ptr.lines_read = value,
|
||||||
Stream::Callback(ptr) => ptr.lines_read = value,
|
Stream::Callback(ptr) => ptr.lines_read = value,
|
||||||
Stream::InputChannel(ptr) => ptr.lines_read = value,
|
Stream::InputChannel(ptr) => ptr.lines_read = value,
|
||||||
|
Stream::PipeReader(ptr) => ptr.lines_read = value,
|
||||||
|
Stream::PipeWriter(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -839,6 +857,8 @@ impl Stream {
|
|||||||
Stream::StandardError(ptr) => ptr.lines_read,
|
Stream::StandardError(ptr) => ptr.lines_read,
|
||||||
Stream::Callback(ptr) => ptr.lines_read,
|
Stream::Callback(ptr) => ptr.lines_read,
|
||||||
Stream::InputChannel(ptr) => ptr.lines_read,
|
Stream::InputChannel(ptr) => ptr.lines_read,
|
||||||
|
Stream::PipeReader(ptr) => ptr.lines_read,
|
||||||
|
Stream::PipeWriter(_) => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -856,6 +876,8 @@ impl CharRead for Stream {
|
|||||||
Stream::StaticString(src) => (*src).peek_char(),
|
Stream::StaticString(src) => (*src).peek_char(),
|
||||||
Stream::Byte(cursor) => (*cursor).peek_char(),
|
Stream::Byte(cursor) => (*cursor).peek_char(),
|
||||||
Stream::InputChannel(cursor) => (*cursor).peek_char(),
|
Stream::InputChannel(cursor) => (*cursor).peek_char(),
|
||||||
|
Stream::PipeReader(cursor) => (*cursor).peek_char(),
|
||||||
|
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
|
Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
@@ -865,7 +887,8 @@ impl CharRead for Stream {
|
|||||||
| Stream::StandardError(_)
|
| Stream::StandardError(_)
|
||||||
| Stream::StandardOutput(_)
|
| Stream::StandardOutput(_)
|
||||||
| Stream::Null(_)
|
| Stream::Null(_)
|
||||||
| Stream::Callback(_) => Some(Err(std::io::Error::new(
|
| Stream::Callback(_)
|
||||||
|
| Stream::PipeWriter(_) => Some(Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::ReadFromOutputStream,
|
StreamError::ReadFromOutputStream,
|
||||||
))),
|
))),
|
||||||
@@ -884,6 +907,7 @@ impl CharRead for Stream {
|
|||||||
Stream::StaticString(src) => (*src).read_char(),
|
Stream::StaticString(src) => (*src).read_char(),
|
||||||
Stream::Byte(cursor) => (*cursor).read_char(),
|
Stream::Byte(cursor) => (*cursor).read_char(),
|
||||||
Stream::InputChannel(cursor) => (*cursor).read_char(),
|
Stream::InputChannel(cursor) => (*cursor).read_char(),
|
||||||
|
Stream::PipeReader(cursor) => (*cursor).read_char(),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
|
Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
@@ -893,7 +917,8 @@ impl CharRead for Stream {
|
|||||||
| Stream::StandardError(_)
|
| Stream::StandardError(_)
|
||||||
| Stream::StandardOutput(_)
|
| Stream::StandardOutput(_)
|
||||||
| Stream::Null(_)
|
| Stream::Null(_)
|
||||||
| Stream::Callback(_) => Some(Err(std::io::Error::new(
|
| Stream::Callback(_)
|
||||||
|
| Stream::PipeWriter(_) => Some(Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::ReadFromOutputStream,
|
StreamError::ReadFromOutputStream,
|
||||||
))),
|
))),
|
||||||
@@ -911,13 +936,15 @@ impl CharRead for Stream {
|
|||||||
Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
|
Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
|
||||||
Stream::StaticString(src) => src.put_back_char(c),
|
Stream::StaticString(src) => src.put_back_char(c),
|
||||||
Stream::Byte(cursor) => cursor.put_back_char(c),
|
Stream::Byte(cursor) => cursor.put_back_char(c),
|
||||||
|
Stream::PipeReader(cursor) => cursor.put_back_char(c),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
Stream::HttpWrite(_) => {}
|
Stream::HttpWrite(_) => {}
|
||||||
Stream::OutputFile(_)
|
Stream::OutputFile(_)
|
||||||
| Stream::StandardError(_)
|
| Stream::StandardError(_)
|
||||||
| Stream::StandardOutput(_)
|
| Stream::StandardOutput(_)
|
||||||
| Stream::Null(_)
|
| Stream::Null(_)
|
||||||
| Stream::Callback(_) => {}
|
| Stream::Callback(_)
|
||||||
|
| Stream::PipeWriter(_) => {}
|
||||||
Stream::InputChannel(_) => {}
|
Stream::InputChannel(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -934,13 +961,15 @@ impl CharRead for Stream {
|
|||||||
Stream::StaticString(ref mut src) => src.consume(nread),
|
Stream::StaticString(ref mut src) => src.consume(nread),
|
||||||
Stream::Byte(ref mut cursor) => cursor.consume(nread),
|
Stream::Byte(ref mut cursor) => cursor.consume(nread),
|
||||||
Stream::InputChannel(ref mut cursor) => cursor.consume(nread),
|
Stream::InputChannel(ref mut cursor) => cursor.consume(nread),
|
||||||
|
Stream::PipeReader(ref mut cursor) => cursor.consume(nread),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
Stream::HttpWrite(_) => {}
|
Stream::HttpWrite(_) => {}
|
||||||
Stream::OutputFile(_)
|
Stream::OutputFile(_)
|
||||||
| Stream::StandardError(_)
|
| Stream::StandardError(_)
|
||||||
| Stream::StandardOutput(_)
|
| Stream::StandardOutput(_)
|
||||||
| Stream::Null(_)
|
| Stream::Null(_)
|
||||||
| Stream::Callback(_) => {}
|
| Stream::Callback(_)
|
||||||
|
| Stream::PipeWriter(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -959,6 +988,7 @@ impl Read for Stream {
|
|||||||
Stream::StaticString(src) => (*src).read(buf),
|
Stream::StaticString(src) => (*src).read(buf),
|
||||||
Stream::Byte(cursor) => (*cursor).read(buf),
|
Stream::Byte(cursor) => (*cursor).read(buf),
|
||||||
Stream::InputChannel(cursor) => (*cursor).read(buf),
|
Stream::InputChannel(cursor) => (*cursor).read(buf),
|
||||||
|
Stream::PipeReader(cursor) => (*cursor).read(buf),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
Stream::HttpWrite(_) => Err(std::io::Error::new(
|
Stream::HttpWrite(_) => Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
@@ -967,7 +997,8 @@ impl Read for Stream {
|
|||||||
Stream::OutputFile(_)
|
Stream::OutputFile(_)
|
||||||
| Stream::StandardError(_)
|
| Stream::StandardError(_)
|
||||||
| Stream::StandardOutput(_)
|
| Stream::StandardOutput(_)
|
||||||
| Stream::Callback(_) => Err(std::io::Error::new(
|
| Stream::Callback(_)
|
||||||
|
| Stream::PipeWriter(_) => Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::ReadFromOutputStream,
|
StreamError::ReadFromOutputStream,
|
||||||
)),
|
)),
|
||||||
@@ -989,6 +1020,7 @@ impl Write for Stream {
|
|||||||
Stream::StandardError(stream) => stream.write(buf),
|
Stream::StandardError(stream) => stream.write(buf),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
|
Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
|
||||||
|
Stream::PipeWriter(ref mut stream) => stream.get_mut().write(buf),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
Stream::HttpRead(_) => Err(std::io::Error::new(
|
Stream::HttpRead(_) => Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
@@ -998,7 +1030,8 @@ impl Write for Stream {
|
|||||||
Stream::StaticString(_)
|
Stream::StaticString(_)
|
||||||
| Stream::InputChannel(_)
|
| Stream::InputChannel(_)
|
||||||
| Stream::Readline(_)
|
| Stream::Readline(_)
|
||||||
| Stream::InputFile(..) => Err(std::io::Error::new(
|
| Stream::InputFile(..)
|
||||||
|
| Stream::PipeReader(_) => Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::WriteToInputStream,
|
StreamError::WriteToInputStream,
|
||||||
)),
|
)),
|
||||||
@@ -1015,6 +1048,7 @@ impl Write for Stream {
|
|||||||
Stream::Callback(ref mut callback_stream) => callback_stream.stream.get_mut().flush(),
|
Stream::Callback(ref mut callback_stream) => callback_stream.stream.get_mut().flush(),
|
||||||
Stream::StandardError(stream) => stream.stream.flush(),
|
Stream::StandardError(stream) => stream.stream.flush(),
|
||||||
Stream::StandardOutput(stream) => stream.stream.flush(),
|
Stream::StandardOutput(stream) => stream.stream.flush(),
|
||||||
|
Stream::PipeWriter(ref mut stream) => stream.stream.get_mut().flush(),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
|
Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
@@ -1026,7 +1060,8 @@ impl Write for Stream {
|
|||||||
Stream::StaticString(_)
|
Stream::StaticString(_)
|
||||||
| Stream::InputChannel(_)
|
| Stream::InputChannel(_)
|
||||||
| Stream::Readline(_)
|
| Stream::Readline(_)
|
||||||
| Stream::InputFile(_) => Err(std::io::Error::new(
|
| Stream::InputFile(_)
|
||||||
|
| Stream::PipeReader(_) => Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::FlushToInputStream,
|
StreamError::FlushToInputStream,
|
||||||
)),
|
)),
|
||||||
@@ -1192,6 +1227,8 @@ impl Stream {
|
|||||||
Stream::StandardError(stream) => stream.past_end_of_stream,
|
Stream::StandardError(stream) => stream.past_end_of_stream,
|
||||||
Stream::Callback(stream) => stream.past_end_of_stream,
|
Stream::Callback(stream) => stream.past_end_of_stream,
|
||||||
Stream::InputChannel(stream) => stream.past_end_of_stream,
|
Stream::InputChannel(stream) => stream.past_end_of_stream,
|
||||||
|
Stream::PipeReader(stream) => stream.past_end_of_stream,
|
||||||
|
Stream::PipeWriter(stream) => stream.past_end_of_stream,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1220,6 +1257,8 @@ impl Stream {
|
|||||||
Stream::StandardError(stream) => stream.past_end_of_stream = value,
|
Stream::StandardError(stream) => stream.past_end_of_stream = value,
|
||||||
Stream::Callback(stream) => stream.past_end_of_stream = value,
|
Stream::Callback(stream) => stream.past_end_of_stream = value,
|
||||||
Stream::InputChannel(stream) => stream.past_end_of_stream = value,
|
Stream::InputChannel(stream) => stream.past_end_of_stream = value,
|
||||||
|
Stream::PipeReader(stream) => stream.past_end_of_stream = value,
|
||||||
|
Stream::PipeWriter(stream) => stream.past_end_of_stream = value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1330,7 +1369,8 @@ impl Stream {
|
|||||||
| Stream::InputChannel(_)
|
| Stream::InputChannel(_)
|
||||||
| Stream::Readline(_)
|
| Stream::Readline(_)
|
||||||
| Stream::StaticString(_)
|
| Stream::StaticString(_)
|
||||||
| Stream::InputFile(..) => atom!("read"),
|
| Stream::InputFile(..)
|
||||||
|
| Stream::PipeReader(_) => atom!("read"),
|
||||||
Stream::NamedTcp(..) => atom!("read_append"),
|
Stream::NamedTcp(..) => atom!("read_append"),
|
||||||
Stream::OutputFile(file) if file.is_append => atom!("append"),
|
Stream::OutputFile(file) if file.is_append => atom!("append"),
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
@@ -1338,7 +1378,8 @@ impl Stream {
|
|||||||
Stream::OutputFile(_)
|
Stream::OutputFile(_)
|
||||||
| Stream::StandardError(_)
|
| Stream::StandardError(_)
|
||||||
| Stream::StandardOutput(_)
|
| Stream::StandardOutput(_)
|
||||||
| Stream::Callback(_) => {
|
| Stream::Callback(_)
|
||||||
|
| Stream::PipeWriter(_) => {
|
||||||
atom!("write")
|
atom!("write")
|
||||||
}
|
}
|
||||||
Stream::Null(_) => atom!(""),
|
Stream::Null(_) => atom!(""),
|
||||||
@@ -1372,6 +1413,20 @@ impl Stream {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_pipe_writer(writer: io::PipeWriter, arena: &mut Arena) -> Stream {
|
||||||
|
Stream::PipeWriter(arena_alloc!(
|
||||||
|
ManuallyDrop::new(StreamLayout::new(CharReader::new(writer))),
|
||||||
|
arena
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_pipe_reader(reader: io::PipeReader, arena: &mut Arena) -> Stream {
|
||||||
|
Stream::PipeReader(arena_alloc!(
|
||||||
|
ManuallyDrop::new(StreamLayout::new(CharReader::new(reader))),
|
||||||
|
arena
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn from_tcp_stream(address: Atom, tcp_stream: TcpStream, arena: &mut Arena) -> Self {
|
pub(crate) fn from_tcp_stream(address: Atom, tcp_stream: TcpStream, arena: &mut Arena) -> Self {
|
||||||
tcp_stream.set_read_timeout(None).unwrap();
|
tcp_stream.set_read_timeout(None).unwrap();
|
||||||
@@ -1512,6 +1567,16 @@ impl Stream {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stream::PipeReader(mut stream) => {
|
||||||
|
stream.drop_payload();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream::PipeWriter(mut stream) => {
|
||||||
|
stream.drop_payload();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
Stream::Null(_) => Ok(()),
|
Stream::Null(_) => Ok(()),
|
||||||
|
|
||||||
Stream::Readline(_) | Stream::StandardOutput(_) | Stream::StandardError(_) => {
|
Stream::Readline(_) | Stream::StandardOutput(_) | Stream::StandardError(_) => {
|
||||||
@@ -1538,6 +1603,7 @@ impl Stream {
|
|||||||
| Stream::Readline(_)
|
| Stream::Readline(_)
|
||||||
| Stream::StaticString(_)
|
| Stream::StaticString(_)
|
||||||
| Stream::InputFile(..)
|
| Stream::InputFile(..)
|
||||||
|
| Stream::PipeReader(_)
|
||||||
| Stream::Null(_) => true,
|
| Stream::Null(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@@ -1556,6 +1622,7 @@ impl Stream {
|
|||||||
| Stream::Byte(_)
|
| Stream::Byte(_)
|
||||||
| Stream::OutputFile(..)
|
| Stream::OutputFile(..)
|
||||||
| Stream::Callback(_)
|
| Stream::Callback(_)
|
||||||
|
| Stream::PipeWriter(_)
|
||||||
| Stream::Null(_) => true,
|
| Stream::Null(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@@ -1653,7 +1720,8 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
stream.set_past_end_of_stream(true);
|
stream.set_past_end_of_stream(true);
|
||||||
Ok(unify!(self, result, end_of_stream))
|
unify!(self, result, end_of_stream);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
EOFAction::Reset => {
|
EOFAction::Reset => {
|
||||||
if !stream.reset() {
|
if !stream.reset() {
|
||||||
@@ -1808,59 +1876,60 @@ impl MachineState {
|
|||||||
let addr = self.store(MachineState::deref(self, addr));
|
let addr = self.store(MachineState::deref(self, addr));
|
||||||
|
|
||||||
read_heap_cell!(addr,
|
read_heap_cell!(addr,
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
debug_assert_eq!(arity, 0);
|
debug_assert_eq!(arity, 0);
|
||||||
|
|
||||||
return match indices.get_stream(name) {
|
return match indices.get_stream(name) {
|
||||||
Some(stream) => Ok(stream),
|
Some(stream) => Ok(stream),
|
||||||
_ => {
|
_ => {
|
||||||
let stub = functor_stub(caller, arity);
|
let stub = functor_stub(caller, arity);
|
||||||
let addr = atom_as_cell!(name);
|
let addr = atom_as_cell!(name);
|
||||||
|
|
||||||
let existence_error = self.existence_error(ExistenceError::Stream(addr));
|
let existence_error = self.existence_error(ExistenceError::Stream(addr));
|
||||||
|
|
||||||
Err(self.error_form(existence_error, stub))
|
Err(self.error_form(existence_error, stub))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
.get_name_and_arity();
|
.get_name_and_arity();
|
||||||
|
|
||||||
debug_assert_eq!(arity, 0);
|
debug_assert_eq!(arity, 0);
|
||||||
|
|
||||||
return match indices.get_stream(name) {
|
return match indices.get_stream(name) {
|
||||||
Some(stream) => Ok(stream),
|
Some(stream) => Ok(stream),
|
||||||
_ => {
|
_ => {
|
||||||
let stub = functor_stub(caller, arity);
|
let stub = functor_stub(caller, arity);
|
||||||
let addr = atom_as_cell!(name);
|
let addr = atom_as_cell!(name);
|
||||||
|
|
||||||
let existence_error = self.existence_error(ExistenceError::Stream(addr));
|
let existence_error = self.existence_error(ExistenceError::Stream(addr));
|
||||||
|
|
||||||
Err(self.error_form(existence_error, stub))
|
Err(self.error_form(existence_error, stub))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Cons, ptr) => {
|
(HeapCellValueTag::Cons, ptr) => {
|
||||||
match_untyped_arena_ptr!(ptr,
|
match_untyped_arena_ptr!(ptr,
|
||||||
(ArenaHeaderTag::Stream, stream) => {
|
(ArenaHeaderTag::Stream, stream) => {
|
||||||
if stream.is_null_stream() {
|
return if stream.is_null_stream() {
|
||||||
unreachable!("Null streams have no Cons representation");
|
Err(self.open_permission_error(stream_as_cell!(stream), caller, arity))
|
||||||
}
|
} else {
|
||||||
return Ok(stream);
|
Ok(stream)
|
||||||
}
|
};
|
||||||
(ArenaHeaderTag::Dropped, _value) => {
|
}
|
||||||
let stub = functor_stub(caller, arity);
|
(ArenaHeaderTag::Dropped, _value) => {
|
||||||
let err = self.existence_error(ExistenceError::Stream(addr));
|
let stub = functor_stub(caller, arity);
|
||||||
|
let err = self.existence_error(ExistenceError::Stream(addr));
|
||||||
|
|
||||||
return Err(self.error_form(err, stub));
|
return Err(self.error_form(err, stub));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let stub = functor_stub(caller, arity);
|
let stub = functor_stub(caller, arity);
|
||||||
@@ -1953,7 +2022,7 @@ impl MachineState {
|
|||||||
let err = self.permission_error(
|
let err = self.permission_error(
|
||||||
Permission::Open,
|
Permission::Open,
|
||||||
atom!("source_sink"),
|
atom!("source_sink"),
|
||||||
functor!(atom!("alias"), [atom(alias)]),
|
functor!(atom!("alias"), [atom_as_cell(alias)]),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.error_form(err, stub)
|
self.error_form(err, stub)
|
||||||
@@ -1961,7 +2030,7 @@ impl MachineState {
|
|||||||
|
|
||||||
pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub {
|
pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub {
|
||||||
let stub = functor_stub(stub_name, stub_arity);
|
let stub = functor_stub(stub_name, stub_arity);
|
||||||
let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]);
|
let rep_stub = functor!(atom!("reposition"), [atom_as_cell((atom!("true")))]);
|
||||||
let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub);
|
let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub);
|
||||||
|
|
||||||
self.error_form(err, stub)
|
self.error_form(err, stub)
|
||||||
@@ -2086,7 +2155,7 @@ impl MachineState {
|
|||||||
_ => {
|
_ => {
|
||||||
// assume the OS is out of file descriptors.
|
// assume the OS is out of file descriptors.
|
||||||
let stub = functor_stub(atom!("open"), 4);
|
let stub = functor_stub(atom!("open"), 4);
|
||||||
let err = self.resource_error(ResourceError::OutOfFiles);
|
let err = Self::resource_error(ResourceError::OutOfFiles);
|
||||||
|
|
||||||
return Err(self.error_form(err, stub));
|
return Err(self.error_form(err, stub));
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@ use crate::machine::loader::*;
|
|||||||
use crate::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::machine::*;
|
use crate::machine::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
|
use crate::parser::lexer::*;
|
||||||
use crate::parser::parser::*;
|
use crate::parser::parser::*;
|
||||||
use crate::read::devour_whitespace;
|
use crate::read::devour_whitespace;
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eof(&mut self) -> Result<bool, CompilationError> {
|
fn eof(&mut self) -> Result<bool, CompilationError> {
|
||||||
devour_whitespace(&mut self.parser) // eliminate dangling comments before checking for EOF.
|
devour_whitespace(&mut self.parser.lexer) // eliminate dangling comments before checking for EOF.
|
||||||
.map_err(CompilationError::from)
|
.map_err(CompilationError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ use crate::arena::*;
|
|||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
use crate::heap_iter::{stackful_preorder_iter, NonListElider};
|
use crate::heap_iter::{stackful_preorder_iter, NonListElider};
|
||||||
use crate::machine::machine_state::*;
|
use crate::machine::machine_state::*;
|
||||||
use crate::machine::partial_string::*;
|
|
||||||
use crate::machine::*;
|
use crate::machine::*;
|
||||||
|
use crate::offset_table::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use derive_more::*;
|
use derive_more::*;
|
||||||
@@ -14,6 +13,18 @@ use fxhash::FxBuildHasher;
|
|||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use num_order::NumOrd;
|
use num_order::NumOrd;
|
||||||
|
|
||||||
|
impl MachineState {
|
||||||
|
pub(crate) fn partial_string_to_pdl(&mut self, pstr_loc: usize, l: usize) {
|
||||||
|
let (c, succ_cell) = self.heap.last_str_char_and_tail(pstr_loc);
|
||||||
|
|
||||||
|
self.pdl.push(heap_loc_as_cell!(l + 1));
|
||||||
|
self.pdl.push(succ_cell);
|
||||||
|
|
||||||
|
self.pdl.push(heap_loc_as_cell!(l));
|
||||||
|
self.pdl.push(char_as_cell!(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
||||||
fn unify_structure(&mut self, s1: usize, value: HeapCellValue) {
|
fn unify_structure(&mut self, s1: usize, value: HeapCellValue) {
|
||||||
// s1 is the value of a STR cell.
|
// s1 is the value of a STR cell.
|
||||||
@@ -82,8 +93,8 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
self.fail = true;
|
self.fail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => {
|
(HeapCellValueTag::PStrLoc, l) => {
|
||||||
Self::unify_partial_string(self, list_loc_as_cell!(l1), value)
|
Self::unify_partial_string(self, l, list_loc_as_cell!(l1))
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::AttrVar, h) => {
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
Self::bind(self, Ref::attr_var(h), list_loc_as_cell!(l1));
|
Self::bind(self, Ref::attr_var(h), list_loc_as_cell!(l1));
|
||||||
@@ -100,261 +111,43 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) {
|
fn unify_partial_string(&mut self, pstr_loc: usize, value: HeapCellValue) {
|
||||||
if let Some(r) = value.as_var() {
|
if let Some(r) = value.as_var() {
|
||||||
if atom == atom!("") {
|
Self::bind(self, r, pstr_loc_as_cell!(pstr_loc));
|
||||||
Self::bind(self, r, atom_as_cell!(atom!("[]")));
|
|
||||||
} else {
|
|
||||||
Self::bind(self, r, atom_as_cstr_cell!(atom));
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
read_heap_cell!(value,
|
|
||||||
(HeapCellValueTag::Atom, (cstr_atom, arity)) if atom == atom!("") => {
|
|
||||||
debug_assert_eq!(arity, 0);
|
|
||||||
self.fail = cstr_atom != atom!("[]");
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s) => {
|
|
||||||
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
|
||||||
.get_name_and_arity();
|
|
||||||
|
|
||||||
if arity == 0 {
|
|
||||||
self.fail = atom == atom!("") && name != atom!("[]");
|
|
||||||
} else {
|
|
||||||
// this is intentionally the same policy for
|
|
||||||
// value.tag() == Lis and PStrLoc. they're not
|
|
||||||
// grouped together to allow for arity == 0.
|
|
||||||
Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value);
|
|
||||||
|
|
||||||
if !self.pdl.is_empty() {
|
|
||||||
Self::unify_internal(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::CStr, cstr_atom) => {
|
|
||||||
self.fail = atom != cstr_atom;
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
|
|
||||||
Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value);
|
|
||||||
|
|
||||||
if !self.pdl.is_empty() {
|
|
||||||
Self::unify_internal(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the return value of unify_partial_string is interpreted as
|
|
||||||
// follows:
|
|
||||||
//
|
|
||||||
// Some(None) -- the strings are equal, nothing to unify
|
|
||||||
// Some(Some(f2,f1)) -- prefixes equal, try to unify focus values f2, f1
|
|
||||||
// None -- prefixes not equal, unification fails
|
|
||||||
//
|
|
||||||
// d1's tag is assumed to be one of LIS, STR or PSTRLOC.
|
|
||||||
fn unify_partial_string(&mut self, value_1: HeapCellValue, value_2: HeapCellValue) {
|
|
||||||
if let Some(r) = value_2.as_var() {
|
|
||||||
Self::bind(self, r, value_1);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let machine_st = self.deref_mut();
|
let machine_st = self.deref_mut();
|
||||||
|
|
||||||
let s1 = machine_st.heap.len();
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
machine_st.heap.push(value_1);
|
if name == atom!(".") && arity == 2 {
|
||||||
machine_st.heap.push(value_2);
|
machine_st.partial_string_to_pdl(pstr_loc, s+1);
|
||||||
|
|
||||||
let mut pstr_iter1 = HeapPStrIter::new(&machine_st.heap, s1);
|
|
||||||
let mut pstr_iter2 = HeapPStrIter::new(&machine_st.heap, s1 + 1);
|
|
||||||
|
|
||||||
fn unify_sequence(
|
|
||||||
machine_st: &mut MachineState,
|
|
||||||
iter: PStrIteratee,
|
|
||||||
source_cell: HeapCellValue,
|
|
||||||
) -> bool {
|
|
||||||
match iter {
|
|
||||||
PStrIteratee::Char(focus, _) => {
|
|
||||||
machine_st.pdl.push(machine_st.heap[focus]);
|
|
||||||
machine_st.pdl.push(source_cell);
|
|
||||||
}
|
|
||||||
PStrIteratee::PStrSegment(focus, _, n) => {
|
|
||||||
read_heap_cell!(machine_st.heap[focus],
|
|
||||||
(HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => {
|
|
||||||
if focus < machine_st.heap.len() - 2 {
|
|
||||||
machine_st.heap.pop();
|
|
||||||
machine_st.heap.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == 0 {
|
|
||||||
let target_cell = match machine_st.heap[focus].get_tag() {
|
|
||||||
HeapCellValueTag::CStr => {
|
|
||||||
atom_as_cstr_cell!(pstr_atom)
|
|
||||||
}
|
|
||||||
HeapCellValueTag::PStr => {
|
|
||||||
pstr_loc_as_cell!(focus)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
machine_st.pdl.push(target_cell);
|
|
||||||
machine_st.pdl.push(source_cell);
|
|
||||||
} else {
|
|
||||||
let h_len = machine_st.heap.len();
|
|
||||||
|
|
||||||
machine_st.heap.push(pstr_offset_as_cell!(focus));
|
|
||||||
machine_st.heap.push(fixnum_as_cell!(
|
|
||||||
Fixnum::build_with(n as i64)
|
|
||||||
));
|
|
||||||
|
|
||||||
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
|
|
||||||
machine_st.pdl.push(source_cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::PStrOffset, pstr_loc) => {
|
|
||||||
let n0 = cell_as_fixnum!(machine_st.heap[focus+1])
|
|
||||||
.get_num() as usize;
|
|
||||||
|
|
||||||
if pstr_loc < machine_st.heap.len() - 2 {
|
|
||||||
machine_st.heap.pop();
|
|
||||||
machine_st.heap.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == n0 {
|
|
||||||
machine_st.pdl.push(pstr_loc_as_cell!(focus));
|
|
||||||
machine_st.pdl.push(source_cell);
|
|
||||||
} else {
|
|
||||||
let h_len = machine_st.heap.len();
|
|
||||||
|
|
||||||
machine_st.heap.push(pstr_offset_as_cell!(pstr_loc));
|
|
||||||
machine_st.heap.push(fixnum_as_cell!(
|
|
||||||
Fixnum::build_with(n as i64)
|
|
||||||
));
|
|
||||||
|
|
||||||
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
|
|
||||||
machine_st.pdl.push(source_cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if focus < machine_st.heap.len() - 2 {
|
|
||||||
machine_st.heap.pop();
|
|
||||||
machine_st.heap.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
machine_st.pdl.push(machine_st.heap[focus]);
|
|
||||||
machine_st.pdl.push(source_cell);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
|
|
||||||
PStrCmpResult::Ordered(Ordering::Equal) => {}
|
|
||||||
PStrCmpResult::Ordered(Ordering::Less) => {
|
|
||||||
if pstr_iter2.focus.as_var().is_none() {
|
|
||||||
machine_st.fail = true;
|
|
||||||
} else {
|
} else {
|
||||||
machine_st.pdl.push(empty_list_as_cell!());
|
|
||||||
machine_st.pdl.push(pstr_iter2.focus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PStrCmpResult::Ordered(Ordering::Greater) => {
|
|
||||||
if pstr_iter1.focus.as_var().is_none() {
|
|
||||||
machine_st.fail = true;
|
machine_st.fail = true;
|
||||||
} else {
|
|
||||||
machine_st.pdl.push(empty_list_as_cell!());
|
|
||||||
machine_st.pdl.push(pstr_iter1.focus);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continuable @ PStrCmpResult::FirstIterContinuable(iteratee)
|
(HeapCellValueTag::Lis, l) => {
|
||||||
| continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
|
machine_st.partial_string_to_pdl(pstr_loc, l);
|
||||||
if continuable.is_second_iter() {
|
}
|
||||||
std::mem::swap(&mut pstr_iter1, &mut pstr_iter2);
|
(HeapCellValueTag::PStrLoc, other_pstr_loc) => {
|
||||||
}
|
match machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc) {
|
||||||
|
PStrSegmentCmpResult::Continue(v1, v2) => {
|
||||||
let mut chars_iter = PStrCharsIter {
|
machine_st.pdl.push(v1.offset_by(pstr_loc));
|
||||||
iter: pstr_iter1,
|
machine_st.pdl.push(v2.offset_by(other_pstr_loc));
|
||||||
item: Some(iteratee),
|
}
|
||||||
};
|
_ => {
|
||||||
|
machine_st.fail = true;
|
||||||
let mut focus = pstr_iter2.focus;
|
|
||||||
|
|
||||||
'outer: {
|
|
||||||
while let Some(c) = chars_iter.peek() {
|
|
||||||
read_heap_cell!(focus,
|
|
||||||
(HeapCellValueTag::Lis, l) => {
|
|
||||||
let val = pstr_iter2.heap[l];
|
|
||||||
|
|
||||||
machine_st.pdl.push(val);
|
|
||||||
machine_st.pdl.push(char_as_cell!(c));
|
|
||||||
|
|
||||||
focus = pstr_iter2.heap[l+1];
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str, s) => {
|
|
||||||
let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s])
|
|
||||||
.get_name_and_arity();
|
|
||||||
|
|
||||||
if name == atom!(".") && arity == 2 {
|
|
||||||
machine_st.pdl.push(pstr_iter2.heap[s+1]);
|
|
||||||
machine_st.pdl.push(char_as_cell!(c));
|
|
||||||
|
|
||||||
focus = pstr_iter2.heap[s+2];
|
|
||||||
} else {
|
|
||||||
machine_st.fail = true;
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
|
|
||||||
unify_sequence(machine_st, chars_iter.item.unwrap(), focus);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
|
||||||
if unify_sequence(machine_st, chars_iter.item.unwrap(), heap_loc_as_cell!(h)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
machine_st.fail = true;
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
chars_iter.next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chars_iter.iter.next();
|
|
||||||
|
|
||||||
machine_st.pdl.push(focus);
|
|
||||||
machine_st.pdl.push(chars_iter.iter.focus);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PStrCmpResult::Unordered => {
|
_ => {
|
||||||
machine_st.pdl.push(pstr_iter1.focus);
|
machine_st.fail = true;
|
||||||
machine_st.pdl.push(pstr_iter2.focus);
|
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
|
|
||||||
machine_st.heap.pop();
|
|
||||||
machine_st.heap.pop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) {
|
fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) {
|
||||||
@@ -368,16 +161,6 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
|
|
||||||
self.fail = !(arity == 0 && name == atom);
|
self.fail = !(arity == 0 && name == atom);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => {
|
|
||||||
self.fail = cstr_atom != atom!("");
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Char, c1) => {
|
|
||||||
if let Some(c2) = atom.as_char() {
|
|
||||||
self.fail = c1 != c2;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::AttrVar, h) => {
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
Self::bind(self, Ref::attr_var(h), atom_as_cell!(atom));
|
Self::bind(self, Ref::attr_var(h), atom_as_cell!(atom));
|
||||||
}
|
}
|
||||||
@@ -412,11 +195,6 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
self.fail = true;
|
self.fail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Char, c2) => {
|
|
||||||
if c != c2 {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::AttrVar, h) => {
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
Self::bind(self, Ref::attr_var(h), char_as_cell!(c));
|
Self::bind(self, Ref::attr_var(h), char_as_cell!(c));
|
||||||
}
|
}
|
||||||
@@ -438,7 +216,9 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match Number::try_from(value) {
|
let machine_st = self.deref();
|
||||||
|
|
||||||
|
match Number::try_from((value, &machine_st.arena.f64_tbl)) {
|
||||||
Ok(n2) => match n2 {
|
Ok(n2) => match n2 {
|
||||||
Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {}
|
Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {}
|
||||||
Number::Integer(n2) if (*n2).num_eq(&n1.get_num()) => {}
|
Number::Integer(n2) if (*n2).num_eq(&n1.get_num()) => {}
|
||||||
@@ -459,7 +239,9 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match Number::try_from(value) {
|
let machine_st = self.deref();
|
||||||
|
|
||||||
|
match Number::try_from((value, &machine_st.arena.f64_tbl)) {
|
||||||
Ok(n2) => match n2 {
|
Ok(n2) => match n2 {
|
||||||
Number::Fixnum(n2) if (*n1).num_eq(&n2.get_num()) => {}
|
Number::Fixnum(n2) if (*n1).num_eq(&n2.get_num()) => {}
|
||||||
Number::Integer(n2) if (*n1).num_eq(&*n2) => {}
|
Number::Integer(n2) if (*n1).num_eq(&*n2) => {}
|
||||||
@@ -480,7 +262,9 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match Number::try_from(value) {
|
let machine_st = self.deref_mut();
|
||||||
|
|
||||||
|
match Number::try_from((value, &machine_st.arena.f64_tbl)) {
|
||||||
Ok(n2) => match n2 {
|
Ok(n2) => match n2 {
|
||||||
Number::Fixnum(n2) if (*n1).num_eq(&Integer::from(n2.get_num())) => {}
|
Number::Fixnum(n2) if (*n1).num_eq(&Integer::from(n2.get_num())) => {}
|
||||||
Number::Integer(n2) if (*n1).num_eq(&*n2) => {}
|
Number::Integer(n2) if (*n1).num_eq(&*n2) => {}
|
||||||
@@ -495,15 +279,20 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) {
|
fn unify_f64(&mut self, f1: F64Offset, value: HeapCellValue) {
|
||||||
if let Some(r) = value.as_var() {
|
if let Some(r) = value.as_var() {
|
||||||
Self::bind(self, r, HeapCellValue::from(f1));
|
Self::bind(self, r, HeapCellValue::from(f1));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_heap_cell!(value,
|
read_heap_cell!(value,
|
||||||
(HeapCellValueTag::F64, f2) => {
|
(HeapCellValueTag::F64Offset, f2) => {
|
||||||
self.fail = **f1 != **f2;
|
let machine_st = self.deref_mut();
|
||||||
|
|
||||||
|
let f1 = machine_st.arena.f64_tbl.get_entry(f1);
|
||||||
|
let f2 = machine_st.arena.f64_tbl.get_entry(f2);
|
||||||
|
|
||||||
|
self.fail = f1 != f2;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.fail = true;
|
self.fail = true;
|
||||||
@@ -610,7 +399,7 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
tabu_list.insert((d1, d2));
|
tabu_list.insert((d1, d2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStrLoc) => {
|
(HeapCellValueTag::PStrLoc, l) => {
|
||||||
read_heap_cell!(d2,
|
read_heap_cell!(d2,
|
||||||
(HeapCellValueTag::PStrLoc |
|
(HeapCellValueTag::PStrLoc |
|
||||||
HeapCellValueTag::Lis |
|
HeapCellValueTag::Lis |
|
||||||
@@ -619,8 +408,7 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::CStr |
|
(HeapCellValueTag::AttrVar |
|
||||||
HeapCellValueTag::AttrVar |
|
|
||||||
HeapCellValueTag::Var |
|
HeapCellValueTag::Var |
|
||||||
HeapCellValueTag::StackVar) => {
|
HeapCellValueTag::StackVar) => {
|
||||||
}
|
}
|
||||||
@@ -630,52 +418,19 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::unify_partial_string(self, d1, d2);
|
Self::unify_partial_string(self, l, d2);
|
||||||
|
|
||||||
if !self.fail && !d2.is_constant() {
|
if !self.fail && !d2.is_constant() {
|
||||||
let d2 = self.store(d2);
|
let d2 = self.store(d2);
|
||||||
tabu_list.insert((d1, d2));
|
tabu_list.insert((d1, d2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::CStr) => {
|
(HeapCellValueTag::F64Offset, f1) => {
|
||||||
read_heap_cell!(d2,
|
|
||||||
(HeapCellValueTag::AttrVar, h) => {
|
|
||||||
Self::bind(self, Ref::attr_var(h), d1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Var, h) => {
|
|
||||||
Self::bind(self, Ref::heap_cell(h), d1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::StackVar, s) => {
|
|
||||||
Self::bind(self, Ref::stack_cell(s), d1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Str |
|
|
||||||
HeapCellValueTag::Lis |
|
|
||||||
HeapCellValueTag::PStrLoc) => {
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::CStr) => {
|
|
||||||
self.fail = d1 != d2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Self::unify_partial_string(self, d2, d1);
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::F64, f1) => {
|
|
||||||
Self::unify_f64(self, f1, d2);
|
Self::unify_f64(self, f1, d2);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Fixnum, n1) => {
|
(HeapCellValueTag::Fixnum, n1) => {
|
||||||
Self::unify_fixnum(self, n1, d2);
|
Self::unify_fixnum(self, n1, d2);
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Char, c1) => {
|
|
||||||
Self::unify_char(self, c1, d2);
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Cons, ptr_1) => {
|
(HeapCellValueTag::Cons, ptr_1) => {
|
||||||
Self::unify_constant(self, ptr_1, d2);
|
Self::unify_constant(self, ptr_1, d2);
|
||||||
}
|
}
|
||||||
@@ -707,12 +462,11 @@ fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellVa
|
|||||||
|
|
||||||
if !value.is_constant() {
|
if !value.is_constant() {
|
||||||
let machine_st: &mut MachineState = unifier.deref_mut();
|
let machine_st: &mut MachineState = unifier.deref_mut();
|
||||||
|
machine_st.heap[0] = value;
|
||||||
|
|
||||||
for cell in stackful_preorder_iter::<NonListElider>(
|
for cell in
|
||||||
&mut machine_st.heap,
|
stackful_preorder_iter::<NonListElider>(&mut machine_st.heap, &mut machine_st.stack, 0)
|
||||||
&mut machine_st.stack,
|
{
|
||||||
value,
|
|
||||||
) {
|
|
||||||
let cell = unmark_cell_bits!(cell);
|
let cell = unmark_cell_bits!(cell);
|
||||||
|
|
||||||
if let Some(inner_r) = cell.as_var() {
|
if let Some(inner_r) = cell.as_var() {
|
||||||
|
|||||||
318
src/macros.rs
318
src/macros.rs
@@ -1,15 +1,10 @@
|
|||||||
/* A simple macro to count the arguments in a variadic list
|
/* A simple macro to count the arguments in a variadic list
|
||||||
* of token trees.
|
* of token trees.
|
||||||
*/
|
*/
|
||||||
macro_rules! count_tt {
|
|
||||||
() => { 0 };
|
|
||||||
($odd:tt $($a:tt $b:tt)*) => { (count_tt!($($a)*) << 1) | 1 };
|
|
||||||
($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 };
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! char_as_cell {
|
macro_rules! char_as_cell {
|
||||||
($c: expr) => {
|
($c: expr) => {
|
||||||
HeapCellValue::build_with(HeapCellValueTag::Char, $c as u64)
|
HeapCellValue::from_bytes(AtomCell::new_char_inlined($c).into_bytes())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,12 +14,6 @@ macro_rules! fixnum_as_cell {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! cell_as_fixnum {
|
|
||||||
($cell:expr) => {
|
|
||||||
Fixnum::from_bytes($cell.into_bytes())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! integer_as_cell {
|
macro_rules! integer_as_cell {
|
||||||
($n: expr) => {{
|
($n: expr) => {{
|
||||||
match $n {
|
match $n {
|
||||||
@@ -45,31 +34,17 @@ macro_rules! empty_list_as_cell {
|
|||||||
|
|
||||||
macro_rules! atom_as_cell {
|
macro_rules! atom_as_cell {
|
||||||
($atom:expr) => {
|
($atom:expr) => {
|
||||||
HeapCellValue::from_bytes(
|
HeapCellValue::from_bytes(AtomCell::build_with($atom.index, 0).into_bytes())
|
||||||
AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::Atom).into_bytes(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
($atom:expr, $arity:expr) => {
|
($atom:expr, $arity:expr) => {
|
||||||
HeapCellValue::from_bytes(
|
HeapCellValue::from_bytes(AtomCell::build_with($atom.index, $arity as u8).into_bytes())
|
||||||
AtomCell::build_with($atom.flat_index(), $arity as u16, HeapCellValueTag::Atom)
|
|
||||||
.into_bytes(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! cell_as_string {
|
|
||||||
($cell:expr) => {
|
|
||||||
PartialString::from(cell_as_atom!($cell))
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! cell_as_atom {
|
macro_rules! cell_as_atom {
|
||||||
($cell:expr) => {{
|
($cell:expr) => {
|
||||||
let cell = AtomCell::from_bytes($cell.into_bytes());
|
AtomCell::from_bytes($cell.into_bytes()).get_name()
|
||||||
let name = (cell.get_index() as u64) << 3;
|
};
|
||||||
|
|
||||||
Atom::from(name)
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! cell_as_atom_cell {
|
macro_rules! cell_as_atom_cell {
|
||||||
@@ -78,10 +53,17 @@ macro_rules! cell_as_atom_cell {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! cell_as_f64_ptr {
|
macro_rules! cell_as_f64_offset {
|
||||||
($cell:expr) => {{
|
($cell:expr) => {{
|
||||||
let offset = $cell.get_value() as usize;
|
let offset = $cell.get_value() as usize;
|
||||||
F64Ptr::from_offset(F64Offset::new(offset))
|
F64Offset::from(offset)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! cell_as_code_index_offset {
|
||||||
|
($cell:expr) => {{
|
||||||
|
let offset = $cell.get_value() as usize;
|
||||||
|
CodeIndexOffset::from(offset)
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,26 +73,12 @@ macro_rules! cell_as_untyped_arena_ptr {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
macro_rules! pstr_loc_as_cell {
|
||||||
($h:expr) => {
|
($h:expr) => {
|
||||||
HeapCellValue::build_with(HeapCellValueTag::PStrLoc, $h as u64)
|
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 {
|
macro_rules! list_loc_as_cell {
|
||||||
($h:expr) => {
|
($h:expr) => {
|
||||||
HeapCellValue::build_with(HeapCellValueTag::Lis, $h as u64)
|
HeapCellValue::build_with(HeapCellValueTag::Lis, $h as u64)
|
||||||
@@ -172,11 +140,11 @@ macro_rules! typed_arena_ptr_as_cell {
|
|||||||
macro_rules! raw_ptr_as_cell {
|
macro_rules! raw_ptr_as_cell {
|
||||||
($ptr:expr) => {{
|
($ptr:expr) => {{
|
||||||
// Cell is 64-bit, but raw ptr is 32-bit in 32-bit systems
|
// Cell is 64-bit, but raw ptr is 32-bit in 32-bit systems
|
||||||
// TODO use <*{const,mut} _>::addr instead of as when the strict_provenance feature is stable rust-lang/rust#95228
|
let ptr: *const _ = $ptr;
|
||||||
// we might need <*{const,mut} _>::expose_provenance for strict provenance, dependening on how we recreate a pointer later
|
// This needs to expose provenance because it needs to be turned back into a pointer
|
||||||
let ptr : *const _ = $ptr;
|
// in contexts where there is no available provenance locally. For example, in
|
||||||
debug_assert!(!$ptr.is_null());
|
// `ConsPtr::as_ptr`.
|
||||||
HeapCellValue::from_ptr_addr(ptr as usize)
|
HeapCellValue::from_ptr_addr(ptr.expose_provenance())
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,36 +154,10 @@ macro_rules! untyped_arena_ptr_as_cell {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! atom_as_cstr_cell {
|
macro_rules! stream_as_cell {
|
||||||
($atom:expr) => {{
|
($ptr:expr) => {
|
||||||
let offset = $atom.flat_index();
|
raw_ptr_as_cell!($ptr.as_ptr())
|
||||||
|
};
|
||||||
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! cell_as_stream {
|
macro_rules! cell_as_stream {
|
||||||
@@ -276,9 +218,21 @@ macro_rules! match_untyped_arena_ptr_pat_body {
|
|||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
$code
|
$code
|
||||||
}};
|
}};
|
||||||
($ptr:ident, IndexPtr, $ip:ident, $code:expr) => {{
|
($ptr:ident, PipeReader, $listener:ident, $code:expr) => {{
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut $ip = unsafe { $ptr.as_typed_ptr::<IndexPtr>() };
|
let mut $listener = unsafe { $ptr.as_typed_ptr::<PipeReader>() };
|
||||||
|
#[allow(unused_braces)]
|
||||||
|
$code
|
||||||
|
}};
|
||||||
|
($ptr:ident, PipeWriter, $listener:ident, $code:expr) => {{
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut $listener = unsafe { $ptr.as_typed_ptr::<PipeWriter>() };
|
||||||
|
#[allow(unused_braces)]
|
||||||
|
$code
|
||||||
|
}};
|
||||||
|
($ptr:ident, ChildProcess, $listener:ident, $code:expr) => {{
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut $listener = unsafe { $ptr.as_typed_ptr::<std::process::Child>() };
|
||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
$code
|
$code
|
||||||
}};
|
}};
|
||||||
@@ -304,12 +258,8 @@ macro_rules! match_untyped_arena_ptr_pat {
|
|||||||
| ArenaHeaderTag::InputChannelStream
|
| ArenaHeaderTag::InputChannelStream
|
||||||
| ArenaHeaderTag::StandardOutputStream
|
| ArenaHeaderTag::StandardOutputStream
|
||||||
| ArenaHeaderTag::StandardErrorStream
|
| ArenaHeaderTag::StandardErrorStream
|
||||||
};
|
| ArenaHeaderTag::PipeReader
|
||||||
(IndexPtr) => {
|
| ArenaHeaderTag::PipeWriter
|
||||||
ArenaHeaderTag::IndexPtrUndefined
|
|
||||||
| ArenaHeaderTag::IndexPtrDynamicUndefined
|
|
||||||
| ArenaHeaderTag::IndexPtrDynamicIndex
|
|
||||||
| ArenaHeaderTag::IndexPtrIndex
|
|
||||||
};
|
};
|
||||||
($tag:ident) => {
|
($tag:ident) => {
|
||||||
ArenaHeaderTag::$tag
|
ArenaHeaderTag::$tag
|
||||||
@@ -336,8 +286,13 @@ macro_rules! read_heap_cell_pat_body {
|
|||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
$code
|
$code
|
||||||
}};
|
}};
|
||||||
($cell:ident, F64, $n:ident, $code:expr) => {{
|
($cell:ident, F64Offset, $n:ident, $code:expr) => {{
|
||||||
let $n = cell_as_f64_ptr!($cell);
|
let $n = cell_as_f64_offset!($cell);
|
||||||
|
#[allow(unused_braces)]
|
||||||
|
$code
|
||||||
|
}};
|
||||||
|
($cell:ident, CodeIndexOffset, $n:ident, $code:expr) => {{
|
||||||
|
let $n = cell_as_code_index_offset!($cell);
|
||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
$code
|
$code
|
||||||
}};
|
}};
|
||||||
@@ -346,26 +301,6 @@ macro_rules! read_heap_cell_pat_body {
|
|||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
$code
|
$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) => {{
|
($cell:ident, Fixnum, $value:ident, $code:expr) => {{
|
||||||
let $value = Fixnum::from_bytes($cell.into_bytes());
|
let $value = Fixnum::from_bytes($cell.into_bytes());
|
||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
@@ -386,11 +321,6 @@ macro_rules! read_heap_cell_pat_body {
|
|||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
$code
|
$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) => {{
|
($cell:ident, $($tags:tt)|+, $value:ident, $code:expr) => {{
|
||||||
let $value = $cell.get_value() as usize;
|
let $value = $cell.get_value() as usize;
|
||||||
#[allow(unused_braces)]
|
#[allow(unused_braces)]
|
||||||
@@ -432,119 +362,6 @@ macro_rules! read_heap_cell {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! functor {
|
|
||||||
($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
|
|
||||||
{
|
|
||||||
#[allow(unused_variables, unused_mut)]
|
|
||||||
let mut addendum = Heap::new();
|
|
||||||
let arity: usize = count_tt!($($dt) +);
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
let aux_lens: [usize; count_tt!($($aux) *)] = [$($aux.len()),*];
|
|
||||||
|
|
||||||
let mut result =
|
|
||||||
vec![ atom_as_cell!($name, arity as u16),
|
|
||||||
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
|
|
||||||
|
|
||||||
$(
|
|
||||||
result.extend($aux.iter());
|
|
||||||
)*
|
|
||||||
|
|
||||||
result.extend(addendum.into_iter());
|
|
||||||
result
|
|
||||||
}
|
|
||||||
});
|
|
||||||
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
|
|
||||||
{
|
|
||||||
let arity: usize = count_tt!($($dt) +);
|
|
||||||
|
|
||||||
#[allow(unused_variables, unused_mut)]
|
|
||||||
let mut addendum = Heap::new();
|
|
||||||
|
|
||||||
let mut result =
|
|
||||||
vec![ atom_as_cell!($name, arity as u16),
|
|
||||||
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
|
|
||||||
|
|
||||||
result.extend(addendum.into_iter());
|
|
||||||
result
|
|
||||||
}
|
|
||||||
});
|
|
||||||
($name:expr) => ({
|
|
||||||
vec![ atom_as_cell!($name) ]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! functor_term {
|
|
||||||
(str(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
|
||||||
str_loc_as_cell!($arity + 1)
|
|
||||||
});
|
|
||||||
(str($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
|
||||||
let len: usize = $aux_lens[0 .. $e].iter().sum();
|
|
||||||
str_loc_as_cell!($arity + 1 + len)
|
|
||||||
});
|
|
||||||
(str($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
|
||||||
str_loc_as_cell!($arity + $h + 1)
|
|
||||||
});
|
|
||||||
(str($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
|
||||||
let len: usize = $aux_lens[0 .. $e].iter().sum();
|
|
||||||
str_loc_as_cell!($arity + $h + 1 + len)
|
|
||||||
});
|
|
||||||
(literal($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
|
||||||
HeapCellValue::from($e)
|
|
||||||
);
|
|
||||||
(integer($e:expr, $arena:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
|
||||||
HeapCellValue::arena_from(Number::arena_from($e, $arena), $arena)
|
|
||||||
);
|
|
||||||
(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!(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.len() + $h;
|
|
||||||
|
|
||||||
$addendum.extend(stub.into_iter());
|
|
||||||
|
|
||||||
str_loc_as_cell!(h)
|
|
||||||
});
|
|
||||||
(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) => (
|
|
||||||
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.len() + $h;
|
|
||||||
|
|
||||||
let cell = string_as_pstr_cell!($e);
|
|
||||||
|
|
||||||
$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(atom!("true")), $arity, $aux_lens, $addendum)
|
|
||||||
} else {
|
|
||||||
functor_term!(atom(atom!("false")), $arity, $aux_lens, $addendum)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
(cell($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
|
||||||
$e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! compare_number_instr {
|
macro_rules! compare_number_instr {
|
||||||
($cmp: expr, $at_1: expr, $at_2: expr) => {{
|
($cmp: expr, $at_1: expr, $at_2: expr) => {{
|
||||||
$cmp.set_terms($at_1, $at_2);
|
$cmp.set_terms($at_1, $at_2);
|
||||||
@@ -629,3 +446,44 @@ macro_rules! compare_term_test {
|
|||||||
$machine_st.compare_term_test($var_comparison)
|
$machine_st.compare_term_test($var_comparison)
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! step_or_resource_error {
|
||||||
|
($machine_st:expr, $val:expr) => {{
|
||||||
|
match $val {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(err_loc) => {
|
||||||
|
$machine_st.throw_resource_error(err_loc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
($machine_st:expr, $val:expr, $fail:block) => {{
|
||||||
|
match $val {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(err_loc) => {
|
||||||
|
$machine_st.throw_resource_error(err_loc);
|
||||||
|
$fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! resource_error_call_result {
|
||||||
|
($machine_st:expr, $val:expr) => {
|
||||||
|
step_or_resource_error!($machine_st, $val, {
|
||||||
|
return Err(vec![]);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! heap_index {
|
||||||
|
($idx:expr) => {
|
||||||
|
($idx) * std::mem::size_of::<HeapCellValue>()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! cell_index {
|
||||||
|
($idx:expr) => {
|
||||||
|
(($idx) / std::mem::size_of::<HeapCellValue>())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
422
src/offset_table.rs
Normal file
422
src/offset_table.rs
Normal file
@@ -0,0 +1,422 @@
|
|||||||
|
use std::cell::UnsafeCell;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::{fmt, mem, ptr};
|
||||||
|
|
||||||
|
use arcu::atomic::Arcu;
|
||||||
|
use arcu::epoch_counters::GlobalEpochCounterPool;
|
||||||
|
use arcu::rcu_ref::RcuRef;
|
||||||
|
use arcu::Rcu;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
|
use crate::machine::machine_indices::IndexPtr;
|
||||||
|
use crate::raw_block::RawBlock;
|
||||||
|
use crate::raw_block::RawBlockTraits;
|
||||||
|
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
|
const F64_TABLE_INIT_SIZE: usize = 1 << 16;
|
||||||
|
const F64_TABLE_ALIGN: usize = 8;
|
||||||
|
|
||||||
|
const CODE_INDEX_TABLE_INIT_SIZE: usize = 1 << 16;
|
||||||
|
const CODE_INDEX_TABLE_ALIGN: usize = 8;
|
||||||
|
|
||||||
|
impl RawBlockTraits for OrderedFloat<f64> {
|
||||||
|
#[inline]
|
||||||
|
fn init_size() -> usize {
|
||||||
|
F64_TABLE_INIT_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn align() -> usize {
|
||||||
|
F64_TABLE_ALIGN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawBlockTraits for IndexPtr {
|
||||||
|
#[inline]
|
||||||
|
fn init_size() -> usize {
|
||||||
|
CODE_INDEX_TABLE_INIT_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn align() -> usize {
|
||||||
|
CODE_INDEX_TABLE_ALIGN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OffsetTableImpl<T: RawBlockTraits>(InnerOffsetTableImpl<T>);
|
||||||
|
|
||||||
|
impl<T: RawBlockTraits> From<Arc<ConcurrentOffsetTable<T>>> for OffsetTableImpl<T> {
|
||||||
|
#[inline]
|
||||||
|
fn from(value: Arc<ConcurrentOffsetTable<T>>) -> Self {
|
||||||
|
OffsetTableImpl(InnerOffsetTableImpl::Concurrent(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug + RawBlockTraits> OffsetTableImpl<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(InnerOffsetTableImpl::Serial(SerialOffsetTable::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "the returned concurrent table must be absorbed into the owned OffsetTable"]
|
||||||
|
pub fn single_to_concurrent(&mut self) -> Arc<ConcurrentOffsetTable<T>> {
|
||||||
|
match &mut self.0 {
|
||||||
|
InnerOffsetTableImpl::Serial(serial_tbl) => {
|
||||||
|
let empty_serial_tbl = SerialOffsetTable {
|
||||||
|
block: RawBlock::empty_block(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let serial_tbl = mem::replace(serial_tbl, empty_serial_tbl);
|
||||||
|
let num_tbl_entries = serial_tbl.block.size() / size_of::<T>();
|
||||||
|
let block = Arcu::new(serial_tbl.block, GlobalEpochCounterPool);
|
||||||
|
|
||||||
|
let offset_locks: Vec<RwLock<()>> =
|
||||||
|
(0..num_tbl_entries).map(|_| RwLock::new(())).collect();
|
||||||
|
|
||||||
|
let concurrent_tbl = Arc::new(ConcurrentOffsetTable {
|
||||||
|
block,
|
||||||
|
growth_lock: RwLock::new(()),
|
||||||
|
offset_locks: RwLock::new(offset_locks),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.0 = InnerOffsetTableImpl::Concurrent(concurrent_tbl.clone());
|
||||||
|
|
||||||
|
concurrent_tbl
|
||||||
|
}
|
||||||
|
InnerOffsetTableImpl::Concurrent(concurrent_tbl) => concurrent_tbl.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "the transition to a single-threaded offset table may fail if the concurrent table is held from multiple places"]
|
||||||
|
pub fn concurrent_to_single(&mut self) -> Result<(), ()> {
|
||||||
|
match &mut self.0 {
|
||||||
|
InnerOffsetTableImpl::Serial(_serial_tbl) => Ok(()),
|
||||||
|
InnerOffsetTableImpl::Concurrent(concurrent_tbl) => {
|
||||||
|
let table_arc = std::mem::replace(
|
||||||
|
concurrent_tbl,
|
||||||
|
Arc::new(ConcurrentOffsetTable {
|
||||||
|
block: Arcu::new(RawBlock::empty_block(), GlobalEpochCounterPool),
|
||||||
|
growth_lock: RwLock::new(()),
|
||||||
|
offset_locks: RwLock::new(vec![]),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
match Arc::try_unwrap(table_arc) {
|
||||||
|
Ok(table) => {
|
||||||
|
// this was the only instance of the concurrent table, as such
|
||||||
|
// at this point no build_with/with_entry{_mut} call can be in-progress/made
|
||||||
|
|
||||||
|
// this shouldn't be able to fail
|
||||||
|
let raw_block =
|
||||||
|
Arc::try_unwrap(table.block.replace(RawBlock::empty_block())).unwrap();
|
||||||
|
self.0 =
|
||||||
|
InnerOffsetTableImpl::Serial(SerialOffsetTable { block: raw_block });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(table_arc) => {
|
||||||
|
// restore the concurrent_tbl
|
||||||
|
*concurrent_tbl = table_arc;
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_entry(&self, offset: <Self as OffsetTable<T>>::Offset) -> T
|
||||||
|
where
|
||||||
|
Self: OffsetTable<T>,
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
|
self.with_entry(offset, |value| *value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug + RawBlockTraits> Default for OffsetTableImpl<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct SerialOffsetTable<T: RawBlockTraits> {
|
||||||
|
block: RawBlock<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ConcurrentOffsetTable<T: RawBlockTraits> {
|
||||||
|
block: Arcu<RawBlock<T>, GlobalEpochCounterPool>,
|
||||||
|
growth_lock: RwLock<()>,
|
||||||
|
offset_locks: RwLock<Vec<RwLock<()>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum InnerOffsetTableImpl<T: RawBlockTraits> {
|
||||||
|
Serial(SerialOffsetTable<T>),
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Concurrent(Arc<ConcurrentOffsetTable<T>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RawBlockTraits> InnerOffsetTableImpl<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn build_with(&mut self, value: T) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::Concurrent(concurrent_tbl) => concurrent_tbl.build_with(value),
|
||||||
|
Self::Serial(serial_tbl) => unsafe { serial_tbl.build_with(value) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn with_entry<R, F: FnOnce(&T) -> R>(&self, offset: usize, f: F) -> R {
|
||||||
|
match self {
|
||||||
|
Self::Concurrent(concurrent_tbl) => concurrent_tbl.with_entry(offset, f),
|
||||||
|
Self::Serial(serial_tbl) => f(unsafe { serial_tbl.lookup(offset) }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn with_entry_mut<R, F: FnOnce(&mut T) -> R>(&mut self, offset: usize, f: F) -> R {
|
||||||
|
match self {
|
||||||
|
Self::Concurrent(concurrent_tbl) => concurrent_tbl.with_entry_mut(offset, f),
|
||||||
|
Self::Serial(serial_tbl) => f(unsafe { serial_tbl.lookup_mut(offset) }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait OffsetTable<T: RawBlockTraits> {
|
||||||
|
type Offset: Copy + Into<usize>;
|
||||||
|
|
||||||
|
fn build_with(&mut self, value: T) -> Self::Offset;
|
||||||
|
|
||||||
|
fn with_entry<R, F: FnOnce(&T) -> R>(&self, offset: Self::Offset, f: F) -> R;
|
||||||
|
fn with_entry_mut<R, F: FnOnce(&mut T) -> R>(&mut self, offset: Self::Offset, f: F) -> R;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OffsetTable<OrderedFloat<f64>> for OffsetTableImpl<OrderedFloat<f64>> {
|
||||||
|
type Offset = F64Offset;
|
||||||
|
|
||||||
|
fn build_with(&mut self, value: OrderedFloat<f64>) -> F64Offset {
|
||||||
|
F64Offset(self.0.build_with(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_entry<R, F: FnOnce(&OrderedFloat<f64>) -> R>(&self, offset: F64Offset, f: F) -> R {
|
||||||
|
self.0.with_entry(offset.into(), f)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_entry_mut<R, F: FnOnce(&mut OrderedFloat<f64>) -> R>(
|
||||||
|
&mut self,
|
||||||
|
offset: F64Offset,
|
||||||
|
f: F,
|
||||||
|
) -> R {
|
||||||
|
self.0.with_entry_mut(offset.into(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OffsetTable<IndexPtr> for OffsetTableImpl<IndexPtr> {
|
||||||
|
type Offset = CodeIndexOffset;
|
||||||
|
|
||||||
|
fn build_with(&mut self, value: IndexPtr) -> CodeIndexOffset {
|
||||||
|
CodeIndexOffset(self.0.build_with(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_entry<R, F: FnOnce(&IndexPtr) -> R>(&self, offset: CodeIndexOffset, f: F) -> R {
|
||||||
|
self.0.with_entry(offset.into(), f)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_entry_mut<R, F: FnOnce(&mut IndexPtr) -> R>(
|
||||||
|
&mut self,
|
||||||
|
offset: CodeIndexOffset,
|
||||||
|
f: F,
|
||||||
|
) -> R {
|
||||||
|
self.0.with_entry_mut(offset.into(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RawBlockTraits> SerialOffsetTable<T> {
|
||||||
|
#[inline]
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
block: RawBlock::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn build_with(&mut self, value: T) -> usize {
|
||||||
|
let mut ptr;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
ptr = self.block.alloc(size_of::<T>());
|
||||||
|
|
||||||
|
if ptr.is_null() {
|
||||||
|
let new_block = self.block.grow_new().unwrap();
|
||||||
|
self.block = new_block;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr::write(ptr as *mut T, value);
|
||||||
|
ptr.addr() - self.block.base.addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn lookup(&self, offset: usize) -> &T {
|
||||||
|
&*self.block.base.add(offset).cast::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn lookup_mut(&mut self, offset: usize) -> &mut T {
|
||||||
|
&mut *self.block.base.add(offset).cast::<T>().cast_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RawBlockTraits> ConcurrentOffsetTable<T> {
|
||||||
|
#[allow(clippy::missing_safety_doc)]
|
||||||
|
fn build_with(&self, value: T) -> usize {
|
||||||
|
let growth_lock = self.growth_lock.write();
|
||||||
|
|
||||||
|
// we don't have an index table for lookups as AtomTable does so
|
||||||
|
// just get the epoch after we take the upgrade lock
|
||||||
|
let mut block_epoch = self.block.read();
|
||||||
|
let mut ptr;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
ptr = unsafe { block_epoch.alloc(mem::size_of::<T>()) };
|
||||||
|
|
||||||
|
if ptr.is_null() {
|
||||||
|
let new_block = unsafe { block_epoch.grow_new().unwrap() };
|
||||||
|
self.block.replace(new_block);
|
||||||
|
block_epoch = self.block.read();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_tbl_sz = block_epoch.size() / size_of::<T>();
|
||||||
|
let mut offset_locks = self.offset_locks.write();
|
||||||
|
|
||||||
|
offset_locks.resize_with(new_tbl_sz, || RwLock::new(()));
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ptr::write(ptr as *mut T, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = ptr.addr() - block_epoch.base.addr();
|
||||||
|
|
||||||
|
// AtomTable would have to update the index table at this point
|
||||||
|
// explicit drop to ensure we don't accidentally drop it early
|
||||||
|
drop(offset_locks);
|
||||||
|
drop(growth_lock);
|
||||||
|
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_entry<R, F: FnOnce(&T) -> R>(&self, offset: usize, f: F) -> R {
|
||||||
|
let outer_offset_lock = self.offset_locks.read();
|
||||||
|
let inner_offset_lock = outer_offset_lock[offset / size_of::<T>()].read();
|
||||||
|
|
||||||
|
let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe {
|
||||||
|
raw_block.base.add(offset).cast::<T>().as_ref()
|
||||||
|
})
|
||||||
|
.expect("offset valid");
|
||||||
|
|
||||||
|
let result = f(&*rcu_ref);
|
||||||
|
|
||||||
|
drop(inner_offset_lock);
|
||||||
|
drop(outer_offset_lock);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_entry_mut<R, F: FnOnce(&mut T) -> R>(&self, offset: usize, f: F) -> R {
|
||||||
|
let growth_lock = self.growth_lock.read();
|
||||||
|
let outer_offset_lock = self.offset_locks.read();
|
||||||
|
let inner_offset_lock = outer_offset_lock[offset / size_of::<T>()].write();
|
||||||
|
|
||||||
|
let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe {
|
||||||
|
raw_block
|
||||||
|
.base
|
||||||
|
.add(offset)
|
||||||
|
.cast_mut()
|
||||||
|
.cast::<UnsafeCell<T>>()
|
||||||
|
.as_ref()
|
||||||
|
})
|
||||||
|
.expect("offset valid");
|
||||||
|
|
||||||
|
let result = f(unsafe { &mut *rcu_ref.get().as_mut().unwrap() });
|
||||||
|
|
||||||
|
drop(inner_offset_lock);
|
||||||
|
drop(outer_offset_lock);
|
||||||
|
drop(growth_lock);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type F64Table = OffsetTableImpl<OrderedFloat<f64>>;
|
||||||
|
pub type CodeIndexTable = OffsetTableImpl<IndexPtr>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct F64Offset(usize);
|
||||||
|
|
||||||
|
impl From<usize> for F64Offset {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(offset: usize) -> Self {
|
||||||
|
Self(offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<F64Offset> for usize {
|
||||||
|
fn from(val: F64Offset) -> Self {
|
||||||
|
val.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct CodeIndexOffset(usize);
|
||||||
|
|
||||||
|
impl From<usize> for CodeIndexOffset {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(offset: usize) -> Self {
|
||||||
|
Self(offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodeIndexOffset> for usize {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(val: CodeIndexOffset) -> Self {
|
||||||
|
val.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CodeIndexOffset {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn to_u64(self) -> u64 {
|
||||||
|
self.0 as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CodeIndexOffset {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "CodeIndexOffset({})", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl F64Offset {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn to_u64(self) -> u64 {
|
||||||
|
self.0 as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for F64Offset {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "F64Offset({})", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,21 +2,24 @@
|
|||||||
|
|
||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::machine::machine_indices::*;
|
use crate::offset_table::*;
|
||||||
use crate::parser::char_reader::*;
|
use crate::parser::char_reader::*;
|
||||||
use crate::types::HeapCellValueTag;
|
use crate::types::HeapCellValueTag;
|
||||||
|
|
||||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::Hash;
|
||||||
|
use std::hash::Hasher;
|
||||||
use std::io::{Error as IOError, ErrorKind};
|
use std::io::{Error as IOError, ErrorKind};
|
||||||
|
use std::ops::Not;
|
||||||
|
use std::ops::RangeInclusive;
|
||||||
use std::ops::{Deref, Neg};
|
use std::ops::{Deref, Neg};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
use crate::parser::dashu::{Integer, Rational};
|
use dashu::Integer;
|
||||||
|
use dashu::Rational;
|
||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use scryer_modular_bitfield::error::OutOfBounds;
|
use scryer_modular_bitfield::error::OutOfBounds;
|
||||||
@@ -24,7 +27,7 @@ use scryer_modular_bitfield::prelude::*;
|
|||||||
|
|
||||||
pub type Specifier = u32;
|
pub type Specifier = u32;
|
||||||
|
|
||||||
pub const MAX_ARITY: usize = 1023;
|
pub const MAX_ARITY: usize = 255;
|
||||||
|
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
@@ -264,8 +267,8 @@ impl RegType {
|
|||||||
impl fmt::Display for RegType {
|
impl fmt::Display for RegType {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
RegType::Perm(val) => write!(f, "Y{}", val),
|
RegType::Perm(val) => write!(f, "Y{val}"),
|
||||||
RegType::Temp(val) => write!(f, "X{}", val),
|
RegType::Temp(val) => write!(f, "X{val}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,10 +290,10 @@ impl VarReg {
|
|||||||
impl fmt::Display for VarReg {
|
impl fmt::Display for VarReg {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
|
VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{reg}"),
|
||||||
VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
|
VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{reg}"),
|
||||||
VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg),
|
VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{reg} A{arg}"),
|
||||||
VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg),
|
VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{reg} A{arg}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,28 +310,6 @@ macro_rules! temp_v {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
pub enum GenContext {
|
|
||||||
Head,
|
|
||||||
Mid(usize),
|
|
||||||
Last(usize), // Mid & Last: chunk_num
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GenContext {
|
|
||||||
#[inline]
|
|
||||||
pub fn chunk_num(self) -> usize {
|
|
||||||
match self {
|
|
||||||
GenContext::Head => 0,
|
|
||||||
GenContext::Mid(cn) | GenContext::Last(cn) => cn,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn is_last(self) -> bool {
|
|
||||||
matches!(self, GenContext::Last(_))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
||||||
pub struct OpDesc {
|
pub struct OpDesc {
|
||||||
@@ -420,7 +401,7 @@ pub fn default_op_dir() -> OpDir {
|
|||||||
op_dir
|
op_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum ArithmeticError {
|
pub enum ArithmeticError {
|
||||||
NonEvaluableFunctor(Literal, usize),
|
NonEvaluableFunctor(Literal, usize),
|
||||||
UninstantiatedVar,
|
UninstantiatedVar,
|
||||||
@@ -465,9 +446,9 @@ impl ParserError {
|
|||||||
ParserError::InvalidSingleQuotedCharacter(..) => {
|
ParserError::InvalidSingleQuotedCharacter(..) => {
|
||||||
atom!("invalid_single_quoted_character")
|
atom!("invalid_single_quoted_character")
|
||||||
}
|
}
|
||||||
ParserError::InfiniteFloat(..) => {
|
ParserError::InfiniteFloat(..) => {
|
||||||
atom!("infinite_float")
|
atom!("infinite_float")
|
||||||
}
|
}
|
||||||
ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
|
ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
|
||||||
atom!("unexpected_end_of_file")
|
atom!("unexpected_end_of_file")
|
||||||
}
|
}
|
||||||
@@ -570,9 +551,90 @@ pub struct Fixnum {
|
|||||||
tag: B6,
|
tag: B6,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod private {
|
||||||
|
use dashu::Integer;
|
||||||
|
|
||||||
|
pub(crate) trait FitsInFixnumSeal {}
|
||||||
|
pub(crate) trait MightNotFitInFixnumSeal {}
|
||||||
|
|
||||||
|
macro_rules! impl_fits_in_fixnum {
|
||||||
|
($t:ty) => {
|
||||||
|
impl $crate::parser::ast::private::FitsInFixnumSeal for $t {}
|
||||||
|
|
||||||
|
impl $crate::parser::ast::FitsInFixnum for $t {
|
||||||
|
fn into_i56(self) -> i64 {
|
||||||
|
self.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_fits_in_fixnum!(u8);
|
||||||
|
impl_fits_in_fixnum!(i8);
|
||||||
|
impl_fits_in_fixnum!(u16);
|
||||||
|
impl_fits_in_fixnum!(i16);
|
||||||
|
impl_fits_in_fixnum!(u32);
|
||||||
|
impl_fits_in_fixnum!(i32);
|
||||||
|
|
||||||
|
impl FitsInFixnumSeal for char {}
|
||||||
|
impl super::FitsInFixnum for char {
|
||||||
|
fn into_i56(self) -> i64 {
|
||||||
|
u32::from(self) as i64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MightNotFitInFixnumSeal for i64 {}
|
||||||
|
impl MightNotFitInFixnumSeal for &Integer {}
|
||||||
|
impl MightNotFitInFixnumSeal for Integer {}
|
||||||
|
impl MightNotFitInFixnumSeal for usize {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(private_bounds)]
|
||||||
|
pub trait FitsInFixnum: private::FitsInFixnumSeal {
|
||||||
|
fn into_i56(self) -> i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(private_bounds)]
|
||||||
|
pub trait MightNotFitInFixnum: private::MightNotFitInFixnumSeal {
|
||||||
|
fn try_into_i56(self) -> Option<i64>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MightNotFitInFixnum for T
|
||||||
|
where
|
||||||
|
T: private::MightNotFitInFixnumSeal + TryInto<i64>,
|
||||||
|
{
|
||||||
|
fn try_into_i56(self) -> Option<i64> {
|
||||||
|
let val = self.try_into().ok()?;
|
||||||
|
if Fixnum::RANGE.contains(&val) {
|
||||||
|
Some(val)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Fixnum {
|
impl Fixnum {
|
||||||
|
pub(crate) const MIN: i64 = -(1 << 55);
|
||||||
|
pub(crate) const MAX: i64 = (1 << 55) - 1;
|
||||||
|
const RANGE: RangeInclusive<i64> = Self::MIN..=Self::MAX;
|
||||||
|
|
||||||
|
// if you have a type that is not guaranteed to fit use `Fixnum::build_with_checked` or `Fixnum::build_with_unchecked` instead
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build_with(num: i64) -> Self {
|
pub fn build_with(num: impl FitsInFixnum) -> Self {
|
||||||
|
// Safety: FitsInFixnum is only implemented by types that only have valid values
|
||||||
|
// and FitsInFixnumSeal ensures no one outside this crate can violate that
|
||||||
|
unsafe { Self::build_with_unchecked(num.into_i56()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn build_with_unchecked(num: i64) -> Self {
|
||||||
|
debug_assert!(
|
||||||
|
Self::RANGE.contains(&num),
|
||||||
|
"{num} should be in the range {}..={}",
|
||||||
|
Self::MIN,
|
||||||
|
Self::MAX
|
||||||
|
);
|
||||||
|
|
||||||
Fixnum::new()
|
Fixnum::new()
|
||||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
|
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
|
||||||
.with_tag(HeapCellValueTag::Fixnum as u8)
|
.with_tag(HeapCellValueTag::Fixnum as u8)
|
||||||
@@ -581,12 +643,8 @@ impl Fixnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_cutpoint(num: i64) -> Self {
|
pub fn as_cutpoint(self) -> Self {
|
||||||
Fixnum::new()
|
self.with_tag(HeapCellValueTag::CutPoint as u8)
|
||||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
|
|
||||||
.with_tag(HeapCellValueTag::CutPoint as u8)
|
|
||||||
.with_m(false)
|
|
||||||
.with_f(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -595,20 +653,14 @@ impl Fixnum {
|
|||||||
HeapCellValueTag::from_bytes(self.tag()).unwrap()
|
HeapCellValueTag::from_bytes(self.tag()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if you have a type that is guaranteed to fit use `Fixnum::build_with` instead
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
|
pub fn build_with_checked(num: impl MightNotFitInFixnum) -> Result<Self, OutOfBounds> {
|
||||||
const UPPER_BOUND: i64 = (1 << 55) - 1;
|
Ok(unsafe {
|
||||||
const LOWER_BOUND: i64 = -(1 << 55);
|
// Safety: all MightNotFitInFixnum impls return None when the value is out-of-bounds
|
||||||
|
// and MightNotFitInFixnumSeal ensures no one outside this crate can violate that
|
||||||
if (LOWER_BOUND..=UPPER_BOUND).contains(&num) {
|
Self::build_with_unchecked(num.try_into_i56().ok_or(OutOfBounds {})?)
|
||||||
Ok(Fixnum::new()
|
})
|
||||||
.with_m(false)
|
|
||||||
.with_f(false)
|
|
||||||
.with_tag(HeapCellValueTag::Fixnum as u8)
|
|
||||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)))
|
|
||||||
} else {
|
|
||||||
Err(OutOfBounds {})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -618,6 +670,10 @@ impl Fixnum {
|
|||||||
debug_assert!(!overflowed);
|
debug_assert!(!overflowed);
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn checked_abs(self) -> Option<Self> {
|
||||||
|
Self::build_with_checked(self.get_num().abs()).ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Neg for Fixnum {
|
impl Neg for Fixnum {
|
||||||
@@ -625,23 +681,33 @@ impl Neg for Fixnum {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn neg(self) -> Self::Output {
|
fn neg(self) -> Self::Output {
|
||||||
Fixnum::build_with(-self.get_num())
|
// Safety: the truncating behaviour is correct
|
||||||
|
unsafe { Self::build_with_unchecked(-self.get_num()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
impl Not for Fixnum {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn not(self) -> Self::Output {
|
||||||
|
// Safety: the truncating behaviour is correct
|
||||||
|
unsafe { Self::build_with_unchecked(!self.get_num()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
Atom(Atom),
|
Atom(Atom),
|
||||||
Char(char),
|
CodeIndexOffset(CodeIndexOffset),
|
||||||
CodeIndex(CodeIndex),
|
|
||||||
Fixnum(Fixnum),
|
Fixnum(Fixnum),
|
||||||
Integer(TypedArenaPtr<Integer>),
|
Integer(TypedArenaPtr<Integer>),
|
||||||
Rational(TypedArenaPtr<Rational>),
|
Rational(TypedArenaPtr<Rational>),
|
||||||
Float(F64Offset),
|
F64Offset(F64Offset),
|
||||||
String(Atom),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<F64Ptr> for Literal {
|
/*
|
||||||
|
impl From<F64Ptr<'_>> for Literal {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(ptr: F64Ptr) -> Literal {
|
fn from(ptr: F64Ptr) -> Literal {
|
||||||
Literal::Float(ptr.as_offset())
|
Literal::Float(ptr.as_offset())
|
||||||
@@ -654,16 +720,15 @@ impl fmt::Display for Literal {
|
|||||||
Literal::Atom(ref atom) => {
|
Literal::Atom(ref atom) => {
|
||||||
write!(f, "{}", atom.flat_index())
|
write!(f, "{}", atom.flat_index())
|
||||||
}
|
}
|
||||||
Literal::Char(c) => write!(f, "'{}'", *c as u32),
|
Literal::CodeIndexOffset(i) => write!(f, "{}", *i),
|
||||||
Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64),
|
|
||||||
Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
|
Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
|
||||||
Literal::Integer(ref n) => write!(f, "{}", n),
|
Literal::Integer(ref n) => write!(f, "{}", n),
|
||||||
Literal::Rational(ref n) => write!(f, "{}", n),
|
Literal::Rational(ref n) => write!(f, "{}", n),
|
||||||
Literal::Float(ref n) => write!(f, "{}", *n),
|
Literal::FloatOffset(ref n) => write!(f, "{}", *n),
|
||||||
Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
impl Literal {
|
impl Literal {
|
||||||
pub fn as_atom(&self, atom_tbl: &Arc<AtomTable>) -> Option<Atom> {
|
pub fn as_atom(&self, atom_tbl: &Arc<AtomTable>) -> Option<Atom> {
|
||||||
@@ -742,20 +807,20 @@ impl From<&str> for VarPtr {
|
|||||||
pub enum Var {
|
pub enum Var {
|
||||||
Generated(usize),
|
Generated(usize),
|
||||||
InSitu(usize),
|
InSitu(usize),
|
||||||
Named(String),
|
Named(Rc<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Var {
|
impl From<String> for Var {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: String) -> Var {
|
fn from(value: String) -> Var {
|
||||||
Var::Named(value)
|
Var::Named(Rc::new(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for Var {
|
impl From<&str> for Var {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: &str) -> Var {
|
fn from(value: &str) -> Var {
|
||||||
Var::Named(value.to_owned())
|
Var::Named(Rc::new(value.to_owned()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,8 +829,8 @@ impl Var {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Var::InSitu(n) | Var::Generated(n) => format!("_{}", n),
|
Var::InSitu(n) | Var::Generated(n) => format!("_{n}"),
|
||||||
Var::Named(value) => value.to_owned(),
|
Var::Named(value) => value.as_ref().clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -778,8 +843,8 @@ pub enum Term {
|
|||||||
Literal(Cell<RegType>, Literal),
|
Literal(Cell<RegType>, Literal),
|
||||||
// PartialString wraps a String in anticipation of it absorbing
|
// PartialString wraps a String in anticipation of it absorbing
|
||||||
// other PartialString variants in as_partial_string.
|
// other PartialString variants in as_partial_string.
|
||||||
PartialString(Cell<RegType>, String, Box<Term>),
|
PartialString(Cell<RegType>, Rc<String>, Box<Term>),
|
||||||
CompleteString(Cell<RegType>, Atom),
|
CompleteString(Cell<RegType>, Rc<String>),
|
||||||
Var(Cell<VarReg>, VarPtr),
|
Var(Cell<VarReg>, VarPtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,10 +857,9 @@ impl Term {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> Option<Atom> {
|
pub fn name(&self) -> Option<Atom> {
|
||||||
match self {
|
match *self {
|
||||||
&Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => {
|
Term::Literal(_, Literal::Atom(atom)) => Some(atom),
|
||||||
Some(*atom)
|
Term::Clause(_, atom, ..) => Some(atom),
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -810,7 +874,7 @@ impl Term {
|
|||||||
|
|
||||||
pub(crate) fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> {
|
pub(crate) fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> {
|
||||||
if let Term::Clause(_, ref name, ref mut subterms) = term {
|
if let Term::Clause(_, ref name, ref mut subterms) = term {
|
||||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = subterms.last() {
|
if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = subterms.last() {
|
||||||
subterms.pop();
|
subterms.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
use crate::arena::F64Ptr;
|
use crate::arena::*;
|
||||||
use crate::arena::TypedArenaPtr;
|
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
pub use crate::machine::machine_state::*;
|
pub use crate::machine::machine_state::*;
|
||||||
|
use crate::offset_table::*;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::char_reader::*;
|
use crate::parser::char_reader::*;
|
||||||
use crate::parser::dashu::Integer;
|
use crate::parser::dashu::Integer;
|
||||||
|
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
@@ -28,10 +30,11 @@ struct LayoutInfo {
|
|||||||
more: bool,
|
more: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Var(String),
|
Var(String),
|
||||||
|
String(String),
|
||||||
Open, // '('
|
Open, // '('
|
||||||
OpenCT, // '('
|
OpenCT, // '('
|
||||||
Close, // ')'
|
Close, // ')'
|
||||||
@@ -55,16 +58,17 @@ impl Token {
|
|||||||
enum Number {
|
enum Number {
|
||||||
BigInt(TypedArenaPtr<Integer>),
|
BigInt(TypedArenaPtr<Integer>),
|
||||||
Fixnum(Fixnum),
|
Fixnum(Fixnum),
|
||||||
Float(F64Ptr),
|
Float(F64Offset),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Number {
|
impl Number {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::wrong_self_convention)]
|
||||||
fn to_literal(self) -> Literal {
|
fn to_literal(self) -> Literal {
|
||||||
match self {
|
match self {
|
||||||
Number::BigInt(ibig) => Literal::Integer(ibig),
|
Number::BigInt(ibig) => Literal::Integer(ibig),
|
||||||
Number::Fixnum(fixnum) => Literal::Fixnum(fixnum),
|
Number::Fixnum(fixnum) => Literal::Fixnum(fixnum),
|
||||||
Number::Float(f) => Literal::Float(f.as_offset()),
|
Number::Float(f) => Literal::F64Offset(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,6 +81,7 @@ enum NumberToken {
|
|||||||
|
|
||||||
impl NumberToken {
|
impl NumberToken {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::wrong_self_convention)]
|
||||||
fn to_token(self) -> Option<Token> {
|
fn to_token(self) -> Option<Token> {
|
||||||
match self {
|
match self {
|
||||||
NumberToken::Number(number) => Some(Token::Literal(number.to_literal())),
|
NumberToken::Number(number) => Some(Token::Literal(number.to_literal())),
|
||||||
@@ -100,7 +105,7 @@ macro_rules! try_nt {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Lexer<'a, R> {
|
pub(crate) struct Lexer<'a, R> {
|
||||||
pub(crate) reader: R,
|
pub(crate) reader: R,
|
||||||
pub(crate) machine_st: &'a mut MachineState,
|
pub(crate) machine_st: &'a mut MachineState,
|
||||||
pub(crate) line_num: usize,
|
pub(crate) line_num: usize,
|
||||||
@@ -109,7 +114,7 @@ pub struct Lexer<'a, R> {
|
|||||||
|
|
||||||
impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
|
impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("Lexer")
|
f.debug_struct("LexerParser")
|
||||||
.field("reader", &"&'a mut R") // Hacky solution.
|
.field("reader", &"&'a mut R") // Hacky solution.
|
||||||
.field("line_num", &self.line_num)
|
.field("line_num", &self.line_num)
|
||||||
.field("col_num", &self.col_num)
|
.field("col_num", &self.col_num)
|
||||||
@@ -119,7 +124,7 @@ impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
|
|||||||
|
|
||||||
impl<'a, R: CharRead> Lexer<'a, R> {
|
impl<'a, R: CharRead> Lexer<'a, R> {
|
||||||
pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
|
pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
|
||||||
Lexer {
|
Self {
|
||||||
reader: src,
|
reader: src,
|
||||||
machine_st,
|
machine_st,
|
||||||
line_num: 0,
|
line_num: 0,
|
||||||
@@ -505,7 +510,13 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
if hexadecimal_digit_char!(c) {
|
if hexadecimal_digit_char!(c) {
|
||||||
self.skip_char(c);
|
self.skip_char(c);
|
||||||
token.push(c);
|
token.push(c);
|
||||||
c = try_nt!(token, self.lookahead_char());
|
c = match self.lookahead_char() {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) if e.is_unexpected_eof() => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -530,7 +541,13 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
if octal_digit_char!(c) {
|
if octal_digit_char!(c) {
|
||||||
self.skip_char(c);
|
self.skip_char(c);
|
||||||
token.push(c);
|
token.push(c);
|
||||||
c = try_nt!(token, self.lookahead_char());
|
c = match self.lookahead_char() {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) if e.is_unexpected_eof() => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -555,7 +572,13 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
if binary_digit_char!(c) {
|
if binary_digit_char!(c) {
|
||||||
self.skip_char(c);
|
self.skip_char(c);
|
||||||
token.push(c);
|
token.push(c);
|
||||||
c = try_nt!(token, self.lookahead_char());
|
c = match self.lookahead_char() {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) if e.is_unexpected_eof() => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -632,7 +655,9 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
|
|
||||||
if !token.is_empty() && token.chars().nth(1).is_none() {
|
if !token.is_empty() && token.chars().nth(1).is_none() {
|
||||||
if let Some(c) = token.chars().next() {
|
if let Some(c) = token.chars().next() {
|
||||||
return Ok(Token::Literal(Literal::Char(c)));
|
return Ok(Token::Literal(Literal::Atom(
|
||||||
|
AtomCell::new_char_inlined(c).get_name(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -679,12 +704,8 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_integer_by_radix(
|
fn parse_integer_by_radix(&mut self, token: &str, radix: u32) -> Result<Number, ParserError> {
|
||||||
&mut self,
|
i64::from_str_radix(token, radix)
|
||||||
token: &String,
|
|
||||||
radix: u32,
|
|
||||||
) -> Result<Number, ParserError> {
|
|
||||||
i64::from_str_radix(&token, radix)
|
|
||||||
.map(|n| {
|
.map(|n| {
|
||||||
Fixnum::build_with_checked(n)
|
Fixnum::build_with_checked(n)
|
||||||
.map(Number::Fixnum)
|
.map(Number::Fixnum)
|
||||||
@@ -701,7 +722,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn parse_integer(&mut self, token: &String) -> Result<Number, ParserError> {
|
fn parse_integer(&mut self, token: &str) -> Result<Number, ParserError> {
|
||||||
self.parse_integer_by_radix(token, 10)
|
self.parse_integer_by_radix(token, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -785,6 +806,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let n = parse_float_lossy(&token)?;
|
let n = parse_float_lossy(&token)?;
|
||||||
|
|
||||||
Ok(NumberToken::Number(Number::Float(float_alloc!(
|
Ok(NumberToken::Number(Number::Float(float_alloc!(
|
||||||
n,
|
n,
|
||||||
self.machine_st.arena
|
self.machine_st.arena
|
||||||
@@ -847,7 +869,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.get_single_quoted_char()
|
self.get_single_quoted_char()
|
||||||
.map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c as i64))))
|
.map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c))))
|
||||||
.or_else(|err| {
|
.or_else(|err| {
|
||||||
match err {
|
match err {
|
||||||
ParserError::UnexpectedChar('\'', ..) => {}
|
ParserError::UnexpectedChar('\'', ..) => {}
|
||||||
@@ -933,13 +955,14 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
Ok(n) => Ok(Token::Literal(n.to_literal())),
|
Ok(n) => Ok(Token::Literal(n.to_literal())),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let n = parse_float_lossy(&token_string)?;
|
let n = parse_float_lossy(&token_string)?;
|
||||||
Ok(Token::Literal(Literal::Float(
|
Ok(Token::Literal(Literal::F64Offset(float_alloc!(
|
||||||
float_alloc!(n, self.machine_st.arena).as_offset(),
|
n,
|
||||||
)))
|
self.machine_st.arena
|
||||||
|
))))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Ok(NumberToken::Number(n)) => return Ok(Token::Literal(n.to_literal())),
|
Ok(NumberToken::Number(n)) => Ok(Token::Literal(n.to_literal())),
|
||||||
Err(e) => return Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1028,12 +1051,12 @@ impl<'a, R: CharRead> Lexer<'a, R> {
|
|||||||
|
|
||||||
if c == '"' {
|
if c == '"' {
|
||||||
let s = self.char_code_list_token(c)?;
|
let s = self.char_code_list_token(c)?;
|
||||||
let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s);
|
|
||||||
|
|
||||||
return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes {
|
return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes {
|
||||||
|
let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s);
|
||||||
Ok(Token::Literal(Literal::Atom(atom)))
|
Ok(Token::Literal(Literal::Atom(atom)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Token::Literal(Literal::String(atom)))
|
Ok(Token::String(s))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use dashu::Rational;
|
|||||||
|
|
||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
|
use crate::offset_table::OffsetTable;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
use crate::parser::char_reader::*;
|
use crate::parser::char_reader::*;
|
||||||
use crate::parser::lexer::*;
|
use crate::parser::lexer::*;
|
||||||
@@ -10,6 +11,7 @@ use crate::parser::lexer::*;
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
@@ -73,7 +75,6 @@ pub(crate) fn as_partial_string(
|
|||||||
return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
|
return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Term::Literal(_, Literal::Char(c)) => c.to_string(),
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
|
return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
|
||||||
}
|
}
|
||||||
@@ -93,9 +94,6 @@ pub(crate) fn as_partial_string(
|
|||||||
return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
|
return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Term::Literal(_, Literal::Char(c)) => {
|
|
||||||
string.push(*c);
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
tail = Term::Cons(
|
tail = Term::Cons(
|
||||||
Cell::default(),
|
Cell::default(),
|
||||||
@@ -113,7 +111,7 @@ pub(crate) fn as_partial_string(
|
|||||||
tail_ref = tail;
|
tail_ref = tail;
|
||||||
}
|
}
|
||||||
Term::CompleteString(_, cstr) => {
|
Term::CompleteString(_, cstr) => {
|
||||||
string += &*cstr.as_str();
|
string += cstr.as_str();
|
||||||
tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
|
tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -124,13 +122,17 @@ pub(crate) fn as_partial_string(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match &tail {
|
match tail {
|
||||||
Term::AnonVar | Term::Var(..) => Ok((string, Some(Box::new(tail)))),
|
Term::AnonVar | Term::Var(..) => Ok((string, Some(Box::new(tail)))),
|
||||||
Term::Literal(_, Literal::Atom(atom!("[]"))) => Ok((string, None)),
|
Term::Literal(_, Literal::Atom(atom!("[]"))) => Ok((string, None)),
|
||||||
Term::Literal(_, Literal::String(tail)) => {
|
Term::CompleteString(_, tail) => {
|
||||||
string += &*tail.as_str();
|
string += &tail;
|
||||||
Ok((string, None))
|
Ok((string, None))
|
||||||
}
|
}
|
||||||
|
Term::PartialString(_, tail_string, tail) => {
|
||||||
|
string += &tail_string;
|
||||||
|
Ok((string, Some(tail)))
|
||||||
|
}
|
||||||
_ => Ok((string, Some(Box::new(tail)))),
|
_ => Ok((string, Some(Box::new(tail)))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,7 +239,7 @@ pub struct Parser<'a, R> {
|
|||||||
terms: Vec<Term>,
|
terms: Vec<Term>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> {
|
pub fn read_tokens<R: CharRead>(lexer: &mut Lexer<'_, R>) -> Result<Vec<Token>, ParserError> {
|
||||||
let mut tokens = vec![];
|
let mut tokens = vec![];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@@ -263,22 +265,30 @@ fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserEr
|
|||||||
}
|
}
|
||||||
|
|
||||||
tokens.reverse();
|
tokens.reverse();
|
||||||
|
|
||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn atomize_term(atom_tbl: &AtomTable, term: &Term) -> Option<Atom> {
|
fn atomize_term(term: &Term) -> Option<Atom> {
|
||||||
match term {
|
match term {
|
||||||
Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c),
|
&Term::Literal(_, Literal::Atom(c)) => Some(c),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn atomize_constant(atom_tbl: &AtomTable, c: Literal) -> Option<Atom> {
|
impl TokenType {
|
||||||
match c {
|
fn sep_to_atom(&mut self) -> Option<Atom> {
|
||||||
Literal::Atom(ref name) => Some(*name),
|
match self {
|
||||||
Literal::Char(c) => Some(AtomTable::build_with(atom_tbl, &c.to_string())),
|
TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
|
||||||
_ => None,
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,21 +311,6 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_term_name(&mut self, td: TokenDesc) -> Option<Atom> {
|
fn get_term_name(&mut self, td: TokenDesc) -> Option<Atom> {
|
||||||
match td.tt {
|
match td.tt {
|
||||||
TokenType::HeadTailSeparator => Some(atom!("|")),
|
TokenType::HeadTailSeparator => Some(atom!("|")),
|
||||||
@@ -385,9 +380,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
|
|
||||||
fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
|
fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
|
||||||
let tt = match token {
|
let tt = match token {
|
||||||
Token::Literal(Literal::String(s))
|
Token::String(s) if self.lexer.machine_st.flags.double_quotes.is_codes() => {
|
||||||
if self.lexer.machine_st.flags.double_quotes.is_codes() =>
|
|
||||||
{
|
|
||||||
let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
|
let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
|
||||||
|
|
||||||
for c in s.as_str().chars().rev() {
|
for c in s.as_str().chars().rev() {
|
||||||
@@ -395,7 +388,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
Cell::default(),
|
Cell::default(),
|
||||||
Box::new(Term::Literal(
|
Box::new(Term::Literal(
|
||||||
Cell::default(),
|
Cell::default(),
|
||||||
Literal::Fixnum(Fixnum::build_with(c as i64)),
|
Literal::Fixnum(Fixnum::build_with(c)),
|
||||||
)),
|
)),
|
||||||
Box::new(list),
|
Box::new(list),
|
||||||
);
|
);
|
||||||
@@ -404,10 +397,10 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
self.terms.push(list);
|
self.terms.push(list);
|
||||||
TokenType::Term
|
TokenType::Term
|
||||||
}
|
}
|
||||||
Token::Literal(Literal::String(s))
|
Token::String(s) => {
|
||||||
if self.lexer.machine_st.flags.double_quotes.is_chars() =>
|
debug_assert!(self.lexer.machine_st.flags.double_quotes.is_chars());
|
||||||
{
|
self.terms
|
||||||
self.terms.push(Term::CompleteString(Cell::default(), s));
|
.push(Term::CompleteString(Cell::default(), Rc::new(s)));
|
||||||
TokenType::Term
|
TokenType::Term
|
||||||
}
|
}
|
||||||
Token::Literal(c) => {
|
Token::Literal(c) => {
|
||||||
@@ -549,17 +542,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
let idx = self.terms.len() - arity;
|
let idx = self.terms.len() - arity;
|
||||||
|
|
||||||
if TokenType::Term == self.stack[stack_len].tt
|
if TokenType::Term == self.stack[stack_len].tt
|
||||||
&& atomize_term(&self.lexer.machine_st.atom_tbl, &self.terms[idx - 1]).is_some()
|
&& atomize_term(&self.terms[idx - 1]).is_some()
|
||||||
{
|
{
|
||||||
self.stack.truncate(stack_len + 1);
|
self.stack.truncate(stack_len + 1);
|
||||||
|
|
||||||
let mut subterms: Vec<_> = self.terms.drain(idx..).collect();
|
let mut subterms: Vec<_> = self.terms.drain(idx..).collect();
|
||||||
|
|
||||||
if let Some(name) = self
|
if let Some(name) = self.terms.pop().and_then(|t| atomize_term(&t)) {
|
||||||
.terms
|
|
||||||
.pop()
|
|
||||||
.and_then(|t| atomize_term(&self.lexer.machine_st.atom_tbl, &t))
|
|
||||||
{
|
|
||||||
// reduce the '.' functor to a cons cell if it applies.
|
// reduce the '.' functor to a cons cell if it applies.
|
||||||
if name == atom!(".") && subterms.len() == 2 {
|
if name == atom!(".") && subterms.len() == 2 {
|
||||||
let tail = subterms.pop().unwrap();
|
let tail = subterms.pop().unwrap();
|
||||||
@@ -567,12 +556,10 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
|
|
||||||
self.terms.push(match as_partial_string(head, tail) {
|
self.terms.push(match as_partial_string(head, tail) {
|
||||||
Ok((string_buf, Some(tail))) => {
|
Ok((string_buf, Some(tail))) => {
|
||||||
Term::PartialString(Cell::default(), string_buf, tail)
|
Term::PartialString(Cell::default(), Rc::new(string_buf), tail)
|
||||||
}
|
}
|
||||||
Ok((string_buf, None)) => {
|
Ok((string_buf, None)) => {
|
||||||
let atom =
|
Term::CompleteString(Cell::default(), Rc::new(string_buf))
|
||||||
AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
|
|
||||||
Term::CompleteString(Cell::default(), atom)
|
|
||||||
}
|
}
|
||||||
Err(term) => term,
|
Err(term) => term,
|
||||||
});
|
});
|
||||||
@@ -754,11 +741,10 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
self.terms.push(match list {
|
self.terms.push(match list {
|
||||||
Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) {
|
Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) {
|
||||||
Ok((string_buf, Some(tail))) => {
|
Ok((string_buf, Some(tail))) => {
|
||||||
Term::PartialString(Cell::default(), string_buf, tail)
|
Term::PartialString(Cell::default(), Rc::new(string_buf), tail)
|
||||||
}
|
}
|
||||||
Ok((string_buf, None)) => {
|
Ok((string_buf, None)) => {
|
||||||
let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
|
Term::CompleteString(Cell::default(), Rc::new(string_buf))
|
||||||
Term::CompleteString(Cell::default(), atom)
|
|
||||||
}
|
}
|
||||||
Err(term) => term,
|
Err(term) => term,
|
||||||
},
|
},
|
||||||
@@ -846,7 +832,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(atom) = self.sep_to_atom(self.stack[idx].tt) {
|
if let Some(atom) = self.stack[idx].tt.sep_to_atom() {
|
||||||
self.terms
|
self.terms
|
||||||
.push(Term::Literal(Cell::default(), Literal::Atom(atom)));
|
.push(Term::Literal(Cell::default(), Literal::Atom(atom)));
|
||||||
}
|
}
|
||||||
@@ -967,8 +953,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
Token::Literal(Literal::Fixnum(n)) => {
|
Token::String(string) => {
|
||||||
self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n))
|
self.shift(Token::String(string), 0, TERM);
|
||||||
}
|
}
|
||||||
Token::Literal(Literal::Integer(n)) => {
|
Token::Literal(Literal::Integer(n)) => {
|
||||||
self.negate_number(n, negate_int_rc, |n, _| Literal::Integer(n))
|
self.negate_number(n, negate_int_rc, |n, _| Literal::Integer(n))
|
||||||
@@ -976,21 +962,34 @@ impl<'a, R: CharRead> Parser<'a, R> {
|
|||||||
Token::Literal(Literal::Rational(n)) => {
|
Token::Literal(Literal::Rational(n)) => {
|
||||||
self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r))
|
self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r))
|
||||||
}
|
}
|
||||||
Token::Literal(Literal::Float(n)) if F64Ptr::from_offset(n).is_infinite() => {
|
Token::Literal(Literal::F64Offset(n))
|
||||||
return Err(ParserError::InfiniteFloat(
|
if self
|
||||||
self.lexer.line_num,
|
.lexer
|
||||||
self.lexer.col_num,
|
.machine_st
|
||||||
));
|
.arena
|
||||||
}
|
.f64_tbl
|
||||||
Token::Literal(Literal::Float(n)) => self.negate_number(
|
.get_entry(n)
|
||||||
**n.as_ptr(),
|
.is_infinite() =>
|
||||||
|n, _| -n,
|
{
|
||||||
|n, arena| Literal::from(float_alloc!(n, arena)),
|
return Err(ParserError::InfiniteFloat(
|
||||||
),
|
self.lexer.line_num,
|
||||||
Token::Literal(c) => {
|
self.lexer.col_num,
|
||||||
let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c);
|
));
|
||||||
|
}
|
||||||
|
Token::Literal(Literal::F64Offset(n)) => {
|
||||||
|
let n = self.lexer.machine_st.arena.f64_tbl.get_entry(n);
|
||||||
|
|
||||||
if let Some(name) = atomized {
|
self.negate_number(
|
||||||
|
n,
|
||||||
|
|n, _| -n,
|
||||||
|
|n, arena| Literal::F64Offset(arena.f64_tbl.build_with(n)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Token::Literal(Literal::Fixnum(n)) => {
|
||||||
|
self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n))
|
||||||
|
}
|
||||||
|
Token::Literal(c) => {
|
||||||
|
if let Literal::Atom(name) = c {
|
||||||
if !self.shift_op(name, op_dir)? {
|
if !self.shift_op(name, op_dir)? {
|
||||||
self.shift(Token::Literal(c), 0, TERM);
|
self.shift(Token::Literal(c), 0, TERM);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ pub struct RawBlock<T: RawBlockTraits> {
|
|||||||
|
|
||||||
impl<T: RawBlockTraits> RawBlock<T> {
|
impl<T: RawBlockTraits> RawBlock<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn empty_block() -> Self {
|
pub fn empty_block() -> Self {
|
||||||
RawBlock {
|
RawBlock {
|
||||||
base: ptr::null(),
|
base: ptr::null(),
|
||||||
top: ptr::null(),
|
top: ptr::null(),
|
||||||
@@ -66,8 +66,8 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
self.base = new_base;
|
self.base = new_base;
|
||||||
self.top = (self.base as usize + size * 2) as *const _;
|
self.top = self.base.add(size * 2);
|
||||||
*self.ptr.get_mut() = (self.base as usize + size) as *mut _;
|
*self.ptr.get_mut() = self.base.add(size).cast_mut();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
// allocation failed
|
// allocation failed
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let allocated = (*self.ptr.get()) as usize - self.base as usize;
|
let allocated = (*self.ptr.get()).addr() - self.base.addr();
|
||||||
self.base.copy_to(new_block.base.cast_mut(), allocated);
|
self.base.copy_to(new_block.base.cast_mut(), allocated);
|
||||||
*new_block.ptr.get_mut() = new_block.base.add(allocated).cast_mut();
|
*new_block.ptr.get_mut() = new_block.base.add(allocated).cast_mut();
|
||||||
Some(new_block)
|
Some(new_block)
|
||||||
@@ -93,7 +93,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
self.top as usize - self.base as usize
|
self.top.addr() - self.base.addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -105,7 +105,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
self.base
|
self.base
|
||||||
);
|
);
|
||||||
|
|
||||||
self.top as usize - (*self.ptr.get()) as usize
|
self.top.addr() - (*self.ptr.get()).addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn alloc(&self, size: usize) -> *mut u8 {
|
pub unsafe fn alloc(&self, size: usize) -> *mut u8 {
|
||||||
|
|||||||
124
src/read.rs
124
src/read.rs
@@ -1,4 +1,5 @@
|
|||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
|
use crate::parser::lexer::Lexer;
|
||||||
use crate::parser::parser::*;
|
use crate::parser::parser::*;
|
||||||
|
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
@@ -32,9 +33,9 @@ use std::sync::Arc;
|
|||||||
type SubtermDeque = VecDeque<(usize, usize)>;
|
type SubtermDeque = VecDeque<(usize, usize)>;
|
||||||
|
|
||||||
pub(crate) fn devour_whitespace<R: CharRead>(
|
pub(crate) fn devour_whitespace<R: CharRead>(
|
||||||
parser: &mut Parser<'_, R>,
|
lexer: &mut Lexer<'_, R>,
|
||||||
) -> Result<bool, ParserError> {
|
) -> Result<bool, ParserError> {
|
||||||
match parser.lexer.scan_for_layout() {
|
match lexer.scan_for_layout() {
|
||||||
Err(e) if e.is_unexpected_eof() => Ok(true),
|
Err(e) if e.is_unexpected_eof() => Ok(true),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
Ok(_) => Ok(false),
|
Ok(_) => Ok(false),
|
||||||
@@ -80,7 +81,7 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inner.add_lines_read(num_lines_read);
|
inner.add_lines_read(num_lines_read);
|
||||||
write_term_to_heap(&term, &mut self.heap, &self.atom_tbl)
|
write_term_to_heap(&term, &mut self.heap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,16 +296,14 @@ impl CharRead for ReadlineStream {
|
|||||||
pub(crate) fn write_term_to_heap(
|
pub(crate) fn write_term_to_heap(
|
||||||
term: &Term,
|
term: &Term,
|
||||||
heap: &mut Heap,
|
heap: &mut Heap,
|
||||||
atom_tbl: &AtomTable,
|
|
||||||
) -> Result<TermWriteResult, CompilationError> {
|
) -> Result<TermWriteResult, CompilationError> {
|
||||||
let term_writer = TermWriter::new(heap, atom_tbl);
|
let term_writer = TermWriter::new(heap);
|
||||||
term_writer.write_term_to_heap(term)
|
term_writer.write_term_to_heap(term)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct TermWriter<'a, 'b> {
|
struct TermWriter<'a> {
|
||||||
heap: &'a mut Heap,
|
heap: &'a mut Heap,
|
||||||
atom_tbl: &'b AtomTable,
|
|
||||||
queue: SubtermDeque,
|
queue: SubtermDeque,
|
||||||
var_dict: HeapVarDict,
|
var_dict: HeapVarDict,
|
||||||
}
|
}
|
||||||
@@ -315,12 +314,11 @@ pub struct TermWriteResult {
|
|||||||
pub var_dict: HeapVarDict,
|
pub var_dict: HeapVarDict,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> TermWriter<'a, 'b> {
|
impl<'a> TermWriter<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(heap: &'a mut Heap, atom_tbl: &'b AtomTable) -> Self {
|
fn new(heap: &'a mut Heap) -> Self {
|
||||||
TermWriter {
|
TermWriter {
|
||||||
heap,
|
heap,
|
||||||
atom_tbl,
|
|
||||||
queue: SubtermDeque::new(),
|
queue: SubtermDeque::new(),
|
||||||
var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
|
var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
|
||||||
}
|
}
|
||||||
@@ -338,25 +336,23 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn push_stub_addr(&mut self) {
|
fn push_stub_addr(&mut self) -> Result<(), CompilationError> {
|
||||||
let h = self.heap.len();
|
let h = self.heap.cell_len();
|
||||||
self.heap.push(heap_loc_as_cell!(h));
|
self.push_cell(heap_loc_as_cell!(h))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), CompilationError> {
|
||||||
|
self.heap
|
||||||
|
.push_cell(cell)
|
||||||
|
.map_err(CompilationError::FiniteMemoryInHeap)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue {
|
fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue {
|
||||||
match term {
|
match term {
|
||||||
&TermRef::Cons(..) => list_loc_as_cell!(h),
|
&TermRef::Cons(..) => list_loc_as_cell!(h),
|
||||||
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
|
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
|
||||||
TermRef::CompleteString(_, _, src) => {
|
TermRef::PartialString(..) | TermRef::CompleteString(..) => heap_loc_as_cell!(h),
|
||||||
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::Literal(_, _, literal) => HeapCellValue::from(*literal),
|
||||||
&TermRef::Clause(_, _, _, subterms) if subterms.is_empty() => heap_loc_as_cell!(h),
|
&TermRef::Clause(_, _, _, subterms) if subterms.is_empty() => heap_loc_as_cell!(h),
|
||||||
&TermRef::Clause(..) => str_loc_as_cell!(h),
|
&TermRef::Clause(..) => str_loc_as_cell!(h),
|
||||||
@@ -364,45 +360,45 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_term_to_heap(mut self, term: &Term) -> Result<TermWriteResult, CompilationError> {
|
fn write_term_to_heap(mut self, term: &Term) -> Result<TermWriteResult, CompilationError> {
|
||||||
let heap_loc = self.heap.len();
|
let heap_loc = self.heap.cell_len();
|
||||||
|
|
||||||
for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
|
for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
|
||||||
let h = self.heap.len();
|
let h = self.heap.cell_len();
|
||||||
|
|
||||||
match &term {
|
match &term {
|
||||||
&TermRef::Cons(Level::Root, ..) => {
|
&TermRef::Cons(Level::Root, ..) => {
|
||||||
self.queue.push_back((2, h + 1));
|
self.queue.push_back((2, h + 1));
|
||||||
self.heap.push(list_loc_as_cell!(h + 1));
|
self.push_cell(list_loc_as_cell!(h + 1))?;
|
||||||
|
|
||||||
self.push_stub_addr();
|
self.push_stub_addr()?;
|
||||||
self.push_stub_addr();
|
self.push_stub_addr()?;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
&TermRef::Cons(..) => {
|
&TermRef::Cons(..) => {
|
||||||
self.queue.push_back((2, h));
|
self.queue.push_back((2, h));
|
||||||
|
|
||||||
self.push_stub_addr();
|
self.push_stub_addr()?;
|
||||||
self.push_stub_addr();
|
self.push_stub_addr()?;
|
||||||
}
|
}
|
||||||
&TermRef::Clause(Level::Root, _, name, subterms) => {
|
&TermRef::Clause(Level::Root, _, name, subterms) => {
|
||||||
if subterms.len() > MAX_ARITY {
|
if subterms.len() > MAX_ARITY {
|
||||||
return Err(CompilationError::ExceededMaxArity);
|
return Err(CompilationError::ExceededMaxArity);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.heap.push(if subterms.is_empty() {
|
self.push_cell(if subterms.is_empty() {
|
||||||
heap_loc_as_cell!(heap_loc + 1)
|
heap_loc_as_cell!(heap_loc + 1)
|
||||||
} else {
|
} else {
|
||||||
str_loc_as_cell!(heap_loc + 1)
|
str_loc_as_cell!(heap_loc + 1)
|
||||||
});
|
})?;
|
||||||
|
|
||||||
self.queue.push_back((subterms.len(), h + 2));
|
self.queue.push_back((subterms.len(), h + 2));
|
||||||
let named = atom_as_cell!(name, subterms.len());
|
let named = atom_as_cell!(name, subterms.len());
|
||||||
|
|
||||||
self.heap.push(named);
|
self.push_cell(named)?;
|
||||||
|
|
||||||
for _ in 0..subterms.len() {
|
for _ in 0..subterms.len() {
|
||||||
self.push_stub_addr();
|
self.push_stub_addr()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -411,20 +407,20 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
self.queue.push_back((subterms.len(), h + 1));
|
self.queue.push_back((subterms.len(), h + 1));
|
||||||
let named = atom_as_cell!(name, subterms.len());
|
let named = atom_as_cell!(name, subterms.len());
|
||||||
|
|
||||||
self.heap.push(named);
|
self.push_cell(named)?;
|
||||||
|
|
||||||
for _ in 0..subterms.len() {
|
for _ in 0..subterms.len() {
|
||||||
self.push_stub_addr();
|
self.push_stub_addr()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => {
|
&TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => {
|
||||||
let addr = self.term_as_addr(&term, h);
|
let addr = self.term_as_addr(&term, h);
|
||||||
self.heap.push(addr);
|
self.push_cell(addr)?;
|
||||||
}
|
}
|
||||||
&TermRef::Var(Level::Root, _, ref var_ptr) => {
|
&TermRef::Var(Level::Root, _, ref var_ptr) => {
|
||||||
let addr = self.term_as_addr(&term, h);
|
let addr = self.term_as_addr(&term, h);
|
||||||
self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr);
|
self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr);
|
||||||
self.heap.push(addr);
|
self.push_cell(addr)?;
|
||||||
}
|
}
|
||||||
&TermRef::AnonVar(_) => {
|
&TermRef::AnonVar(_) => {
|
||||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||||
@@ -438,25 +434,53 @@ impl<'a, 'b> TermWriter<'a, 'b> {
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TermRef::CompleteString(_, _, src) => {
|
TermRef::CompleteString(lvl, _, src) => {
|
||||||
let src = src.as_str().to_owned();
|
if let Level::Root = lvl {
|
||||||
put_complete_string(self.heap, &src, self.atom_tbl);
|
self.push_stub_addr()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell = self
|
||||||
|
.heap
|
||||||
|
.allocate_cstr(src)
|
||||||
|
.map_err(CompilationError::FiniteMemoryInHeap)?;
|
||||||
|
|
||||||
|
let new_h = self.heap.cell_len();
|
||||||
|
self.push_cell(cell)?;
|
||||||
|
|
||||||
|
if !matches!(lvl, Level::Root) {
|
||||||
|
self.modify_head_of_queue(&term, new_h);
|
||||||
|
} else {
|
||||||
|
self.heap[h] = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
&TermRef::PartialString(lvl, _, src, _) => {
|
TermRef::PartialString(lvl, _, src, _) => {
|
||||||
if let Level::Root = lvl {
|
if let Level::Root = lvl {
|
||||||
// Var tags can't refer directly to partial strings,
|
self.push_stub_addr()?;
|
||||||
// so a PStrLoc cell must be pushed.
|
|
||||||
self.heap.push(pstr_loc_as_cell!(heap_loc + 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
|
let cell = self
|
||||||
|
.heap
|
||||||
|
.allocate_pstr(src)
|
||||||
|
.map_err(CompilationError::FiniteMemoryInHeap)?;
|
||||||
|
|
||||||
let h = self.heap.len();
|
let tail_h = self.heap.cell_len();
|
||||||
self.queue.push_back((1, h - 1));
|
self.push_stub_addr()?;
|
||||||
|
|
||||||
if let Level::Root = lvl {
|
if matches!(lvl, Level::Root) {
|
||||||
continue;
|
self.heap[h] = cell;
|
||||||
|
} else {
|
||||||
|
self.push_cell(cell)?;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.queue.push_back((1, tail_h));
|
||||||
|
|
||||||
|
if !matches!(lvl, Level::Root) {
|
||||||
|
self.modify_head_of_queue(&term, tail_h + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
TermRef::Var(.., var) => {
|
TermRef::Var(.., var) => {
|
||||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ use crate::instructions::*;
|
|||||||
use crate::iterators::*;
|
use crate::iterators::*;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub(crate) struct FactInstruction;
|
pub(crate) struct FactInstruction;
|
||||||
pub(crate) struct QueryInstruction;
|
pub(crate) struct QueryInstruction;
|
||||||
|
|
||||||
@@ -14,14 +16,14 @@ pub(crate) trait CompilationTarget<'a> {
|
|||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator;
|
fn iter(term: &'a Term) -> Self::Iterator;
|
||||||
|
|
||||||
fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
|
fn to_constant(lvl: Level, constant: Literal, r: RegType) -> Instruction;
|
||||||
fn to_list(lvl: Level, r: RegType) -> Instruction;
|
fn to_list(lvl: Level, r: RegType) -> Instruction;
|
||||||
fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction;
|
fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction;
|
||||||
|
|
||||||
fn to_void(num_subterms: usize) -> Instruction;
|
fn to_void(num_subterms: usize) -> Instruction;
|
||||||
fn is_void_instr(instr: &Instruction) -> bool;
|
fn is_void_instr(instr: &Instruction) -> bool;
|
||||||
|
|
||||||
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction;
|
fn to_pstr(lvl: Level, string: Rc<String>, r: RegType) -> Instruction;
|
||||||
|
|
||||||
fn incr_void_instr(instr: &mut Instruction);
|
fn incr_void_instr(instr: &mut Instruction);
|
||||||
|
|
||||||
@@ -67,8 +69,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
|||||||
matches!(instr, &Instruction::UnifyVoid(_))
|
matches!(instr, &Instruction::UnifyVoid(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
|
fn to_pstr(lvl: Level, string: Rc<String>, r: RegType) -> Instruction {
|
||||||
Instruction::GetPartialString(lvl, string, r, has_tail)
|
Instruction::GetPartialString(lvl, string, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn incr_void_instr(instr: &mut Instruction) {
|
fn incr_void_instr(instr: &mut Instruction) {
|
||||||
@@ -125,16 +127,12 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|||||||
Instruction::PutStructure(name, arity, r)
|
Instruction::PutStructure(name, arity, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
|
|
||||||
Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_list(lvl: Level, reg: RegType) -> Instruction {
|
fn to_list(lvl: Level, reg: RegType) -> Instruction {
|
||||||
Instruction::PutList(lvl, reg)
|
Instruction::PutList(lvl, reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
|
fn to_pstr(lvl: Level, string: Rc<String>, r: RegType) -> Instruction {
|
||||||
Instruction::PutPartialString(lvl, string, r, has_tail)
|
Instruction::PutPartialString(lvl, string, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_void(subterms: usize) -> Instruction {
|
fn to_void(subterms: usize) -> Instruction {
|
||||||
@@ -155,6 +153,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|||||||
Instruction::SetConstant(HeapCellValue::from(constant))
|
Instruction::SetConstant(HeapCellValue::from(constant))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
|
||||||
|
Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
|
||||||
|
}
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
|
fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
|
||||||
Instruction::PutVariable(arg, val)
|
Instruction::PutVariable(arg, val)
|
||||||
}
|
}
|
||||||
|
|||||||
333
src/types.rs
333
src/types.rs
@@ -3,10 +3,12 @@
|
|||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::atom_table::*;
|
use crate::atom_table::*;
|
||||||
use crate::forms::*;
|
use crate::forms::*;
|
||||||
|
use crate::machine::heap::*;
|
||||||
use crate::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::machine::partial_string::PartialString;
|
|
||||||
use crate::machine::streams::*;
|
use crate::machine::streams::*;
|
||||||
|
use crate::offset_table::*;
|
||||||
use crate::parser::ast::Fixnum;
|
use crate::parser::ast::Fixnum;
|
||||||
|
use crate::parser::ast::Literal;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@@ -14,60 +16,67 @@ use std::fmt;
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Add, Sub, SubAssign};
|
use std::ops::{Add, Sub, SubAssign};
|
||||||
|
|
||||||
|
use dashu::{Integer, Rational};
|
||||||
|
|
||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
#[repr(u8)]
|
||||||
#[bits = 6]
|
#[bits = 6]
|
||||||
pub enum HeapCellValueTag {
|
pub enum HeapCellValueTag {
|
||||||
Str = 0b000011,
|
Str = 0b000001,
|
||||||
Lis = 0b000101,
|
Lis = 0b000101,
|
||||||
Var = 0b000111,
|
Var = 0b001011,
|
||||||
StackVar = 0b001001,
|
StackVar = 0b001101,
|
||||||
AttrVar = 0b001011,
|
AttrVar = 0b010001,
|
||||||
PStrLoc = 0b001101,
|
PStrLoc = 0b010011,
|
||||||
PStrOffset = 0b001111,
|
|
||||||
// constants.
|
// constants.
|
||||||
Cons = 0b0,
|
Cons = 0b0,
|
||||||
F64 = 0b010001,
|
F64Offset = 0b010101,
|
||||||
Fixnum = 0b010011,
|
Fixnum = 0b011001,
|
||||||
Char = 0b010101,
|
CodeIndexOffset = 0b011011,
|
||||||
Atom = 0b010111,
|
Atom = 0b011111,
|
||||||
PStr = 0b011001,
|
CutPoint = 0b011101,
|
||||||
CStr = 0b011011,
|
// trail elements.
|
||||||
CutPoint = 0b011111,
|
TrailedHeapVar = 0b100001,
|
||||||
|
TrailedStackVar = 0b100011,
|
||||||
|
TrailedAttrVar = 0b100101,
|
||||||
|
TrailedAttrVarListLink = 0b101001,
|
||||||
|
TrailedAttachedValue = 0b101011,
|
||||||
|
TrailedBlackboardEntry = 0b101101,
|
||||||
|
TrailedBlackboardOffset = 0b110001,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
#[repr(u8)]
|
||||||
#[bits = 6]
|
#[bits = 6]
|
||||||
pub enum HeapCellValueView {
|
pub enum HeapCellValueView {
|
||||||
Str = 0b000011,
|
Str = 0b000001,
|
||||||
Lis = 0b000101,
|
Lis = 0b000101,
|
||||||
Var = 0b000111,
|
Var = 0b001011,
|
||||||
StackVar = 0b001001,
|
StackVar = 0b001101,
|
||||||
AttrVar = 0b001011,
|
AttrVar = 0b010001,
|
||||||
PStrLoc = 0b001101,
|
PStrLoc = 0b010011,
|
||||||
PStrOffset = 0b001111,
|
|
||||||
// constants.
|
// constants.
|
||||||
Cons = 0b0,
|
Cons = 0b0,
|
||||||
F64 = 0b010001,
|
F64Offset = 0b010101,
|
||||||
Fixnum = 0b010011,
|
Fixnum = 0b011001,
|
||||||
Char = 0b010101,
|
CodeIndexOffset = 0b011011,
|
||||||
Atom = 0b010111,
|
Atom = 0b011111,
|
||||||
PStr = 0b011001,
|
CutPoint = 0b011101,
|
||||||
CStr = 0b011011,
|
|
||||||
CutPoint = 0b011111,
|
|
||||||
// trail elements.
|
// trail elements.
|
||||||
TrailedHeapVar = 0b101111,
|
TrailedHeapVar = 0b100001,
|
||||||
TrailedStackVar = 0b101011,
|
TrailedStackVar = 0b100011,
|
||||||
TrailedAttrVar = 0b100001,
|
TrailedAttrVar = 0b100101,
|
||||||
TrailedAttrVarListLink = 0b100011,
|
TrailedAttrVarListLink = 0b101001,
|
||||||
TrailedAttachedValue = 0b100101,
|
TrailedAttachedValue = 0b101011,
|
||||||
TrailedBlackboardEntry = 0b100111,
|
TrailedBlackboardEntry = 0b101101,
|
||||||
TrailedBlackboardOffset = 0b110011,
|
TrailedBlackboardOffset = 0b110001,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[bits = 1]
|
#[bits = 1]
|
||||||
pub enum ConsPtrMaskTag {
|
pub enum ConsPtrMaskTag {
|
||||||
Cons = 0b0,
|
Cons = 0b0,
|
||||||
|
Atom = 0b1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
@@ -84,7 +93,7 @@ impl ConsPtr {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
|
pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
|
||||||
ConsPtr::new()
|
ConsPtr::new()
|
||||||
.with_ptr(ptr as *const u8 as u64)
|
.with_ptr(ptr.expose_provenance() as u64)
|
||||||
.with_f(false)
|
.with_f(false)
|
||||||
.with_m(false)
|
.with_m(false)
|
||||||
.with_tag(tag)
|
.with_tag(tag)
|
||||||
@@ -93,7 +102,7 @@ impl ConsPtr {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn as_ptr(self) -> *mut u8 {
|
pub fn as_ptr(self) -> *mut u8 {
|
||||||
let addr: u64 = self.ptr();
|
let addr: u64 = self.ptr();
|
||||||
addr as usize as *mut _
|
std::ptr::with_exposed_provenance_mut(addr as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -105,9 +114,9 @@ impl ConsPtr {
|
|||||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
|
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
|
||||||
#[bits = 6]
|
#[bits = 6]
|
||||||
pub(crate) enum RefTag {
|
pub(crate) enum RefTag {
|
||||||
HeapCell = 0b000111,
|
HeapCell = 0b001011,
|
||||||
StackCell = 0b001001,
|
StackCell = 0b001101,
|
||||||
AttrVar = 0b001011,
|
AttrVar = 0b010001,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
@@ -245,15 +254,16 @@ pub struct HeapCellValue {
|
|||||||
val: B56,
|
val: B56,
|
||||||
f: bool,
|
f: bool,
|
||||||
m: bool,
|
m: bool,
|
||||||
|
#[allow(dead_code)]
|
||||||
tag: HeapCellValueTag,
|
tag: HeapCellValueTag,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for HeapCellValue {
|
impl fmt::Debug for HeapCellValue {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
HeapCellValueTag::F64 => f
|
HeapCellValueTag::F64Offset => f
|
||||||
.debug_struct("HeapCellValue")
|
.debug_struct("HeapCellValue")
|
||||||
.field("tag", &HeapCellValueTag::F64)
|
.field("tag", &HeapCellValueTag::F64Offset)
|
||||||
.field("offset", &self.get_value())
|
.field("offset", &self.get_value())
|
||||||
.field("m", &self.m())
|
.field("m", &self.m())
|
||||||
.field("f", &self.f())
|
.field("f", &self.f())
|
||||||
@@ -279,16 +289,6 @@ impl fmt::Debug for HeapCellValue {
|
|||||||
.field("f", &self.f())
|
.field("f", &self.f())
|
||||||
.finish()
|
.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
|
tag => f
|
||||||
.debug_struct("HeapCellValue")
|
.debug_struct("HeapCellValue")
|
||||||
.field("tag", &tag)
|
.field("tag", &tag)
|
||||||
@@ -300,20 +300,89 @@ impl fmt::Debug for HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Literal> for HeapCellValue {
|
||||||
|
#[inline]
|
||||||
|
fn from(literal: Literal) -> Self {
|
||||||
|
match literal {
|
||||||
|
Literal::Atom(name) => atom_as_cell!(name),
|
||||||
|
Literal::CodeIndexOffset(idx) => HeapCellValue::from(idx),
|
||||||
|
Literal::Fixnum(n) => fixnum_as_cell!(n),
|
||||||
|
Literal::Integer(bigint_ptr) => {
|
||||||
|
typed_arena_ptr_as_cell!(bigint_ptr)
|
||||||
|
}
|
||||||
|
Literal::Rational(bigint_ptr) => {
|
||||||
|
typed_arena_ptr_as_cell!(bigint_ptr)
|
||||||
|
}
|
||||||
|
Literal::F64Offset(f) => HeapCellValue::from(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<HeapCellValue> for Literal {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
|
||||||
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
|
if arity == 0 {
|
||||||
|
Ok(Literal::Atom(name))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Fixnum, n) => {
|
||||||
|
Ok(Literal::Fixnum(n))
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::F64Offset, f) => {
|
||||||
|
Ok(Literal::F64Offset(f))
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::CodeIndexOffset, idx) => {
|
||||||
|
Ok(Literal::CodeIndexOffset(idx))
|
||||||
|
}
|
||||||
|
(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(())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue
|
impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue
|
||||||
where
|
where
|
||||||
T::Payload: Sized,
|
T::Payload: Sized,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
|
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
|
||||||
HeapCellValue::from(arena_ptr.header_ptr() as u64)
|
HeapCellValue::from(arena_ptr.header_ptr().expose_provenance() as u64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<F64Ptr> for HeapCellValue {
|
impl From<F64Offset> for HeapCellValue {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(f64_ptr: F64Ptr) -> HeapCellValue {
|
fn from(f64_offset: F64Offset) -> HeapCellValue {
|
||||||
HeapCellValue::build_with(HeapCellValueTag::F64, f64_ptr.as_offset().to_u64())
|
HeapCellValue::build_with(HeapCellValueTag::F64Offset, f64_offset.to_u64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CodeIndexOffset> for HeapCellValue {
|
||||||
|
#[inline]
|
||||||
|
fn from(code_index_offset: CodeIndexOffset) -> HeapCellValue {
|
||||||
|
HeapCellValue::build_with(
|
||||||
|
HeapCellValueTag::CodeIndexOffset,
|
||||||
|
code_index_offset.to_u64(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,7 +390,7 @@ impl From<ConsPtr> for HeapCellValue {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(cons_ptr: ConsPtr) -> HeapCellValue {
|
fn from(cons_ptr: ConsPtr) -> HeapCellValue {
|
||||||
HeapCellValue::from_bytes(
|
HeapCellValue::from_bytes(
|
||||||
ConsPtr::from(cons_ptr.as_ptr() as u64)
|
ConsPtr::from(cons_ptr.as_ptr().expose_provenance() as u64)
|
||||||
.with_tag(ConsPtrMaskTag::Cons)
|
.with_tag(ConsPtrMaskTag::Cons)
|
||||||
.with_m(false)
|
.with_m(false)
|
||||||
.into_bytes(),
|
.into_bytes(),
|
||||||
@@ -354,19 +423,15 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool {
|
pub fn is_string_terminator(mut self, heap: &impl SizedHeap) -> bool {
|
||||||
use crate::machine::heap::*;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
return read_heap_cell!(self,
|
return read_heap_cell!(self,
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
name == atom!("[]") && arity == 0
|
name == atom!("[]") && arity == 0
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::CStr) => {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::PStrLoc, h) => {
|
(HeapCellValueTag::PStrLoc, h) => {
|
||||||
self = heap[h];
|
let HeapStringScan { tail_idx, .. } = heap.scan_slice_to_str(h);
|
||||||
|
self = heap[tail_idx];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||||
@@ -379,9 +444,6 @@ impl HeapCellValue {
|
|||||||
self = cell;
|
self = cell;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::PStrOffset, pstr_offset) => {
|
|
||||||
heap[pstr_offset].get_tag() == HeapCellValueTag::CStr
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -399,16 +461,12 @@ impl HeapCellValue {
|
|||||||
| HeapCellValueTag::StackVar
|
| HeapCellValueTag::StackVar
|
||||||
| HeapCellValueTag::AttrVar
|
| HeapCellValueTag::AttrVar
|
||||||
| HeapCellValueTag::PStrLoc
|
| HeapCellValueTag::PStrLoc
|
||||||
| HeapCellValueTag::PStrOffset
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_char(self) -> Option<char> {
|
pub fn as_char(self) -> Option<char> {
|
||||||
read_heap_cell!(self,
|
read_heap_cell!(self,
|
||||||
(HeapCellValueTag::Char, c) => {
|
|
||||||
Some(c)
|
|
||||||
}
|
|
||||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
if arity > 0 {
|
if arity > 0 {
|
||||||
return None;
|
return None;
|
||||||
@@ -426,11 +484,9 @@ impl HeapCellValue {
|
|||||||
pub fn is_constant(self) -> bool {
|
pub fn is_constant(self) -> bool {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
HeapCellValueTag::Cons
|
HeapCellValueTag::Cons
|
||||||
| HeapCellValueTag::F64
|
| HeapCellValueTag::F64Offset
|
||||||
| HeapCellValueTag::Fixnum
|
| HeapCellValueTag::Fixnum
|
||||||
| HeapCellValueTag::CutPoint
|
| HeapCellValueTag::CutPoint => true,
|
||||||
| HeapCellValueTag::Char
|
|
||||||
| HeapCellValueTag::CStr => true,
|
|
||||||
HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0,
|
HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@@ -442,16 +498,12 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_compound(self, heap: &[HeapCellValue]) -> bool {
|
pub fn is_compound(self, heap: &Heap) -> bool {
|
||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
HeapCellValueTag::Str => {
|
HeapCellValueTag::Str => {
|
||||||
cell_as_atom_cell!(heap[self.get_value() as usize]).get_arity() > 0
|
cell_as_atom_cell!(heap[self.get_value() as usize]).get_arity() > 0
|
||||||
}
|
}
|
||||||
HeapCellValueTag::Lis
|
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => true,
|
||||||
| HeapCellValueTag::CStr
|
|
||||||
| HeapCellValueTag::PStr
|
|
||||||
| HeapCellValueTag::PStrLoc
|
|
||||||
| HeapCellValueTag::PStrOffset => true,
|
|
||||||
HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() > 0,
|
HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() > 0,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@@ -502,6 +554,7 @@ impl HeapCellValue {
|
|||||||
match self.tag_or_err() {
|
match self.tag_or_err() {
|
||||||
Ok(tag) => tag,
|
Ok(tag) => tag,
|
||||||
Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
|
Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
|
||||||
|
ConsPtrMaskTag::Atom => HeapCellValueTag::Atom,
|
||||||
ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
|
ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -509,16 +562,8 @@ impl HeapCellValue {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_atom(self) -> Option<Atom> {
|
pub fn to_atom(self) -> Option<Atom> {
|
||||||
match self.tag() {
|
match self.get_tag() {
|
||||||
HeapCellValueTag::Atom => Some(Atom::from(self.val() << 3)),
|
HeapCellValueTag::Atom => Some(AtomCell::from_bytes(self.into_bytes()).get_name()),
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn to_pstr(self) -> Option<PartialString> {
|
|
||||||
match self.tag() {
|
|
||||||
HeapCellValueTag::PStr => Some(PartialString::from(Atom::from(self.val() << 3))),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -531,6 +576,16 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: someone that knows this better should check if this can be split into `to_fixnum_unchecked` and `to_cut_point_unchecked` assuming thats always unambigusly knowable
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn to_fixnum_or_cut_point_unchecked(self) -> Fixnum {
|
||||||
|
debug_assert!(matches!(
|
||||||
|
self.get_tag(),
|
||||||
|
HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint
|
||||||
|
));
|
||||||
|
Fixnum::from_bytes(self.into_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_ptr_addr(ptr_bytes: usize) -> Self {
|
pub fn from_ptr_addr(ptr_bytes: usize) -> Self {
|
||||||
HeapCellValue::from_bytes((ptr_bytes as u64).to_ne_bytes())
|
HeapCellValue::from_bytes((ptr_bytes as u64).to_ne_bytes())
|
||||||
@@ -593,38 +648,53 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn order_category(self, heap: &[HeapCellValue]) -> Option<TermOrderCategory> {
|
pub fn order_category(self, heap: &Heap) -> Option<TermOrderCategory> {
|
||||||
match Number::try_from(self).ok() {
|
read_heap_cell!(self,
|
||||||
Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
|
(HeapCellValueTag::Cons, c) => {
|
||||||
|
match_untyped_arena_ptr!(c,
|
||||||
|
(ArenaHeaderTag::Integer, _n) => {
|
||||||
|
Some(TermOrderCategory::Integer)
|
||||||
|
}
|
||||||
|
(ArenaHeaderTag::Rational, _n) => {
|
||||||
|
Some(TermOrderCategory::Integer)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::F64Offset) => {
|
||||||
|
Some(TermOrderCategory::FloatingPoint)
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint) => {
|
||||||
Some(TermOrderCategory::Integer)
|
Some(TermOrderCategory::Integer)
|
||||||
}
|
}
|
||||||
Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint),
|
(HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
|
||||||
None => match self.get_tag() {
|
Some(TermOrderCategory::Variable)
|
||||||
HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => {
|
}
|
||||||
Some(TermOrderCategory::Variable)
|
(HeapCellValueTag::Atom, (_name, arity)) => {
|
||||||
}
|
Some(if arity > 0 {
|
||||||
HeapCellValueTag::Char => Some(TermOrderCategory::Atom),
|
|
||||||
HeapCellValueTag::Atom => Some(if cell_as_atom_cell!(self).get_arity() > 0 {
|
|
||||||
TermOrderCategory::Compound
|
TermOrderCategory::Compound
|
||||||
} else {
|
} else {
|
||||||
TermOrderCategory::Atom
|
TermOrderCategory::Atom
|
||||||
}),
|
})
|
||||||
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr => {
|
}
|
||||||
|
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
|
||||||
|
Some(TermOrderCategory::Compound)
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let arity = cell_as_atom_cell!(heap[s]).get_arity();
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
Some(TermOrderCategory::Atom)
|
||||||
|
} else {
|
||||||
Some(TermOrderCategory::Compound)
|
Some(TermOrderCategory::Compound)
|
||||||
}
|
}
|
||||||
HeapCellValueTag::Str => {
|
}
|
||||||
let value = heap[self.get_value() as usize];
|
_ => {
|
||||||
let arity = cell_as_atom_cell!(value).get_arity();
|
None
|
||||||
|
}
|
||||||
if arity == 0 {
|
)
|
||||||
Some(TermOrderCategory::Atom)
|
|
||||||
} else {
|
|
||||||
Some(TermOrderCategory::Compound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -640,7 +710,7 @@ impl HeapCellValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const_assert!(mem::size_of::<HeapCellValue>() == 8);
|
const_assert!(size_of::<HeapCellValue>() == 8);
|
||||||
|
|
||||||
#[bitfield]
|
#[bitfield]
|
||||||
#[repr(u64)]
|
#[repr(u64)]
|
||||||
@@ -666,21 +736,21 @@ const_assert!(mem::size_of::<UntypedArenaPtr>() == 8);
|
|||||||
impl From<*const ArenaHeader> for UntypedArenaPtr {
|
impl From<*const ArenaHeader> for UntypedArenaPtr {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr {
|
fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr {
|
||||||
UntypedArenaPtr::build_with(ptr as usize)
|
UntypedArenaPtr::build_with(ptr.expose_provenance())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<*const IndexPtr> for UntypedArenaPtr {
|
impl From<*const IndexPtr> for UntypedArenaPtr {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(ptr: *const IndexPtr) -> UntypedArenaPtr {
|
fn from(ptr: *const IndexPtr) -> UntypedArenaPtr {
|
||||||
UntypedArenaPtr::build_with(ptr as usize)
|
UntypedArenaPtr::build_with(ptr.expose_provenance())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<UntypedArenaPtr> for *const ArenaHeader {
|
impl From<UntypedArenaPtr> for *const ArenaHeader {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {
|
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {
|
||||||
ptr.get_ptr() as *const ArenaHeader
|
ptr.get_ptr().cast::<ArenaHeader>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,21 +763,21 @@ impl UntypedArenaPtr {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_ptr(self) -> *const u8 {
|
pub fn get_ptr(self) -> *const u8 {
|
||||||
let addr: u64 = self.ptr();
|
let addr: u64 = self.ptr();
|
||||||
addr as usize as *const u8
|
std::ptr::with_exposed_provenance(addr as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_tag(self) -> ArenaHeaderTag {
|
pub fn get_tag(self) -> ArenaHeaderTag {
|
||||||
unsafe {
|
unsafe {
|
||||||
debug_assert!(!self.get_ptr().is_null());
|
debug_assert!(!self.get_ptr().is_null());
|
||||||
let header = *(self.get_ptr() as *const ArenaHeader);
|
let header = *self.get_ptr().cast::<ArenaHeader>();
|
||||||
header.get_tag()
|
header.get_tag()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn payload_offset(self) -> *const u8 {
|
pub fn payload_offset(self) -> *const u8 {
|
||||||
unsafe { self.get_ptr().add(mem::size_of::<ArenaHeader>()) }
|
unsafe { self.get_ptr().add(size_of::<ArenaHeader>()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@@ -734,12 +804,14 @@ impl Add<usize> for HeapCellValue {
|
|||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
tag @ HeapCellValueTag::Str
|
tag @ HeapCellValueTag::Str
|
||||||
| tag @ HeapCellValueTag::Lis
|
| tag @ HeapCellValueTag::Lis
|
||||||
| tag @ HeapCellValueTag::PStrOffset
|
|
||||||
| tag @ HeapCellValueTag::PStrLoc
|
|
||||||
| tag @ HeapCellValueTag::Var
|
| tag @ HeapCellValueTag::Var
|
||||||
| tag @ HeapCellValueTag::AttrVar => {
|
| tag @ HeapCellValueTag::AttrVar => {
|
||||||
HeapCellValue::build_with(tag, (self.get_value() as usize + rhs) as u64)
|
HeapCellValue::build_with(tag, (self.get_value() as usize + rhs) as u64)
|
||||||
}
|
}
|
||||||
|
tag @ HeapCellValueTag::PStrLoc => {
|
||||||
|
let value = (self.get_value() as usize + heap_index!(rhs)) as u64;
|
||||||
|
HeapCellValue::build_with(tag, value)
|
||||||
|
}
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -752,12 +824,14 @@ impl Sub<usize> for HeapCellValue {
|
|||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
tag @ HeapCellValueTag::Str
|
tag @ HeapCellValueTag::Str
|
||||||
| tag @ HeapCellValueTag::Lis
|
| tag @ HeapCellValueTag::Lis
|
||||||
| tag @ HeapCellValueTag::PStrOffset
|
|
||||||
| tag @ HeapCellValueTag::PStrLoc
|
|
||||||
| tag @ HeapCellValueTag::Var
|
| tag @ HeapCellValueTag::Var
|
||||||
| tag @ HeapCellValueTag::AttrVar => {
|
| tag @ HeapCellValueTag::AttrVar => {
|
||||||
HeapCellValue::build_with(tag, (self.get_value() as usize - rhs) as u64)
|
HeapCellValue::build_with(tag, (self.get_value() as usize - rhs) as u64)
|
||||||
}
|
}
|
||||||
|
tag @ HeapCellValueTag::PStrLoc => {
|
||||||
|
let value = self.get_value() as usize - heap_index!(rhs);
|
||||||
|
HeapCellValue::build_with(tag, value as u64)
|
||||||
|
}
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -778,12 +852,15 @@ impl Sub<i64> for HeapCellValue {
|
|||||||
match self.get_tag() {
|
match self.get_tag() {
|
||||||
tag @ HeapCellValueTag::Str
|
tag @ HeapCellValueTag::Str
|
||||||
| tag @ HeapCellValueTag::Lis
|
| tag @ HeapCellValueTag::Lis
|
||||||
| tag @ HeapCellValueTag::PStrOffset
|
|
||||||
| tag @ HeapCellValueTag::PStrLoc
|
|
||||||
| tag @ HeapCellValueTag::Var
|
| tag @ HeapCellValueTag::Var
|
||||||
| tag @ HeapCellValueTag::AttrVar => {
|
| tag @ HeapCellValueTag::AttrVar => {
|
||||||
HeapCellValue::build_with(tag, self.get_value() + rhs.unsigned_abs())
|
HeapCellValue::build_with(tag, self.get_value() + rhs.unsigned_abs())
|
||||||
}
|
}
|
||||||
|
tag @ HeapCellValueTag::PStrLoc => {
|
||||||
|
let value =
|
||||||
|
self.get_value() as usize + heap_index!(rhs.unsigned_abs() as usize);
|
||||||
|
HeapCellValue::build_with(tag, value as u64)
|
||||||
|
}
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::forms::GenContext;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
|
|
||||||
use bit_set::*;
|
use bit_set::*;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
:- op(10, xf, [example, Var]).
|
:- op(10, xf, [example, Var]).
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
test :- load_html("<html><head><title>Hello!</title></head></html>", Es, []), write(Es).
|
test :- load_html("<html><head><title>Hello!</title></head></html>", Es, []), write(Es).
|
||||||
|
|
||||||
:- initialization(test).
|
:- initialization(test).
|
||||||
|
|||||||
11
tests-pl/issue2949.pl
Normal file
11
tests-pl/issue2949.pl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
:- use_module(library(sgml)).
|
||||||
|
|
||||||
|
test :-
|
||||||
|
load_html("<!DOCTYPE html><html><head><title>Hello!</title></head></html>", Es, []),
|
||||||
|
write(Es),
|
||||||
|
load_html("<!DOCTYPE html><html><head><title>Hello!</title><!-- comment --></head></html>", Es2, []),
|
||||||
|
write(Es2),
|
||||||
|
load_html("<!", Es3, []),
|
||||||
|
write(Es3).
|
||||||
|
|
||||||
|
:- initialization(test).
|
||||||
@@ -27,6 +27,7 @@ use_module(library(ordsets)).
|
|||||||
use_module(library(os)).
|
use_module(library(os)).
|
||||||
use_module(library(pairs)).
|
use_module(library(pairs)).
|
||||||
use_module(library(pio)).
|
use_module(library(pio)).
|
||||||
|
use_module(library(process)).
|
||||||
use_module(library(queues)).
|
use_module(library(queues)).
|
||||||
use_module(library(random)).
|
use_module(library(random)).
|
||||||
use_module(library(reif)).
|
use_module(library(reif)).
|
||||||
|
|||||||
@@ -45,3 +45,4 @@
|
|||||||
true.
|
true.
|
||||||
true.
|
true.
|
||||||
true.
|
true.
|
||||||
|
true.
|
||||||
|
|||||||
59
tests/scryer/cli/src_tests/process.md
Normal file
59
tests/scryer/cli/src_tests/process.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid, process(P)]), process_kill(P), halt'
|
||||||
|
use_module(library(process)),process_create([],[],[invalid,process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),[predicate-process_create/3,predicate-check_options/3,predicate-must_be_known_options/3])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid(_Var), process(P)]), process_kill(P), halt'
|
||||||
|
use_module(library(process)),process_create([],[],[invalid(_Var),process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),[predicate-process_create/3,predicate-check_options/3,predicate-must_be_known_options/3])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(null), stdin(null), process(P)]), process_kill(P), halt'
|
||||||
|
use_module(library(process)),process_create([],[],[stdin(null),stdin(null),process(P)]),process_kill(P),halt causes: error(domain_error(non_duplicate_options,stdin),[predicate-process_create/3,predicate-check_options/3,predicate-must_be_known_options/3])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [env([]), environment([]), process(P)]), process_kill(P), halt'
|
||||||
|
use_module(library(process)),process_create([],[],[env([]),environment([]),process(P)]),process_kill(P),halt causes: error(domain_error(non_conflicting_options,[env([]),environment([])]),[predicate-process_create/3,predicate-check_options/3,predicate-extract_options/2])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(pid, _Status, [invalid(_Var), timeout(0)]), halt'
|
||||||
|
use_module(library(process)),process_wait(pid,_Status,[invalid(_Var),timeout(0)]),halt causes: error(domain_error(process_wait_option,invalid),[predicate-process_wait/3,predicate-check_options/3,predicate-must_be_known_options/3])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(invalid), process(P)]), process_kill(P), halt'
|
||||||
|
use_module(library(process)),process_create([],[],[stdin(invalid),process(P)]),process_kill(P),halt causes: error(domain_error(stdio_spec,invalid),[predicate-process_create/3,predicate-check_options/3,predicate-extract_options/2,predicate-valid_stdio/1])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(50, _Status), halt'
|
||||||
|
use_module(library(process)),process_wait(50,_Status),halt causes: error(type_error(process,50),[predicate-process_wait/2,predicate-process_wait/3|process_wait/3])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_kill(50), halt'
|
||||||
|
use_module(library(process)),process_kill(50),halt causes: error(type_error(process,50),[predicate-process_kill/1|process_kill/1])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_id(50,_Pid), halt'
|
||||||
|
use_module(library(process)),process_id(50,_Pid),halt causes: error(type_error(process,50),[predicate-process_id/2|process_id/2])
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_release(50), halt'
|
||||||
|
use_module(library(process)),process_release(50),halt causes: error(type_error(process,50),[predicate-process_release/1,predicate-process_wait/2,predicate-process_wait/3|process_wait/3])
|
||||||
|
|
||||||
|
```
|
||||||
14
tests/scryer/cli/unix/process.md
Normal file
14
tests/scryer/cli/unix/process.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("false", [], [process(P)]), process_wait(P, exit(1)), halt'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), use_module(library(format)), process_create("sh", [], [process(P), stdout(null), stdin(pipe(S))]), format(S, "exit 1~n", []), process_wait(P, exit(1)), halt'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("sh", ["-c", "sleep 5"], [process(P), stdout(null)]), process_kill(P), process_wait(P, killed(9)), halt'
|
||||||
|
|
||||||
|
```
|
||||||
9
tests/scryer/cli/windows/process.md
Normal file
9
tests/scryer/cli/windows/process.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("cmd", ["/C", "exit", "1"], [process(P)]), process_wait(P, exit(1)), halt'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```trycmd
|
||||||
|
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), use_module(library(format)), process_create("cmd", [], [process(P), stdout(null), stdin(pipe(S))]), format(S, "exit 1~n", []), process_wait(P, exit(1)), halt'
|
||||||
|
|
||||||
|
```
|
||||||
@@ -20,6 +20,12 @@ fn issue2588_load_html() {
|
|||||||
load_module_test("tests-pl/issue2588.pl", "[element(html,[],[element(head,[],[element(title,[],[[H,e,l,l,o,!]])]),element(body,[],[])])]");
|
load_module_test("tests-pl/issue2588.pl", "[element(html,[],[element(head,[],[element(title,[],[[H,e,l,l,o,!]])]),element(body,[],[])])]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "unsupported operation when isolation is enabled")]
|
||||||
|
fn issue2949_load_html() {
|
||||||
|
load_module_test("tests-pl/issue2949.pl", "[doctype([h,t,m,l]),element(html,[],[element(head,[],[element(title,[],[[H,e,l,l,o,!]])]),element(body,[],[])])][doctype([h,t,m,l]),element(html,[],[element(head,[],[element(title,[],[[H,e,l,l,o,!]]),comment([ ,c,o,m,m,e,n,t, ])]),element(body,[],[])])][comment([]),element(html,[],[element(head,[],[]),element(body,[],[])])]");
|
||||||
|
}
|
||||||
|
|
||||||
// issue #2361
|
// issue #2361
|
||||||
#[serial]
|
#[serial]
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -19,9 +19,20 @@ mod src_tests;
|
|||||||
ignore = "miri isolation, unsupported operation: can't call foreign function"
|
ignore = "miri isolation, unsupported operation: can't call foreign function"
|
||||||
)]
|
)]
|
||||||
fn cli_tests() {
|
fn cli_tests() {
|
||||||
trycmd::TestCases::new()
|
let cases = trycmd::TestCases::new();
|
||||||
|
cases
|
||||||
.default_bin_name("scryer-prolog")
|
.default_bin_name("scryer-prolog")
|
||||||
.case("tests/scryer/cli/issues/*.toml")
|
.case("tests/scryer/cli/issues/*.toml")
|
||||||
.case("tests/scryer/cli/src_tests/*.toml")
|
.case("tests/scryer/cli/src_tests/*.toml")
|
||||||
.case("tests/scryer/cli/src_tests/*.md");
|
.case("tests/scryer/cli/src_tests/*.md");
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
cases.case("tests/scryer/cli/windows/*.md");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
cases.case("tests/scryer/cli/unix/*.md");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user