Merge pull request #3021 from mthom/rebis-dev

Merge rebis-dev to master
This commit is contained in:
Mark Thom
2025-08-02 00:01:39 -07:00
committed by GitHub
71 changed files with 10768 additions and 8165 deletions

View File

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

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

View File

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

View File

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

View File

@@ -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)| {
for (c, ptr) in constants.iter() {
let key_value_pair = functor!(
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!( functor!(
atom!("switch_on_constant"), atom!(":"),
[str(orig_h, 0)], [cell((*c)), indexing_code_ptr((*ptr))]
[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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,9 +1119,7 @@ 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 optimal_index != instantiated_arg_index {
if left >= right { if left >= right {
optimal_index = instantiated_arg_index; optimal_index = instantiated_arg_index;
@@ -1170,7 +1140,6 @@ impl<'b> CodeGenerator<'b> {
} }
} }
} }
}
if left < right { if left < right {
subseqs.push(ClauseSpan { subseqs.push(ClauseSpan {
@@ -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);
} }
} }

View File

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

View File

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

View File

@@ -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,9 +806,9 @@ 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
View 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!());
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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| {
match Number::try_from((addr, f64_tbl)) {
Ok(Number::Fixnum(n)) => n.get_num() > 0, Ok(Number::Fixnum(n)) => n.get_num() > 0,
Ok(Number::Float(OrderedFloat(f))) => f > 0f64, Ok(Number::Float(OrderedFloat(f))) => f > 0f64,
Ok(Number::Integer(n)) => n.is_positive(), Ok(Number::Integer(n)) => n.is_positive(),
Ok(Number::Rational(n)) => n.is_positive(), Ok(Number::Rational(n)) => n.is_positive(),
_ => false, _ => 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) => {
match_untyped_arena_ptr!(c,
(ArenaHeaderTag::Integer, n) => {
if !n.is_negative() {
Some(numbervar(Integer::from(offset + &*n)))
} else {
None
}
}
_ => {
None
}
)
}
(HeapCellValueTag::Fixnum, n) => {
if n.get_num() >= 0 {
Some(numbervar(offset + Integer::from(n.get_num()))) Some(numbervar(offset + Integer::from(n.get_num())))
} else {
None
} }
Ok(Number::Integer(n)) if !n.is_negative() => Some(numbervar(Integer::from(offset + &*n))),
_ => 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;
} }
macro_rules! emit_char {
($c:expr) => {{
append_str!(self, "'.'"); append_str!(self, "'.'");
push_char!(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,21 +1217,47 @@ 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() {
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 iter {
for c in char_to_string(c).chars() { for c in char_to_string(c).chars() {
push_char!(self, c); 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() {
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 iter.take(max_depth - char_count) {
char_count += 1; char_count += 1;
for c in char_to_string(c).chars() { for c in char_to_string(c).chars() {
push_char!(self, c); push_char!(self, c);
} }
} }
}
if char_count == max_depth { if char_count == max_depth {
append_str!(self, " ..."); append_str!(self, " ...");
@@ -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;
if let Ok(n) = Fixnum::build_with_checked(idx_ptr_p) {
TokenOrRedirect::NumberFocus( TokenOrRedirect::NumberFocus(
max_depth, max_depth,
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx))), NumberFocus::Unfocused(Number::Fixnum(n)),
None, 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));
let mut writer = wam.machine_st.heap.reserve(6002).unwrap();
writer.write_with(|section| {
section.push_cell(list_loc_as_cell!(1));
for idx in 0..3000 { for idx in 0..3000 {
wam.machine_st.heap.push(heap_loc_as_cell!(2 * idx + 1)); section.push_cell(heap_loc_as_cell!(2 * idx + 1));
wam.machine_st.heap.push(list_loc_as_cell!(2 * idx + 2 + 1)); section.push_cell(list_loc_as_cell!(2 * idx + 2 + 1));
} }
wam.machine_st.heap.push(empty_list_as_cell!()); 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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 replacement = read_heap_cell!(self.target[pstr_loc],
(HeapCellValueTag::CStr) => {
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
*self.value_at_scan() = pstr_offset_as_cell!(threshold);
self.target.push(self.target[pstr_loc]);
heap_loc_as_cell!(threshold)
} }
_ => {
*self.value_at_scan() = if scan_tag == HeapCellValueTag::PStrLoc { let offset = self
pstr_loc_as_cell!(threshold) .target
.as_slice_from(pstr_loc)
.take_while(|b| *b != 0u8)
.count();
let left_pstr_boundary = cell_index!(pstr_loc + offset);
let flag = u64::from_be_bytes(self.target[left_pstr_boundary].into_bytes());
let pstr_loc_idx = cell_index!(pstr_loc);
if flag == 1 {
if left_pstr_boundary != pstr_loc_idx {
let mut pstr_data = self
.pstr_loc_locs
.remove(&heap_index!(left_pstr_boundary))
.unwrap();
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 { } else {
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); let pstr_data = self
pstr_offset_as_cell!(threshold) .pstr_loc_locs
.get_mut(&heap_index!(left_pstr_boundary))
.unwrap();
pstr_data.post_old_h_pstr_loc_locs.insert(self.scan);
}
} else {
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));
let old_tail_idx = if (pstr_loc + offset + 1) % Heap::heap_cell_alignment() == 0 {
cell_index!(pstr_loc + offset) + 2
} else {
cell_index!(pstr_loc + offset) + 1
}; };
self.target.push(self.target[pstr_loc]); let tail_cell = self.target[old_tail_idx];
self.target.push(self.target[pstr_loc + 1]);
pstr_loc_as_cell!(threshold) 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;
} }
); )?;
}
} }
fn unwind_trail(mut self) { Ok(())
for (r, value) in self.trail { }
let index = r.get_value() as usize;
match r.get_tag() { fn copy_pstrs(&mut self) -> Result<(), usize> {
RefTag::AttrVar | RefTag::HeapCell => { while let Some((least_pstr_loc, pstr_data)) = self.pstr_loc_locs.pop_first() {
let threshold = heap_index!(self.target.threshold());
for pstr_loc_loc in pstr_data.post_old_h_pstr_loc_locs {
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));

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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,8 +574,7 @@ 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
@@ -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);

View File

@@ -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(
code_idx.into(),
|code_idx_ptr| match compilation_target {
CompilationTarget::User => { CompilationTarget::User => {
if IndexPtrTag::Undefined == code_index.get().tag() { if IndexPtrTag::Undefined == code_idx_ptr.tag() {
code_index.set(code_ptr); *code_idx_ptr = code_ptr;
RetractionRecord::AddedUserPredicate(key) RetractionRecord::AddedUserPredicate(key)
} else { } else {
let replaced = code_index.replace(code_ptr); let replaced = mem::replace(code_idx_ptr, code_ptr);
RetractionRecord::ReplacedUserPredicate(key, replaced) RetractionRecord::ReplacedUserPredicate(key, replaced)
} }
} }
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(ref module_name) => {
if IndexPtrTag::Undefined == code_index.get().tag() { if IndexPtrTag::Undefined == code_idx_ptr.tag() {
code_index.set(code_ptr); *code_idx_ptr = code_ptr;
RetractionRecord::AddedModulePredicate(*module_name, key) RetractionRecord::AddedModulePredicate(*module_name, key)
} else { } else {
let replaced = code_index.replace(code_ptr); let replaced = mem::replace(code_idx_ptr, 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(
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
if global_skeleton.core.is_dynamic {
IndexPtr::dynamic_undefined() IndexPtr::dynamic_undefined()
} else { } else {
IndexPtr::undefined() 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)
} }

View File

@@ -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,46 +1395,32 @@ 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 {
let value = iter.heap[h + arity + 1];
if let Some(idx) = get_structure_index(value) { if let Some(idx) = get_structure_index(value) {
// in the second condition, arity == 0, term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndexOffset(idx.into())));
// 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; arity += 1;
} }
}
}
if arity == 0 { if arity == 0 {
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
@@ -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!("[]")))) {
Term::CompleteString(
Cell::default(), Cell::default(),
atom.as_str().to_owned(), Rc::new(string.to_owned()),
)
} else {
Term::PartialString(
Cell::default(),
Rc::new(string.to_owned()),
Box::new(tail), 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 { }
};
writer.write_with(|section| {
section.push_cell(atom_as_cell!(predicate_name, arity));
for meta_spec in meta_specs.iter() {
section.push_cell(match meta_spec {
MetaSpec::Minus => atom_as_cell!(atom!("+")), MetaSpec::Minus => atom_as_cell!(atom!("+")),
MetaSpec::Plus => atom_as_cell!(atom!("-")), MetaSpec::Plus => atom_as_cell!(atom!("-")),
MetaSpec::Either => atom_as_cell!(atom!("?")), MetaSpec::Either => atom_as_cell!(atom!("?")),
MetaSpec::Colon => atom_as_cell!(atom!(":")), MetaSpec::Colon => atom_as_cell!(atom!(":")),
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
fixnum_as_cell!(Fixnum::build_with(*arg_num as i64)) fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
Fixnum::build_with_unchecked(*arg_num as i64)
})
}
});
} }
}));
let heap_loc = self.machine_st.heap.len(); section.push_cell(atom_as_cell!(atom!("meta_predicate"), 1));
section.push_cell(str_loc_as_cell!(term_loc));
});
self.machine_st let heap_loc = self.machine_st.heap.cell_len() - 2;
.heap
.push(atom_as_cell!(atom!("meta_predicate"), 1));
self.machine_st.heap.push(str_loc_as_cell!(term_loc));
unify!( unify!(
self.machine_st, self.machine_st,

View File

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

View File

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

View File

@@ -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();
let true_size = if size > 0 {
let mut writer = heap.reserve(2 + 5 * size)?;
writer
.write_with(|section| {
let mut size = 0;
for (var, binding) in iter { for (var, binding) in iter {
let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
let h = heap.len();
heap.push(atom_as_cell!(atom!("="), 2)); section.push_cell(atom_as_cell!(atom!("="), 2));
heap.push(atom_as_cell!(var_atom)); section.push_cell(atom_as_cell!(var_atom));
heap.push(*binding); section.push_cell(*binding);
list_of_var_eqs.push(str_loc_as_cell!(h)); size += 1;
} }
list_of_var_eqs 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!(
self,
sized_iter_to_heap_list(
&mut self.heap, &mut self.heap,
var_list.into_iter().map(|(_, cell, _)| cell) 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!(
self,
push_var_eq_functors(
&mut self.heap, &mut self.heap,
list_of_var_eqs.into_iter() var_list.len(),
)); var_list.iter().filter_map(|(var_name, var, _)| {
if var_name.is_anon() {
Ok(unify_fn!(*self, var_names_offset, var_names_addr)) 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,8 +690,11 @@ impl MachineState {
} }
} }
let singleton_var_list = push_var_eq_functors( let singleton_var_list = resource_error_call_result!(
self,
push_var_eq_functors(
&mut self.heap, &mut self.heap,
term_write_result.var_dict.len(),
term_write_result term_write_result
.var_dict .var_dict
.iter() .iter()
@@ -639,12 +710,9 @@ impl MachineState {
} }
}), }),
&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

View File

@@ -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();
let mut writer = wam.heap.reserve(96).unwrap();
writer.write_with(|section| {
// [1,2,3] // [1,2,3]
wam.heap.push(list_loc_as_cell!(1)); section.push_cell(list_loc_as_cell!(1));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
wam.heap.push(list_loc_as_cell!(3)); section.push_cell(list_loc_as_cell!(3));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
wam.heap.push(list_loc_as_cell!(5)); section.push_cell(list_loc_as_cell!(5));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3))); section.push_cell(fixnum_as_cell!(Fixnum::build_with(3)));
wam.heap.push(empty_list_as_cell!()); section.push_cell(empty_list_as_cell!());
// [1,2] // [1,2]
wam.heap.push(list_loc_as_cell!(8)); section.push_cell(list_loc_as_cell!(8));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
wam.heap.push(list_loc_as_cell!(10)); section.push_cell(list_loc_as_cell!(10));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
wam.heap.push(empty_list_as_cell!()); 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));
} }
} }

View File

@@ -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 { } else {
return false; unify!(self.machine_st, cell, lit);
}
}
(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 {
self.machine_st.write_literal_to_var(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

View File

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

View File

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

View File

@@ -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() {
@@ -1844,10 +1912,11 @@ impl MachineState {
(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) => { (ArenaHeaderTag::Dropped, _value) => {
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

View File

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

View File

@@ -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,
machine_st.heap.push(value_1);
machine_st.heap.push(value_2);
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 {
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;
} else {
machine_st.pdl.push(empty_list_as_cell!());
machine_st.pdl.push(pstr_iter1.focus);
}
}
continuable @ PStrCmpResult::FirstIterContinuable(iteratee)
| continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
if continuable.is_second_iter() {
std::mem::swap(&mut pstr_iter1, &mut pstr_iter2);
}
let mut chars_iter = PStrCharsIter {
iter: pstr_iter1,
item: Some(iteratee),
};
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) => { (HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s]) let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
.get_name_and_arity(); .get_name_and_arity();
if name == atom!(".") && arity == 2 { if name == atom!(".") && arity == 2 {
machine_st.pdl.push(pstr_iter2.heap[s+1]); machine_st.partial_string_to_pdl(pstr_loc, s+1);
machine_st.pdl.push(char_as_cell!(c));
focus = pstr_iter2.heap[s+2];
} else { } else {
machine_st.fail = true; machine_st.fail = true;
break 'outer;
} }
} }
(HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { (HeapCellValueTag::Lis, l) => {
unify_sequence(machine_st, chars_iter.item.unwrap(), focus); machine_st.partial_string_to_pdl(pstr_loc, l);
return; }
(HeapCellValueTag::PStrLoc, other_pstr_loc) => {
match machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc) {
PStrSegmentCmpResult::Continue(v1, v2) => {
machine_st.pdl.push(v1.offset_by(pstr_loc));
machine_st.pdl.push(v2.offset_by(other_pstr_loc));
}
_ => {
machine_st.fail = true;
}
} }
(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; 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.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() {

View File

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

View File

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

View File

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

View File

@@ -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,23 +265,31 @@ 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!("(")),
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, _ => None,
} }
}
} }
impl<'a, R: CharRead> Parser<'a, R> { impl<'a, R: CharRead> Parser<'a, R> {
@@ -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))
if self
.lexer
.machine_st
.arena
.f64_tbl
.get_entry(n)
.is_infinite() =>
{
return Err(ParserError::InfiniteFloat( return Err(ParserError::InfiniteFloat(
self.lexer.line_num, self.lexer.line_num,
self.lexer.col_num, self.lexer.col_num,
)); ));
} }
Token::Literal(Literal::Float(n)) => self.negate_number( Token::Literal(Literal::F64Offset(n)) => {
**n.as_ptr(), let n = self.lexer.machine_st.arena.f64_tbl.get_entry(n);
|n, _| -n,
|n, arena| Literal::from(float_alloc!(n, arena)),
),
Token::Literal(c) => {
let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c);
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);
} }

View File

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

View File

@@ -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();
put_complete_string(self.heap, &src, self.atom_tbl);
}
&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_cstr(src)
.map_err(CompilationError::FiniteMemoryInHeap)?;
let h = self.heap.len(); let new_h = self.heap.cell_len();
self.queue.push_back((1, h - 1)); self.push_cell(cell)?;
if !matches!(lvl, Level::Root) {
self.modify_head_of_queue(&term, new_h);
} else {
self.heap[h] = cell;
}
if let Level::Root = lvl {
continue; continue;
} }
TermRef::PartialString(lvl, _, src, _) => {
if let Level::Root = lvl {
self.push_stub_addr()?;
}
let cell = self
.heap
.allocate_pstr(src)
.map_err(CompilationError::FiniteMemoryInHeap)?;
let tail_h = self.heap.cell_len();
self.push_stub_addr()?;
if matches!(lvl, Level::Root) {
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() {

View File

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

View File

@@ -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,28 +648,42 @@ 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) Some(TermOrderCategory::Integer)
} }
Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint), (ArenaHeaderTag::Rational, _n) => {
None => match self.get_tag() { Some(TermOrderCategory::Integer)
HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => { }
_ => {
None
}
)
}
(HeapCellValueTag::F64Offset) => {
Some(TermOrderCategory::FloatingPoint)
}
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint) => {
Some(TermOrderCategory::Integer)
}
(HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
Some(TermOrderCategory::Variable) Some(TermOrderCategory::Variable)
} }
HeapCellValueTag::Char => Some(TermOrderCategory::Atom), (HeapCellValueTag::Atom, (_name, arity)) => {
HeapCellValueTag::Atom => Some(if cell_as_atom_cell!(self).get_arity() > 0 { Some(if 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) Some(TermOrderCategory::Compound)
} }
HeapCellValueTag::Str => { (HeapCellValueTag::Str, s) => {
let value = heap[self.get_value() as usize]; let arity = cell_as_atom_cell!(heap[s]).get_arity();
let arity = cell_as_atom_cell!(value).get_arity();
if arity == 0 { if arity == 0 {
Some(TermOrderCategory::Atom) Some(TermOrderCategory::Atom)
@@ -622,9 +691,10 @@ impl HeapCellValue {
Some(TermOrderCategory::Compound) Some(TermOrderCategory::Compound)
} }
} }
_ => None, _ => {
}, 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 {

View File

@@ -1,3 +1,4 @@
use crate::forms::GenContext;
use crate::parser::ast::*; use crate::parser::ast::*;
use bit_set::*; use bit_set::*;

11
tests-pl/issue2949.pl Normal file
View 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).

View File

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

View File

@@ -45,3 +45,4 @@
true. true.
true. true.
true. true.
true.

View 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])
```

View 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'
```

View 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'
```

View File

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

View File

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