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
+4 -3
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:
Generated
+7 -6
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",
+3 -1
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"
+1 -1
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.
+185 -237
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
+39 -8
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 } },)*
}; };
} }
} }
+1 -1
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,
+64 -406
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!() }
); );
+36 -19
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))
+178 -97
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())
}
}
+57 -88
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);
} }
} }
+8 -4
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>>(
+3 -3
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),
} }
} }
+67 -32
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
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!());
}
}
+557 -675
View File
File diff suppressed because it is too large Load Diff
+276 -161
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;
+43 -73
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);
+25 -34
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 });
} }
} }
} }
+3
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;
+14 -7
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)
). ).
+6 -7
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)
+22 -14
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
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).
+6 -6
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).
+2 -2
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)
+24 -20
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)))
); );
} }
+36 -16
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,
+55 -52
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,
); );
} }
+527 -176
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));
+14 -57
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());
} }
+9 -8
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));
} }
} }
+434 -244
View File
File diff suppressed because it is too large Load Diff
+760 -812
View File
File diff suppressed because it is too large Load Diff
+1091 -170
View File
File diff suppressed because it is too large Load Diff
+51 -78
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);
+90 -79
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)
} }
+96 -81
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,
+201 -203
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)]
+34 -51
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`.
+192 -158
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
+200 -121
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));
} }
} }
+86 -76
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
+27 -41
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))
} }
} }
} }
+41 -44
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();
} }
} }
} }
+89 -20
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));
} }
+1909 -1029
View File
File diff suppressed because it is too large Load Diff
+2 -1
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)
} }
+57 -303
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() {
+88 -230
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
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)
}
}
+141 -77
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();
} }
+50 -27
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))
}; };
} }
+63 -64
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);
} }
+6 -6
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 {
+74 -50
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() {
+12 -10
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)
} }
+195 -118
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 {
+1
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
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).
@@ -27,6 +27,7 @@ use_module(library(ordsets)).
use_module(library(os)). use_module(library(os)).
use_module(library(pairs)). use_module(library(pairs)).
use_module(library(pio)). use_module(library(pio)).
use_module(library(process)).
use_module(library(queues)). use_module(library(queues)).
use_module(library(random)). use_module(library(random)).
use_module(library(reif)). use_module(library(reif)).
@@ -45,3 +45,4 @@
true. true.
true. true.
true. true.
true.
+59
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])
```
+14
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'
```
+9
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'
```
+6
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]
+12 -1
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");
}
} }