]> Repositorios git - scryer-prolog.git/commitdiff
introduce bespoke Heap type for in-heap partial strings
authorMark Thom <[email protected]>
Tue, 14 May 2024 00:00:56 +0000 (18:00 -0600)
committerMark Thom <[email protected]>
Sat, 26 Oct 2024 22:28:09 +0000 (16:28 -0600)
57 files changed:
.github/workflows/ci.yml
benches/run_iai.rs
benches/setup.rs
build/instructions_template.rs
build/static_string_indexing.rs
src/allocator.rs
src/arena.rs
src/arithmetic.rs
src/atom_table.rs
src/codegen.rs
src/debray_allocator.rs
src/forms.rs
src/functor_macro.rs [new file with mode: 0644]
src/heap_iter.rs
src/heap_print.rs
src/indexing.rs
src/iterators.rs
src/lib.rs
src/lib/builtins.pl
src/loader.pl
src/machine/arithmetic_ops.rs
src/machine/attributed_variables.pl
src/machine/attributed_variables.rs
src/machine/compile.rs
src/machine/copier.rs
src/machine/cycle_detection.rs
src/machine/disjuncts.rs
src/machine/dispatch.rs
src/machine/gc.rs
src/machine/heap.rs
src/machine/lib_machine.rs
src/machine/load_state.rs
src/machine/loader.rs
src/machine/machine_errors.rs
src/machine/machine_indices.rs
src/machine/machine_state.rs
src/machine/machine_state_impl.rs
src/machine/mock_wam.rs
src/machine/mod.rs
src/machine/parsed_results.rs
src/machine/partial_string.rs
src/machine/preprocessor.rs
src/machine/streams.rs
src/machine/system_calls.rs
src/machine/term_stream.rs
src/machine/unify.rs
src/macros.rs
src/parser/ast.rs
src/parser/lexer.rs
src/parser/parser.rs
src/read.rs
src/repl_helper.rs
src/targets.rs
src/tests/call_with_inference_limit.pl
src/types.rs
tests-pl/invalid_decl11.pl
tests-pl/issue2588.pl

index 9ff0849c243827435fa8639ff73ee1afcb3f84f7..3fc66550dc4af06cab4589c3df4e497a7bab24fc 100644 (file)
@@ -49,7 +49,6 @@ jobs:
           # Cargo.toml rust-version
           - { os: ubuntu-22.04,   rust-version: "1.77",  target: 'x86_64-unknown-linux-gnu'}
           # rust versions
-          - { os: ubuntu-22.04, rust-version: "1.77", 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"} 
     defaults:
index c29645c2d0a4d5f13b0cc170d6f216e4511a0b27..4af8115a0e9490c09c515fa4069fc5e306fc3c72 100644 (file)
@@ -5,7 +5,7 @@ mod setup;
 mod iai {
     use iai_callgrind::{library_benchmark, library_benchmark_group, main};
 
-    use scryer_prolog::QueryResolution;
+    use scryer_prolog::machine::parsed_results::QueryResolution;
 
     use super::setup;
 
index 6087be446f6ed449a92e8c524b33e359f2d6b529..ec9339c590c4d6e3fd496d7afd7a6552885c8047 100644 (file)
@@ -1,7 +1,10 @@
 use std::{collections::BTreeMap, fs, path::Path};
 
 use maplit::btreemap;
-use scryer_prolog::{Machine, QueryResolution, Value};
+use scryer_prolog::machine::{
+    parsed_results::{QueryResolution, Value},
+    Machine,
+};
 
 pub fn prolog_benches() -> BTreeMap<&'static str, PrologBenchmark> {
     [
@@ -85,7 +88,7 @@ mod test {
     #[test]
     fn validate_benchmarks() {
         use super::prolog_benches;
-        use scryer_prolog::{QueryMatch, QueryResolution};
+        use scryer_prolog::machine::parsed_results::{QueryMatch, QueryResolution};
         use std::{fmt::Write, fs};
 
         struct BenchResult {
index 50114e294cb8d3cf7d8278377ad6be33739bf321..536bdc778ab726cf688e133e79afabe919781f44 100644 (file)
@@ -19,6 +19,7 @@ use to_syn_value_derive::ToDeriveInput;
  */
 
 use std::any::*;
+use std::rc::Rc;
 use std::str::FromStr;
 
 struct ArithmeticTerm;
@@ -28,6 +29,7 @@ struct Death;
 struct HeapCellValue;
 struct IndexingLine;
 struct Level;
+// struct Literal;
 struct NextOrFail;
 struct RegType;
 
@@ -620,7 +622,7 @@ enum InstructionTemplate {
     #[strum_discriminants(strum(props(Arity = "2", Name = "get_list")))]
     GetList(Level, RegType),
     #[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")))]
     GetStructure(Level, Atom, usize, RegType),
     #[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))]
@@ -643,7 +645,7 @@ enum InstructionTemplate {
     #[strum_discriminants(strum(props(Arity = "2", Name = "put_list")))]
     PutList(Level, RegType),
     #[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")))]
     PutStructure(Atom, usize, RegType),
     #[strum_discriminants(strum(props(Arity = "2", Name = "put_unsafe_value")))]
@@ -873,6 +875,7 @@ fn generate_instruction_preface() -> TokenStream {
         use crate::arithmetic::*;
         use crate::atom_table::*;
         use crate::forms::*;
+        use crate::functor_macro::*;
         use crate::machine::heap::*;
         use crate::machine::machine_errors::MachineStub;
         use crate::machine::machine_indices::CodeIndex;
@@ -883,6 +886,7 @@ fn generate_instruction_preface() -> TokenStream {
         use indexmap::IndexMap;
 
         use std::collections::VecDeque;
+        use std::rc::Rc;
 
         fn reg_type_into_functor(r: RegType) -> MachineStub {
             match r {
@@ -894,9 +898,9 @@ fn generate_instruction_preface() -> TokenStream {
         impl Level {
             fn into_functor(self) -> MachineStub {
                 match self {
-                    Level::Root => functor!(atom!("level"), [atom(atom!("root"))]),
-                    Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]),
-                    Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]),
+                    Level::Root => functor!(atom!("level"), [atom_as_cell((atom!("root")))]),
+                    Level::Shallow => functor!(atom!("level"), [atom_as_cell((atom!("shallow")))]),
+                    Level::Deep => functor!(atom!("level"), [atom_as_cell((atom!("deep")))]),
                 }
             }
         }
@@ -909,7 +913,7 @@ fn generate_instruction_preface() -> TokenStream {
                         functor!(atom!("intermediate"), [fixnum(i)])
                     }
                     ArithmeticTerm::Number(n) => {
-                        functor!(atom!("number"), [cell(HeapCellValue::from((n, arena)))])
+                        functor!(atom!("number"), [number(n, arena)])
                     }
                 }
             }
@@ -994,7 +998,7 @@ fn generate_instruction_preface() -> TokenStream {
                 IndexingCodePtr,
                 IndexingCodePtr,
             ),
-            SwitchOnConstant(IndexMap<Literal, IndexingCodePtr, FxBuildHasher>),
+            SwitchOnConstant(IndexMap<HeapCellValue, IndexingCodePtr, FxBuildHasher>),
             SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>),
         }
 
@@ -1014,7 +1018,7 @@ fn generate_instruction_preface() -> TokenStream {
                     IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]),
                     IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]),
                     IndexingCodePtr::Fail => {
-                        vec![atom_as_cell!(atom!("fail"))]
+                        functor!(atom!("fail"))
                     },
                 }
             }
@@ -1028,80 +1032,43 @@ fn generate_instruction_preface() -> TokenStream {
         }
 
         impl IndexingInstruction {
-            pub fn to_functor(&self, mut h: usize) -> MachineStub {
+            pub fn to_functor(&self) -> MachineStub {
                 match self {
                     &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
                         functor!(
                             atom!("switch_on_term"),
                             [
                                 fixnum(arg),
-                                indexing_code_ptr(h, vars),
-                                indexing_code_ptr(h, constants),
-                                indexing_code_ptr(h, lists),
-                                indexing_code_ptr(h, structures)
+                                indexing_code_ptr(vars),
+                                indexing_code_ptr(constants),
+                                indexing_code_ptr(lists),
+                                indexing_code_ptr(structures)
                             ]
                         )
                     }
                     IndexingInstruction::SwitchOnConstant(constants) => {
-                        let mut key_value_list_stub = vec![];
-                        let orig_h = h;
-
-                        h += 2; // skip the 2-cell "switch_on_constant" functor.
-
-                        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!(
-                            atom!("switch_on_constant"),
-                            [str(orig_h, 0)],
-                            [key_value_list_stub]
+                        variadic_functor(
+                            atom!("switch_on_constants"),
+                            1,
+                            constants.iter().map(|(c, ptr)| {
+                                functor!(
+                                    atom!(":"),
+                                    [cell((c.clone())), indexing_code_ptr((*ptr))]
+                                )
+                            }),
                         )
                     }
                     IndexingInstruction::SwitchOnStructure(structures) => {
-                        let mut key_value_list_stub = vec![];
-                        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!(
+                        variadic_functor(
                             atom!("switch_on_structure"),
-                            [str(orig_h, 0)],
-                            [key_value_list_stub]
+                            1,
+                            structures.iter().map(|((name, arity), ptr)| {
+                                functor!(
+                                    atom!(":"),
+                                    [functor((atom!("/")), [atom_as_cell(name), fixnum((*arity))]),
+                                     indexing_code_ptr((*ptr))]
+                                )
+                            }),
                         )
                     }
                 }
@@ -1131,18 +1098,16 @@ fn generate_instruction_preface() -> TokenStream {
         }
 
         fn arith_instr_unary_functor(
-            h: usize,
             name: Atom,
             arena: &mut Arena,
             at: &ArithmeticTerm,
             t: usize,
         ) -> MachineStub {
             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(
-            h: usize,
             name: Atom,
             arena: &mut Arena,
             at_1: &ArithmeticTerm,
@@ -1152,11 +1117,9 @@ fn generate_instruction_preface() -> TokenStream {
             let at_1_stub = at_1.into_functor(arena);
             let at_2_stub = at_2.into_functor(arena);
 
-            functor!(
-                name,
-                [str(h, 0), str(h, 1), fixnum(t)],
-                [at_1_stub, at_2_stub]
-            )
+            functor!(name, [functor(at_1_stub),
+                            functor(at_2_stub),
+                            fixnum(t)])
         }
 
         pub type Code = Vec<Instruction>;
@@ -1168,7 +1131,7 @@ fn generate_instruction_preface() -> TokenStream {
                 match *self {
                     Instruction::GetConstant(_, _, r) => vec![r],
                     Instruction::GetList(_, r) => vec![r],
-                    Instruction::GetPartialString(_, _, r, _) => vec![r],
+                    Instruction::GetPartialString(_, _, r) => vec![r],
                     Instruction::GetStructure(_, _, _, r) => vec![r],
                     Instruction::GetVariable(r, t) => vec![r, temp_v!(t)],
                     Instruction::GetValue(r, t) => vec![r, temp_v!(t)],
@@ -1176,7 +1139,7 @@ fn generate_instruction_preface() -> TokenStream {
                     Instruction::UnifyVariable(r) => vec![r],
                     Instruction::PutConstant(_, _, r) => vec![r],
                     Instruction::PutList(_, r) => vec![r],
-                    Instruction::PutPartialString(_, _, r, _) => vec![r],
+                    Instruction::PutPartialString(_, _, r) => vec![r],
                     Instruction::PutStructure(_, _, r) => vec![r],
                     Instruction::PutValue(r, t) => vec![r, temp_v!(t)],
                     Instruction::PutVariable(r, t) => vec![r, temp_v!(t)],
@@ -1240,7 +1203,6 @@ fn generate_instruction_preface() -> TokenStream {
 
             pub fn enqueue_functors(
                 &self,
-                mut h: usize,
                 arena: &mut Arena,
                 functors: &mut Vec<MachineStub>,
             ) {
@@ -1249,33 +1211,30 @@ fn generate_instruction_preface() -> TokenStream {
                         for indexing_instr in indexing_instrs {
                             match indexing_instr {
                                 IndexingLine::Indexing(indexing_instr) => {
-                                    let section = indexing_instr.to_functor(h);
-                                    h += section.len();
+                                    let section = indexing_instr.to_functor();
                                     functors.push(section);
                                 }
                                 IndexingLine::IndexedChoice(indexed_choice_instrs) => {
                                     for indexed_choice_instr in indexed_choice_instrs {
                                         let section = indexed_choice_instr.to_functor();
-                                        h += section.len();
                                         functors.push(section);
                                     }
                                 }
                                 IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
                                     for indexed_choice_instr in indexed_choice_instrs {
-                                        let section = functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]);
-
-                                        h += section.len();
+                                        let section = functor!(atom!("dynamic"),
+                                                               [fixnum((*indexed_choice_instr))]);
                                         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 {
                     &Instruction::InstallVerifyAttr => {
                         functor!(atom!("install_verify_attr"))
@@ -1288,25 +1247,23 @@ fn generate_instruction_preface() -> TokenStream {
                             (Death::Infinity, NextOrFail::Next(i)) => {
                                 functor!(
                                     atom!("dynamic_else"),
-                                    [fixnum(birth), atom(atom!("inf")), fixnum(i)]
+                                    [fixnum(birth), atom_as_cell((atom!("inf"))), fixnum(i)]
                                 )
                             }
                             (Death::Infinity, NextOrFail::Fail(i)) => {
-                                let next_functor = functor!(atom!("fail"), [fixnum(i)]);
-
                                 functor!(
                                     atom!("dynamic_else"),
-                                    [fixnum(birth), atom(atom!("inf")), str(h, 0)],
-                                    [next_functor]
+                                    [fixnum(birth),
+                                     atom_as_cell((atom!("inf"))),
+                                     functor((atom!("fail")), [fixnum(i)])]
                                 )
                             }
                             (Death::Finite(d), NextOrFail::Fail(i)) => {
-                                let next_functor = functor!(atom!("fail"), [fixnum(i)]);
-
                                 functor!(
                                     atom!("dynamic_else"),
-                                    [fixnum(birth), fixnum(d), str(h, 0)],
-                                    [next_functor]
+                                    [fixnum(birth),
+                                     fixnum(d),
+                                     functor((atom!("fail")), [fixnum(i)])]
                                 )
                             }
                             (Death::Finite(d), NextOrFail::Next(i)) => {
@@ -1319,25 +1276,23 @@ fn generate_instruction_preface() -> TokenStream {
                             (Death::Infinity, NextOrFail::Next(i)) => {
                                 functor!(
                                     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)) => {
-                                let next_functor = functor!(atom!("fail"), [fixnum(i)]);
-
                                 functor!(
                                     atom!("dynamic_internal_else"),
-                                    [fixnum(birth), atom(atom!("inf")), str(h, 0)],
-                                    [next_functor]
+                                    [fixnum(birth),
+                                     atom_as_cell((atom!("inf"))),
+                                     functor((atom!("fail")), [fixnum(i)])]
                                 )
                             }
                             (Death::Finite(d), NextOrFail::Fail(i)) => {
-                                let next_functor = functor!(atom!("fail"), [fixnum(i)]);
-
                                 functor!(
                                     atom!("dynamic_internal_else"),
-                                    [fixnum(birth), fixnum(d), str(h, 0)],
-                                    [next_functor]
+                                    [fixnum(birth),
+                                     fixnum(d),
+                                     functor((atom!("fail")), [fixnum(i)])]
                                 )
                             }
                             (Death::Finite(d), NextOrFail::Next(i)) => {
@@ -1365,157 +1320,154 @@ fn generate_instruction_preface() -> TokenStream {
                     }
                     &Instruction::Cut(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) => {
                         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) => {
                         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) => {
                         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) => {
                         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 => {
                         functor!(atom!("neck_cut"))
                     }
                     &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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        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) => {
-                        arith_instr_unary_functor(h, atom!("sign"), arena, at, t)
+                        arith_instr_unary_functor(atom!("sign"), arena, 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) => {
-                        arith_instr_unary_functor(h, atom!("sin"), arena, at, t)
+                        arith_instr_unary_functor(atom!("sin"), arena, 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) => {
-                        arith_instr_unary_functor(h, atom!("log"), arena, at, t)
+                        arith_instr_unary_functor(atom!("log"), arena, 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) => {
-                        arith_instr_unary_functor(h, atom!("acos"), arena, at, t)
+                        arith_instr_unary_functor(atom!("acos"), arena, 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) => {
-                        arith_instr_unary_functor(h, atom!("atan"), arena, at, t)
+                        arith_instr_unary_functor(atom!("atan"), arena, 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) => {
-                        arith_instr_unary_functor(h, atom!("abs"), arena, at, t)
+                        arith_instr_unary_functor(atom!("abs"), arena, 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) => {
-                        arith_instr_unary_functor(h, atom!("truncate"), arena, at, t)
+                        arith_instr_unary_functor(atom!("truncate"), arena, 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) => {
-                        arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t)
+                        arith_instr_unary_functor(atom!("ceiling"), arena, 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) => {
-                        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) => {
-                        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(
-                        h,
                         atom!("-"),
                         arena,
                         at,
                         t,
                     ),
                     &Instruction::Plus(ref at, t) => arith_instr_unary_functor(
-                        h,
                         atom!("+"),
                         arena,
                         at,
                         t,
                     ),
                     &Instruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor(
-                        h,
                         atom!("\\"),
                         arena,
                         at,
@@ -1531,16 +1483,16 @@ fn generate_instruction_preface() -> TokenStream {
                         functor!(atom!("allocate"), [fixnum(num_frames)])
                     }
                     &Instruction::CallNamed(arity, name, ..) => {
-                        functor!(atom!("call"), [atom(name), fixnum(arity)])
+                        functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)])
                     }
                     &Instruction::ExecuteNamed(arity, name, ..) => {
-                        functor!(atom!("execute"), [atom(name), fixnum(arity)])
+                        functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)])
                     }
                     &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, ..) => {
-                        functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
+                        functor!(atom!("execute_default"), [atom_as_cell(name), fixnum(arity)])
                     }
                     &Instruction::CallN(arity) => {
                         functor!(atom!("call_n"), [fixnum(arity)])
@@ -1583,7 +1535,7 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::CallSort |
                     &Instruction::CallGetNumber(_) => {
                         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 |
@@ -1609,7 +1561,7 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::ExecuteSort |
                     &Instruction::ExecuteGetNumber(_) => {
                         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 |
@@ -1635,7 +1587,7 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::DefaultCallSort |
                     &Instruction::DefaultCallGetNumber(_) => {
                         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 |
@@ -1661,7 +1613,7 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::DefaultExecuteSort |
                     &Instruction::DefaultExecuteGetNumber(_) => {
                         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::CallIsAtomic(r) |
@@ -1674,7 +1626,8 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::CallIsVar(r) => {
                         let (name, arity) = self.to_name_and_arity();
                         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::ExecuteIsAtomic(r) |
@@ -1687,7 +1640,8 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::ExecuteIsVar(r) => {
                         let (name, arity) = self.to_name_and_arity();
                         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 |
@@ -1917,14 +1871,14 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::CallEd25519VerifyRaw |
                     &Instruction::CallEd25519SeedToPublicKey => {
                         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")]
                     &Instruction::CallCryptoDataEncrypt |
                     &Instruction::CallCryptoDataDecrypt => {
                         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 |
@@ -2154,14 +2108,14 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::ExecuteEd25519VerifyRaw |
                     &Instruction::ExecuteEd25519SeedToPublicKey => {
                         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")]
                     &Instruction::ExecuteCryptoDataEncrypt |
                     &Instruction::ExecuteCryptoDataDecrypt => {
                         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 => {
@@ -2176,73 +2130,60 @@ fn generate_instruction_preface() -> TokenStream {
                     &Instruction::Proceed => {
                         functor!(atom!("proceed"))
                     }
-                    &Instruction::GetConstant(lvl, c, r) => {
+                    &Instruction::GetConstant(lvl, lit, r) => {
                         let lvl_stub = lvl.into_functor();
                         let rt_stub = reg_type_into_functor(r);
 
-                        functor!(
-                            atom!("get_constant"),
-                            [str(h, 0), cell(c), str(h, 1)],
-                            [lvl_stub, rt_stub]
-                        )
+                        functor!(atom!("get_constant"), [functor(lvl_stub),
+                                                         cell(lit),
+                                                         functor(rt_stub)])
                     }
                     &Instruction::GetList(lvl, r) => {
                         let lvl_stub = lvl.into_functor();
                         let rt_stub = reg_type_into_functor(r);
 
-                        functor!(
-                            atom!("get_list"),
-                            [str(h, 0), str(h, 1)],
-                            [lvl_stub, rt_stub]
-                        )
+                        functor!(atom!("get_list"), [functor(lvl_stub), functor(rt_stub)])
                     }
-                    &Instruction::GetPartialString(lvl, s, r, has_tail) => {
+                    &Instruction::GetPartialString(lvl, ref s, r) => {
                         let lvl_stub = lvl.into_functor();
                         let rt_stub = reg_type_into_functor(r);
 
-                        functor!(
-                            atom!("get_partial_string"),
-                            [
-                                str(h, 0),
-                                string(h, s),
-                                str(h, 1),
-                                boolean(has_tail)
-                            ],
-                            [lvl_stub, rt_stub]
-                        )
+                        functor!(atom!("get_partial_string"), [functor(lvl_stub),
+                                                               string((s.to_string())),
+                                                               functor(rt_stub)])
                     }
                     &Instruction::GetStructure(lvl, name, arity, r) => {
                         let lvl_stub = lvl.into_functor();
                         let rt_stub = reg_type_into_functor(r);
 
-                        functor!(
-                            atom!("get_structure"),
-                            [str(h, 0), atom(name), fixnum(arity), str(h, 1)],
-                            [lvl_stub, rt_stub]
-                        )
+                        functor!(atom!("get_structure"), [functor(lvl_stub),
+                                                          atom_as_cell(name),
+                                                          fixnum(arity),
+                                                          functor(rt_stub)])
                     }
                     &Instruction::GetValue(r, arg) => {
                         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) => {
                         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) => {
                         functor!(atom!("unify_constant"), [cell(c)])
                     }
                     &Instruction::UnifyLocalValue(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) => {
                         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) => {
                         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) => {
                         functor!(atom!("unify_void"), [fixnum(vars)])
@@ -2254,68 +2195,55 @@ fn generate_instruction_preface() -> TokenStream {
                         let lvl_stub = lvl.into_functor();
                         let rt_stub = reg_type_into_functor(r);
 
-                        functor!(
-                            atom!("put_constant"),
-                            [str(h, 0), cell(c), str(h, 1)],
-                            [lvl_stub, rt_stub]
-                        )
+                        functor!(atom!("put_constant"), [functor(rt_stub), cell(c), functor(lvl_stub)])
                     }
                     &Instruction::PutList(lvl, r) => {
                         let lvl_stub = lvl.into_functor();
                         let rt_stub = reg_type_into_functor(r);
 
-                        functor!(
-                            atom!("put_list"),
-                            [str(h, 0), str(h, 1)],
-                            [lvl_stub, rt_stub]
-                        )
+                        functor!(atom!("put_list"), [functor(lvl_stub), functor(rt_stub)])
                     }
-                    &Instruction::PutPartialString(lvl, s, r, has_tail) => {
+                    &Instruction::PutPartialString(lvl, ref s, r) => {
                         let lvl_stub = lvl.into_functor();
                         let rt_stub = reg_type_into_functor(r);
 
-                        functor!(
-                            atom!("put_partial_string"),
-                            [
-                                str(h, 0),
-                                string(h, s),
-                                str(h, 1),
-                                boolean(has_tail)
-                            ],
-                            [lvl_stub, rt_stub]
-                        )
+                        functor!(atom!("put_partial_string"), [functor(lvl_stub),
+                                                               string((s.to_string())),
+                                                               functor(rt_stub)])
                     }
                     &Instruction::PutStructure(name, arity, r) => {
                         let rt_stub = reg_type_into_functor(r);
 
-                        functor!(
-                            atom!("put_structure"),
-                            [atom(name), fixnum(arity), str(h, 0)],
-                            [rt_stub]
-                        )
+                        functor!(atom!("put_structure"), [atom_as_cell(name),
+                                                          fixnum(arity),
+                                                          functor(rt_stub)])
                     }
                     &Instruction::PutValue(r, arg) => {
                         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) => {
                         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) => {
                         functor!(atom!("set_constant"), [cell(c)])
                     }
                     &Instruction::SetLocalValue(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) => {
                         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) => {
                         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) => {
                         functor!(atom!("set_void"), [fixnum(vars)])
@@ -3200,14 +3128,6 @@ pub fn generate_instructions_rs() -> TokenStream {
                 )
             }
 
-            pub fn name(&self) -> Atom {
-                match self {
-                    #(
-                        #clause_type_name_arms,
-                    )*
-                }
-            }
-
             pub fn is_inlined(name: Atom, arity: usize) -> bool {
                 matches!((name, arity),
                     #(#is_inlined_arms)|*
index c3d1701c9f58be09748765e124d9719969732693..62e06f46c4acf33f20d345639742ed644603af26 100644 (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 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN {
+        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 {
     use quote::*;
 
@@ -149,11 +161,26 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
         visitor.visit_file(&syntax)
     }
 
-    let indices = (0..visitor.static_strs.len()).map(|i| (i << 3) as u64);
-    let indices_iter = indices.clone();
+    let mut static_str_keys = vec![];
+    let mut static_strs = vec![];
+    let mut static_str_indices = vec![];
+
+    let indices: Vec<u64> = visitor.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 = visitor.static_strs.len();
-    let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect();
+    let static_strs_len = static_strs.len(); // visitor.static_strs.len();
+    //let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect();
 
     quote! {
         static STRINGS: [&str; #static_strs_len] = [
@@ -163,11 +190,11 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
         ];
 
         macro_rules! atom {
-            #((#static_strs) => { Atom { index: #indices_iter } };)*
+            #((#static_str_keys) => { Atom { index: #indices } };)*
         }
 
         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 } },)*
         };
     }
 }
index 27def1d670d922ec2311ac1ff4509e351990deb9..735b013f53ddeac25545c016e2621650f508dda7 100644 (file)
@@ -2,6 +2,7 @@ use crate::parser::ast::*;
 
 use crate::forms::*;
 use crate::instructions::*;
+use crate::machine::heap::Heap;
 use crate::targets::*;
 
 pub(crate) trait Allocator {
@@ -45,7 +46,7 @@ pub(crate) trait Allocator {
 
     fn reset(&mut self);
     fn reset_arg(&mut self, arg_num: usize);
-    fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize);
+    fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize);
     fn reset_contents(&mut self);
 
     fn advance_arg(&mut self);
index e5aceb4dfac24c5cdce956cb4d55c3b4cfb33a4e..da5410f420e900111a78fcc07c6454c0a223228a 100644 (file)
@@ -897,7 +897,7 @@ mod tests {
     use crate::arena::*;
     use crate::atom_table::*;
     use crate::machine::mock_wam::*;
-    use crate::machine::partial_string::*;
+    use crate::types::*;
 
     use crate::parser::dashu::{Integer, Rational};
     use ordered_float::OrderedFloat;
@@ -980,7 +980,7 @@ mod tests {
 
         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);
 
         let untyped_arena_ptr = match cell.to_untyped_arena_ptr() {
@@ -1086,31 +1086,6 @@ mod tests {
             _ => { 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
 
         let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3));
@@ -1188,8 +1163,8 @@ mod tests {
         let char_cell = char_as_cell!(c);
 
         read_heap_cell!(char_cell,
-            (HeapCellValueTag::Char, c) => {
-                assert_eq!(c, 'c');
+            (HeapCellValueTag::Atom, (c, _arity)) => {
+                assert_eq!(&*c.as_str(), "c");
             }
             _ => { unreachable!() }
         );
@@ -1198,8 +1173,8 @@ mod tests {
         let cyrillic_char_cell = char_as_cell!(c);
 
         read_heap_cell!(cyrillic_char_cell,
-            (HeapCellValueTag::Char, c) => {
-                assert_eq!(c, 'Ћ');
+            (HeapCellValueTag::Atom, (c, _arity)) => {
+                assert_eq!(&*c.as_str(), "Ћ");
             }
             _ => { unreachable!() }
         );
index 67b4ac79fd8a2f74d674f46d163752c7ee2756bc..55770f888b350fd339afe54fe32a7aed61d6ab0f 100644 (file)
@@ -9,7 +9,6 @@ use crate::instructions::*;
 use crate::iterators::*;
 use crate::machine::disjuncts::*;
 use crate::machine::stack::Stack;
-use crate::parser::ast::FocusedHeap;
 use crate::targets::QueryInstruction;
 use crate::types::*;
 
@@ -55,103 +54,6 @@ impl Default for ArithmeticTerm {
 
 pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
 
-/*
-#[derive(Debug)]
-pub(crate) struct ArithInstructionIterator<'a> {
-    state_stack: Vec<TermIterState<'a>>,
-}
-
-impl<'a> ArithInstructionIterator<'a> {
-    fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
-        self.state_stack
-            .push(TermIterState::subterm_to_state(lvl, term));
-    }
-
-    fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
-        let state = match term {
-            Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
-            Term::Clause(cell, name, terms) => {
-                TermIterState::Clause(Level::Shallow, 0, cell, *name, terms)
-            }
-            Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
-            Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => {
-                return Err(ArithmeticError::NonEvaluableFunctor(
-                    Literal::Atom(atom!(".")),
-                    2,
-                ))
-            }
-            Term::Var(cell, var_ptr) => TermIterState::Var(Level::Shallow, cell, var_ptr.clone()),
-        };
-
-        Ok(ArithInstructionIterator {
-            state_stack: vec![state],
-        })
-    }
-}
-
-#[derive(Debug)]
-pub(crate) enum ArithTermRef<'a> {
-    Literal(&'a Literal),
-    Op(Atom, usize), // name, arity.
-    Var(Level, &'a Cell<VarReg>, VarPtr),
-}
-
-impl<'a> Iterator for ArithInstructionIterator<'a> {
-    type Item = Result<ArithTermRef<'a>, ArithmeticError>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        while let Some(iter_state) = self.state_stack.pop() {
-            match iter_state {
-                TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)),
-                TermIterState::Clause(lvl, child_num, cell, name, subterms) => {
-                    let arity = subterms.len();
-
-                    if child_num == arity {
-                        return Some(Ok(ArithTermRef::Op(name, arity)));
-                    } else {
-                        self.state_stack.push(TermIterState::Clause(
-                            lvl,
-                            child_num + 1,
-                            cell,
-                            name,
-                            subterms,
-                        ));
-
-                        self.push_subterm(lvl.child_level(), &subterms[child_num]);
-                    }
-                }
-                TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
-                TermIterState::Var(lvl, cell, var_ptr) => {
-                    return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr)));
-                }
-                _ => {
-                    return Some(Err(ArithmeticError::NonEvaluableFunctor(
-                        Literal::Atom(atom!(".")),
-                        2,
-                    )));
-                }
-            };
-        }
-
-        None
-    }
-}
-
-pub(crate) trait ArithmeticTermIter<'a> {
-    type Iter: Iterator<Item = Result<ArithTermRef<'a>, ArithmeticError>>;
-
-    fn iter(self) -> Result<Self::Iter, ArithmeticError>;
-}
-
-impl<'a> ArithmeticTermIter<'a> for &'a Term {
-    type Iter = ArithInstructionIterator<'a>;
-
-    fn iter(self) -> Result<Self::Iter, ArithmeticError> {
-        ArithInstructionIterator::from(self)
-    }
-}
-*/
-
 #[derive(Debug)]
 pub(crate) struct ArithmeticEvaluator<'a> {
     marker: &'a mut DebrayAllocator,
@@ -159,23 +61,45 @@ pub(crate) struct ArithmeticEvaluator<'a> {
     interm_c: usize,
 }
 
-fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: Literal) -> Result<(), ArithmeticError> {
-    match c {
-        Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(n))),
-        Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(n))),
-        Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))),
-        Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(n))),
-        Literal::Atom(name) if name == atom!("e") => interm.push(ArithmeticTerm::Number(
-            Number::Float(OrderedFloat(std::f64::consts::E)),
-        )),
-        Literal::Atom(name) if name == atom!("pi") => interm.push(ArithmeticTerm::Number(
-            Number::Float(OrderedFloat(std::f64::consts::PI)),
-        )),
-        Literal::Atom(name) if name == atom!("epsilon") => interm.push(ArithmeticTerm::Number(
-            Number::Float(OrderedFloat(f64::EPSILON)),
-        )),
-        _ => return Err(ArithmeticError::NonEvaluableFunctor(HeapCellValue::from(c), 0)),
-    }
+fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: HeapCellValue) -> Result<(), ArithmeticError> {
+    read_heap_cell!(c,
+        (HeapCellValueTag::Fixnum, n) => {
+            interm.push(ArithmeticTerm::Number(Number::Fixnum(n)))
+        }
+        (HeapCellValueTag::Cons, cons_ptr) => {
+            match_untyped_arena_ptr!(cons_ptr,
+                 (ArenaHeaderTag::Integer, n) => {
+                     interm.push(ArithmeticTerm::Number(Number::Integer(n)));
+                 }
+                 (ArenaHeaderTag::Rational, n) => {
+                     interm.push(ArithmeticTerm::Number(Number::Rational(n)));
+                 }
+                 _ => return Err(ArithmeticError::NonEvaluableFunctor(c, 0)),
+            );
+        }
+        (HeapCellValueTag::Atom, (name, arity)) => {
+            debug_assert_eq!(arity, 0);
+
+            match name {
+                atom!("pi") => interm.push(ArithmeticTerm::Number(
+                    Number::Float(OrderedFloat(std::f64::consts::PI)),
+                )),
+                atom!("epsilon") => interm.push(ArithmeticTerm::Number(
+                    Number::Float(OrderedFloat(std::f64::EPSILON)),
+                )),
+                atom!("e") => interm.push(ArithmeticTerm::Number(
+                    Number::Float(OrderedFloat(std::f64::consts::E)),
+                )),
+                _ => unreachable!(),
+            }
+        }
+        (HeapCellValueTag::F64, n) => {
+            interm.push(ArithmeticTerm::Number(Number::Float(*n)));
+        }
+        _ => {
+            return Err(ArithmeticError::NonEvaluableFunctor(c, 0));
+        }
+    );
 
     Ok(())
 }
@@ -313,7 +237,7 @@ impl<'a> ArithmeticEvaluator<'a> {
 
     pub(crate) fn compile_is(
         &mut self,
-        src: &mut FocusedHeap,
+        src: &mut FocusedHeapRefMut,
         term_loc: usize,
         context: GenContext,
         arg: usize,
@@ -360,16 +284,13 @@ impl<'a> ArithmeticEvaluator<'a> {
                 }
                 (HeapCellValueTag::Atom, (name, arity)) => {
                     if arity == 0 {
-                        push_literal(&mut self.interm, Literal::Atom(name))?;
+                        push_literal(&mut self.interm, atom_as_cell!(name))?;
                     } else {
                         code.push_back(self.instr_from_clause(name, arity)?);
                     }
                 }
                 _ => {
-                    match Literal::try_from(term) {
-                        Ok(lit) => push_literal(&mut self.interm, lit)?,
-                        _ => return Err(ArithmeticError::NonEvaluableFunctor(term, 0)),
-                    }
+                    push_literal(&mut self.interm, term)?;
                 }
             );
         }
index 60b0b3c71ed3b3a44dc4d39b028d195429a39be7..7c23349d3adafd73e0210681c0468780c27acf47 100644 (file)
@@ -23,15 +23,117 @@ use indexmap::IndexSet;
 
 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]
+    pub fn new_static(index: u64) -> Self {
+        // upper 23 bits of index must be 0
+        debug_assert!(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]
+    pub 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 {
+        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)]
 pub struct Atom {
     pub index: u64,
 }
 
-const_assert!(mem::size_of::<Atom>() == 8);
-
 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!("[]");
+
 impl<'a> From<&'a Atom> for Atom {
     #[inline]
     fn from(atom: &'a Atom) -> Self {
@@ -39,17 +141,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 {
     fn equivalent(&self, key: &Atom) -> bool {
         &*key.as_str() == self
@@ -120,24 +211,25 @@ impl Hash for Atom {
     #[inline]
     fn hash<H: Hasher>(&self, hasher: &mut H) {
         self.as_str().hash(hasher)
-        // hasher.write_usize(self.index)
     }
 }
 
 pub enum AtomString<'a> {
     Static(&'a str),
+    Inlined([u8;8]),
     Dynamic(AtomTableRef<str>),
 }
 
-impl AtomString<'_> {
-    pub fn map<F>(self, f: F) -> Self
-    where
-        for<'a> F: FnOnce(&'a str) -> &'a str,
-    {
-        match self {
-            Self::Static(reference) => Self::Static(f(reference)),
-            Self::Dynamic(guard) => Self::Dynamic(AtomTableRef::map(guard, f)),
-        }
+fn inlined_to_str<'a>(bytes: &'a [u8;8]) -> &'a str {
+    // allow the '\0\' atom to be represented as the 0-valued inlined atom
+    let slice_len = if bytes[0] == 0 {
+        1
+    } else {
+        bytes.iter().position(|&b| b == 0u8).unwrap_or(INLINED_ATOM_MAX_LEN)
+    };
+
+    unsafe {
+        str::from_utf8_unchecked(&bytes[..slice_len])
     }
 }
 
@@ -158,6 +250,7 @@ impl std::ops::Deref for AtomString<'_> {
     fn deref(&self) -> &Self::Target {
         match self {
             Self::Static(reference) => reference,
+            Self::Inlined(inlined) => inlined_to_str(&inlined),
             Self::Dynamic(guard) => guard.deref(),
         }
     }
@@ -175,13 +268,32 @@ impl rustyline::completion::Candidate for AtomString<'_> {
 }
 
 impl Atom {
+    #[inline]
+    fn new_inlined(string: &str) -> Self {
+        AtomCell::new_inlined(string, 0).get_name()
+    }
+
     #[inline(always)]
-    pub fn is_static(self) -> bool {
-        (self.index as usize) < STRINGS.len() << 3
+    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)]
-    pub fn as_ptr(self) -> Option<AtomTableRef<AtomData>> {
+    fn as_ptr(self) -> Option<AtomTableRef<AtomData>> {
         if self.is_static() {
             None
         } else {
@@ -192,7 +304,7 @@ impl Atom {
                 let ptr = buf
                     .block
                     .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
                 let atom_data = &*(std::ptr::slice_from_raw_parts(ptr, 0) as *const AtomData);
                 let len = atom_data.header.len();
@@ -208,8 +320,11 @@ impl Atom {
 
     #[inline(always)]
     pub fn len(self) -> usize {
-        if self.is_static() {
-            STRINGS[(self.index >> 3) as usize].len()
+        if let Some(s) = self.inlined_str() {
+            s.len()
+        } else if self.is_static() {
+            let index = self.flat_index();
+            STRINGS[index as usize].len()
         } else {
             let len: u64 = self.as_ptr().unwrap().header.len();
             len as usize
@@ -220,11 +335,6 @@ impl Atom {
         self.len() == 0
     }
 
-    #[inline(always)]
-    pub fn flat_index(self) -> u64 {
-        self.index >> 3
-    }
-
     pub fn as_char(self) -> Option<char> {
         let s = self.as_str();
         let mut it = s.chars();
@@ -239,14 +349,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]
     pub fn as_str(&self) -> AtomString<'static> {
-        if self.is_static() {
-            AtomString::Static(STRINGS[(self.index >> 3) as usize])
+        if let Some(s) = self.inlined_str() {
+            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() {
             AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| &ptr.data))
         } else {
-            AtomString::Static(STRINGS[(self.index >> 3) as usize])
+            AtomString::Static(STRINGS[(self.index >> 1) as usize])
         }
     }
 
@@ -342,6 +464,10 @@ impl AtomTable {
     }
 
     pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom {
+        if 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN {
+            return Atom::new_inlined(string);
+        }
+
         loop {
             let mut block_epoch = atom_table.inner.read();
             let mut table_epoch = block_epoch.table.read();
@@ -390,9 +516,14 @@ impl AtomTable {
 
                 write_to_ptr(string, len_ptr);
 
-                let atom = Atom {
-                    index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64,
-                };
+                let atom = AtomCell::new()
+                    .with_name((STRINGS.len() + len_ptr as usize - 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();
                 table.insert(atom);
@@ -410,18 +541,21 @@ impl AtomTable {
 unsafe impl Send for AtomTable {}
 unsafe impl Sync for AtomTable {}
 
+/*
 #[bitfield]
 #[repr(u64)]
 #[derive(Copy, Clone, Debug)]
 pub struct AtomCell {
-    name: B46,
+    name: B48,
     arity: B10,
     #[allow(unused)]
     f: bool,
     #[allow(unused)]
     m: bool,
     #[allow(unused)]
-    tag: B6,
+    inlined: bool,
+    #[allow(unused)]
+    tag: B3,
 }
 
 impl AtomCell {
@@ -463,3 +597,4 @@ impl AtomCell {
         (Atom::from((self.get_index() as u64) << 3), self.get_arity())
     }
 }
+*/
index 06d8c8e4c09c74d8fca9372f6e1ac21394e7be21..4b27e4487862f1048544798d1f238a14c5fe9443 100644 (file)
@@ -7,7 +7,7 @@ use crate::forms::*;
 use crate::indexing::*;
 use crate::instructions::*;
 use crate::iterators::*;
-use crate::machine::heap::{heap_bound_deref, heap_bound_store};
+use crate::machine::heap::*;
 use crate::parser::ast::*;
 use crate::targets::*;
 use crate::types::*;
@@ -16,7 +16,6 @@ use crate::variable_records::*;
 use crate::machine::disjuncts::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::CodeIndex;
-use crate::machine::machine_state::pstr_loc_and_offset;
 use crate::machine::stack::Stack;
 
 use fxhash::FxBuildHasher;
@@ -24,6 +23,7 @@ use indexmap::IndexMap;
 use indexmap::IndexSet;
 
 use std::collections::VecDeque;
+use std::rc::Rc;
 
 #[derive(Debug)]
 pub struct BranchCodeStack {
@@ -274,33 +274,12 @@ impl CodeGenSettings {
 }
 
 #[derive(Debug)]
-pub(crate) struct CodeGenerator<'a> {
-    pub(crate) atom_tbl: &'a AtomTable,
+pub(crate) struct CodeGenerator {
     marker: DebrayAllocator,
     settings: CodeGenSettings,
     pub(crate) skeleton: PredicateSkeleton,
 }
 
-fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) {
-    let subterm = heap[subterm_loc];
-
-    if subterm.is_ref() {
-        let subterm = heap_bound_deref(heap, subterm);
-        let subterm_loc = subterm.get_value() as usize;
-        let subterm = heap_bound_store(heap, subterm);
-
-        let subterm_loc = if subterm.is_ref() {
-            subterm.get_value() as usize
-        } else {
-            subterm_loc
-        };
-
-        (subterm_loc, subterm)
-    } else {
-        (subterm_loc, subterm)
-    }
-}
-
 impl DebrayAllocator {
     pub(crate) fn mark_non_callable(
         &mut self,
@@ -337,7 +316,7 @@ trait AddToFreeList<'a, Target: CompilationTarget<'a>> {
     fn add_subterm_to_free_list(&mut self, r: RegType);
 }
 
-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) {
         self.marker.add_reg_to_free_list(r);
     }
@@ -345,7 +324,7 @@ impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> {
     fn add_subterm_to_free_list(&mut self, _r: RegType) {}
 }
 
-impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> {
+impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator {
     #[inline(always)]
     fn add_term_to_free_list(&mut self, _r: RegType) {}
 
@@ -357,19 +336,19 @@ impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> {
 
 fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>(
     index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
-    heap: &[HeapCellValue],
+    heap: &Heap,
     arity: usize,
     heap_loc: usize,
 ) -> Option<Instruction> {
     match fetch_index_ptr(heap, arity, heap_loc) {
         Some(index_ptr) => {
-            let subterm = Literal::CodeIndex(index_ptr);
+            let subterm = HeapCellValue::from(index_ptr);
             return Some(Target::constant_subterm(subterm));
         }
         None => {
             // if Level::Shallow == lvl {
                 if let Some(index_ptr) = index_ptrs.get(&heap_loc) {
-                    let subterm = Literal::CodeIndex(*index_ptr);
+                    let subterm = HeapCellValue::from(*index_ptr);
                     return Some(Target::constant_subterm(subterm));
                 }
             // }
@@ -379,10 +358,9 @@ fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>(
     None
 }
 
-impl<'b> CodeGenerator<'b> {
-    pub(crate) fn new(atom_tbl: &'b AtomTable, settings: CodeGenSettings) -> Self {
+impl CodeGenerator {
+    pub(crate) fn new(settings: CodeGenSettings) -> Self {
         CodeGenerator {
-            atom_tbl,
             marker: DebrayAllocator::new(),
             settings,
             skeleton: PredicateSkeleton::new(),
@@ -445,33 +423,26 @@ impl<'b> CodeGenerator<'b> {
 
                 None
             }
-            (HeapCellValueTag::Atom, (name, arity)) => {
-                debug_assert_eq!(arity, 0);
-
+            (HeapCellValueTag::Atom, (name, _arity)) => {
                 if index_ptrs.contains_key(&heap_loc) {
                     let r = self.marker.mark_non_var::<Target>(Level::Deep, heap_loc, context, target);
                     target.push_back(Target::clause_arg_to_instr(r));
                     return Some(r);
                 } else {
-                    target.push_back(Target::constant_subterm(Literal::Atom(name)));
+                    target.push_back(Target::constant_subterm(atom_as_cell!(name)));
                 }
 
                 None
             }
             (HeapCellValueTag::Str
              | HeapCellValueTag::Lis
-             | HeapCellValueTag::PStrLoc
-             | HeapCellValueTag::CStr) => {
+             | HeapCellValueTag::PStrLoc) => {
                 let r = self.marker.mark_non_var::<Target>(Level::Deep, heap_loc, context, target);
                 target.push_back(Target::clause_arg_to_instr(r));
                 return Some(r);
             }
             _ => {
-                match Literal::try_from(subterm) {
-                    Ok(lit) => target.push_back(Target::constant_subterm(lit)),
-                    Err(_)  => unreachable!(),
-                }
-
+                target.push_back(Target::constant_subterm(subterm));
                 None
             }
         )
@@ -486,7 +457,7 @@ impl<'b> CodeGenerator<'b> {
     where
         Target: crate::targets::CompilationTarget<'a>,
         Iter: TermIterator,
-        CodeGenerator<'b>: AddToFreeList<'a, Target>,
+        CodeGenerator: AddToFreeList<'a, Target>,
     {
         let mut target = CodeDeque::new();
         let chunk_num = context.chunk_num();
@@ -530,13 +501,13 @@ impl<'b> CodeGenerator<'b> {
                             target.push_back(instr);
                         } else if lvl == Level::Shallow {
                             let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
-                            target.push_back(Target::to_constant(lvl, Literal::Atom(name), r));
+                            target.push_back(Target::to_constant(lvl, atom_as_cell!(name), r));
                         }
                     } else {
                         let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
                         target.push_back(Target::to_structure(lvl, name, arity, r));
 
-                        <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
+                        <CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
                             self,
                             r,
                         );
@@ -557,7 +528,7 @@ impl<'b> CodeGenerator<'b> {
 
                         for r_opt in free_list_regs {
                             if let Some(r) = r_opt {
-                                <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+                                <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
                                     self, r,
                                 );
                             }
@@ -572,7 +543,7 @@ impl<'b> CodeGenerator<'b> {
 
                     target.push_back(Target::to_list(lvl, r));
 
-                    <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
+                    <CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
                         self,
                         r,
                     );
@@ -597,62 +568,36 @@ impl<'b> CodeGenerator<'b> {
                     );
 
                     if let Some(r) = head_r_opt {
-                        <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+                        <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
                             self, r,
                         );
                     }
 
                     if let Some(r) = tail_r_opt {
-                        <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+                        <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
                             self, r,
                         );
                     }
                 }
-                (HeapCellValueTag::CStr, cstr_atom) => {
-                    let heap_loc = iter.focus().value() as usize;
-                    let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
-
-                    target.push_back(Target::to_pstr(lvl, cstr_atom, r, false));
-                }
-                (HeapCellValueTag::PStr, pstr_atom) => {
+                (HeapCellValueTag::PStrLoc, pstr_loc) => {
                     let heap_loc = iter.focus().value() as usize;
                     let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
                     let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
+                    let (pstr_str, tail_loc) = iter.scan_slice_to_str(pstr_loc);
 
-                    target.push_back(Target::to_pstr(lvl, pstr_atom, r, true));
-
-                    let (tail_loc, tail) = subterm_index(iter.deref(), heap_loc + 1);
-                    self.subterm_to_instr::<Target>(
-                        tail, tail_loc, context, index_ptrs, &mut target,
-                    );
-                }
-                (HeapCellValueTag::PStrOffset, l) => {
-                    let heap_loc = iter.focus().value() as usize;
-                    let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
-
-                    let (index, n) = pstr_loc_and_offset(&iter, l);
-                    let n = n.get_num() as usize;
-
-                    let pstr_atom = cell_as_atom!(iter[index]);
-                    let pstr_offset_atom = if n == 0 {
-                        pstr_atom
-                    } else {
-                        AtomTable::build_with(self.atom_tbl, &pstr_atom.as_str()[n ..])
-                    };
-
-                    let (tail_loc, tail) = subterm_index(iter.deref(), l+1);
-                    target.push_back(Target::to_pstr(lvl, pstr_offset_atom, r, true));
+                    target.push_back(Target::to_pstr(lvl, Rc::new(pstr_str.to_owned()), r));
 
+                    let (tail_loc, tail) = subterm_index(iter.deref(), tail_loc);
                     self.subterm_to_instr::<Target>(
                         tail, tail_loc, context, index_ptrs, &mut target,
                     );
                 }
                 _ if lvl == Level::Shallow => {
-                    if let Ok(lit) = Literal::try_from(term) {
+                    if term.is_constant() {
                         let heap_loc = iter.focus().value() as usize;
                         let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
                         let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
-                        target.push_back(Target::to_constant(lvl, lit, r));
+                        target.push_back(Target::to_constant(lvl, term, r));
                     }
                 }
                 _ => {}
@@ -688,7 +633,7 @@ impl<'b> CodeGenerator<'b> {
     fn compile_inlined(
         &mut self,
         ct: &InlinedClauseType,
-        terms: &mut FocusedHeap,
+        terms: &mut FocusedHeapRefMut,
         term_loc: usize,
         context: GenContext,
         code: &mut CodeDeque,
@@ -763,9 +708,6 @@ impl<'b> CodeGenerator<'b> {
                                 instr!("$fail")
                             }
                         }
-                        (HeapCellValueTag::Char) => {
-                            instr!("$succeed")
-                        }
                         _ => {
                             instr!("$fail")
                         }
@@ -780,7 +722,6 @@ impl<'b> CodeGenerator<'b> {
                 } else {
                    read_heap_cell!(first_arg,
                        (HeapCellValueTag::Fixnum |
-                        HeapCellValueTag::Char |
                         HeapCellValueTag::F64) => {
                            instr!("$succeed")
                        }
@@ -803,12 +744,11 @@ impl<'b> CodeGenerator<'b> {
                        }
                        (HeapCellValueTag::Lis
                         | HeapCellValueTag::Str
-                        | HeapCellValueTag::PStrLoc
-                        | HeapCellValueTag::CStr) => {
+                        | HeapCellValueTag::PStrLoc) => {
                            instr!("$fail")
                        }
                        _ => {
-                           if Literal::try_from(first_arg).is_ok() {
+                           if first_arg.is_constant() {
                                instr!("$succeed")
                            } else {
                                instr!("$fail")
@@ -833,8 +773,7 @@ impl<'b> CodeGenerator<'b> {
                         }
                         (HeapCellValueTag::Lis
                          | HeapCellValueTag::Str
-                         | HeapCellValueTag::PStrLoc
-                         | HeapCellValueTag::CStr) => {
+                         | HeapCellValueTag::PStrLoc) => {
                             instr!("$succeed")
                         }
                         _ => {
@@ -889,12 +828,10 @@ impl<'b> CodeGenerator<'b> {
                 self.marker.reset_arg(1);
                 if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("number", r)
+                } else if Number::try_from(first_arg).is_ok() {
+                    instr!("$succeed")
                 } else {
-                    if Number::try_from(first_arg).is_ok() {
-                        instr!("$succeed")
-                    } else {
-                        instr!("$fail")
-                    }
+                    instr!("$fail")
                 }
             }
             InlinedClauseType::IsNonVar(..) => {
@@ -902,12 +839,10 @@ impl<'b> CodeGenerator<'b> {
 
                 if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("nonvar", r)
+                } else if first_arg.is_var() {
+                    instr!("$fail")
                 } else {
-                    if first_arg.is_var() {
-                        instr!("$fail")
-                    } else {
-                        instr!("$succeed")
-                    }
+                    instr!("$succeed")
                 }
             }
             InlinedClauseType::IsInteger(..) => {
@@ -931,12 +866,10 @@ impl<'b> CodeGenerator<'b> {
 
                 if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("var", r)
+                } else if first_arg.is_var() {
+                    instr!("$succeed")
                 } else {
-                    if first_arg.is_var() {
-                        instr!("$succeed")
-                    } else {
-                        instr!("$fail")
-                    }
+                    instr!("$fail")
                 }
             },
         };
@@ -948,7 +881,7 @@ impl<'b> CodeGenerator<'b> {
 
     fn compile_arith_expr(
         &mut self,
-        terms: &mut FocusedHeap,
+        terms: &mut FocusedHeapRefMut,
         term_loc: usize,
         target_int: usize,
         context: GenContext,
@@ -960,7 +893,7 @@ impl<'b> CodeGenerator<'b> {
 
     fn compile_is_call(
         &mut self,
-        terms: &mut FocusedHeap,
+        terms: &mut FocusedHeapRefMut,
         term_loc: usize,
         code: &mut CodeDeque,
         context: GenContext,
@@ -977,12 +910,10 @@ impl<'b> CodeGenerator<'b> {
 
         self.marker.reset_arg(2);
 
-        let var = {
-            let var_cell = terms.heap[term_loc + 1];
-            let terms = FocusedHeapRefMut::from_cell(&mut terms.heap, var_cell);
-
-            terms.deref_loc(term_loc + 1)
-        };
+        let var = heap_bound_store(
+            terms.heap,
+            heap_bound_deref(terms.heap, heap_loc_as_cell!(term_loc + 1)),
+        );
 
         let at = read_heap_cell!(var,
             (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
@@ -1029,7 +960,7 @@ impl<'b> CodeGenerator<'b> {
 
     fn compile_seq(
         &mut self,
-        focused_heap: &mut FocusedHeap,
+        mut focused_heap: FocusedHeapRefMut,
         clauses: &ChunkedTermVec,
         code: &mut CodeDeque,
     ) -> Result<(), CompilationError> {
@@ -1108,7 +1039,7 @@ impl<'b> CodeGenerator<'b> {
                                     ..
                                 },
                             ) => self.compile_is_call(
-                                focused_heap,
+                                &mut focused_heap,
                                 clause.term_loc(),
                                 branch_code_stack.code(code),
                                 context,
@@ -1121,7 +1052,7 @@ impl<'b> CodeGenerator<'b> {
                                 },
                             ) => self.compile_inlined(
                                 ct,
-                                focused_heap,
+                                &mut focused_heap,
                                 clause.term_loc(),
                                 context,
                                 branch_code_stack.code(code),
@@ -1132,15 +1063,13 @@ impl<'b> CodeGenerator<'b> {
                             &QueryTerm::Succeed => {
                                 let code = branch_code_stack.code(code);
 
-                                if self.marker.in_tail_position {
-                                    if self.marker.var_data.allocates {
-                                        code.push_back(instr!("deallocate"));
-                                    }
+                                if self.marker.in_tail_position && self.marker.var_data.allocates {
+                                    code.push_back(instr!("deallocate"));
                                 }
 
                                 code.push_back(
                                     if self.marker.in_tail_position {
-                                        instr!("$succeed").to_execute()
+                                        instr!("$succeed").into_execute()
                                     } else {
                                         instr!("$succeed")
                                     },
@@ -1148,7 +1077,7 @@ impl<'b> CodeGenerator<'b> {
                             }
                             QueryTerm::Clause(clause) => {
                                 self.compile_query_line(
-                                    focused_heap,
+                                    &mut focused_heap,
                                     clause,
                                     context,
                                     branch_code_stack.code(code),
@@ -1208,24 +1137,23 @@ impl<'b> CodeGenerator<'b> {
 
     pub(crate) fn compile_rule(
         &mut self,
+        heap: &mut Heap,
         rule: &mut Rule,
         var_data: VarData,
     ) -> Result<Code, CompilationError> {
-        let Rule {
-            ref mut term,
-            clauses,
-        } = rule;
+        let Rule { term_loc, clauses } = rule;
+
         self.marker.var_data = var_data;
 
+        let term = FocusedHeapRefMut { heap, focus: *term_loc };
         let mut code = VecDeque::new();
+
         let head_loc = term.nth_arg(term.focus, 1).unwrap();
 
-        self.marker.reset_at_head(term, head_loc);
+        self.marker.reset_at_head(term.heap, head_loc);
 
         let mut stack = Stack::uninitialized();
-        let iter = fact_iterator::<true>(
-            &mut term.heap, &mut stack, head_loc,
-        );
+        let iter = fact_iterator::<true>(term.heap, &mut stack, head_loc);
 
         let fact = self.compile_target::<FactInstruction, _>(
             iter,
@@ -1247,20 +1175,18 @@ impl<'b> CodeGenerator<'b> {
 
     pub(crate) fn compile_fact(
         &mut self,
+        heap: &mut Heap,
         fact: &mut Fact,
         var_data: VarData,
     ) -> Result<Code, CompilationError> {
         let mut code = Vec::new();
 
-        let fact_focus = fact.term.focus;
         let mut stack = Stack::uninitialized();
 
         self.marker.var_data = var_data;
-        self.marker.reset_at_head(&mut fact.term, fact_focus);
+        self.marker.reset_at_head(heap, fact.term_loc);
 
-        let iter = fact_iterator::<true>(
-            &mut fact.term.heap, &mut stack, fact_focus,
-        );
+        let iter = fact_iterator::<true>(heap, &mut stack, fact.term_loc);
 
         let compiled_fact = self.compile_target::<FactInstruction, _>(
             iter,
@@ -1280,7 +1206,7 @@ impl<'b> CodeGenerator<'b> {
 
     fn compile_query_line(
         &mut self,
-        term: &mut FocusedHeap,
+        term: &mut FocusedHeapRefMut,
         clause: &QueryClause,
         context: GenContext,
         code: &mut CodeDeque,
@@ -1300,15 +1226,16 @@ impl<'b> CodeGenerator<'b> {
         self.add_call(code, clause.ct.to_instr(), clause.call_policy);
     }
 
-    fn split_predicate(clauses: &[PredicateClause]) -> Vec<ClauseSpan> {
+    fn split_predicate(heap: &mut Heap, clauses: &[PredicateClause]) -> Vec<ClauseSpan> {
         let mut subseqs = Vec::new();
         let mut left = 0;
         let mut optimal_index = 0;
 
         'outer: for (right, clause) in clauses.iter().enumerate() {
-            if let Some(args) = clause.args() {
-                for (instantiated_arg_index, arg) in args.iter().cloned().enumerate() {
-                    let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg));
+            if let Some(args) = clause.args(heap) {
+                for (instantiated_arg_index, arg_idx) in args.enumerate() {
+                    let arg = heap[arg_idx];
+                    let arg = heap_bound_store(heap, heap_bound_deref(heap, arg));
 
                     if !arg.is_var() {
                         if optimal_index != instantiated_arg_index {
@@ -1364,6 +1291,7 @@ impl<'b> CodeGenerator<'b> {
 
     fn compile_pred_subseq<I: Indexer>(
         &mut self,
+        heap: &mut Heap,
         clauses: &mut [PredicateClause],
         optimal_index: usize,
     ) -> Result<Code, CompilationError> {
@@ -1382,11 +1310,11 @@ impl<'b> CodeGenerator<'b> {
             let clause_code = match clause {
                 PredicateClause::Fact(fact, var_data) => {
                     let var_data = std::mem::take(var_data);
-                    self.compile_fact(fact, var_data)?
+                    self.compile_fact(heap, fact, var_data)?
                 }
                 PredicateClause::Rule(rule, var_data) => {
                     let var_data = std::mem::take(var_data);
-                    self.compile_rule(rule, var_data)?
+                    self.compile_rule(heap, rule, var_data)?
                 }
             };
 
@@ -1414,19 +1342,19 @@ impl<'b> CodeGenerator<'b> {
                 skip_stub_try_me_else = !self.settings.is_dynamic();
             }
 
-            let arg = clause.args().and_then(|args| args.get(optimal_index));
+            let arg = clause.args(heap)
+                .map(|r| heap[r.start() + optimal_index]);
 
-            if let Some(arg) = arg.cloned() {
+            if let Some(arg) = arg {
                 let index = code.len();
 
                 if clauses_len > 1 || self.settings.is_extensible {
-                    let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg));
+                    let arg = heap_bound_store(heap, heap_bound_deref(heap, arg));
                     code_offsets.index_term(
-                        clause.heap(),
+                        heap,
                         arg,
                         index,
                         &mut clause_index_info,
-                        self.atom_tbl,
                     );
                 }
             }
@@ -1457,11 +1385,12 @@ impl<'b> CodeGenerator<'b> {
 
     pub(crate) fn compile_predicate(
         &mut self,
+        heap: &mut Heap,
         mut clauses: Vec<PredicateClause>,
     ) -> Result<Code, CompilationError> {
         let mut code = Code::new();
 
-        let split_pred = Self::split_predicate(&clauses);
+        let split_pred = Self::split_predicate(heap, &clauses);
         let multi_seq = split_pred.len() > 1;
 
         for ClauseSpan {
@@ -1473,11 +1402,13 @@ impl<'b> CodeGenerator<'b> {
             let skel_lower_bound = self.skeleton.clauses.len();
             let code_segment = if self.settings.is_dynamic() {
                 self.compile_pred_subseq::<DynamicCodeIndices>(
+                    heap,
                     &mut clauses[left..right],
                     instantiated_arg_index,
                 )?
             } else {
                 self.compile_pred_subseq::<StaticCodeIndices>(
+                    heap,
                     &mut clauses[left..right],
                     instantiated_arg_index,
                 )?
index 4577b1e6268a76670a9150d38c77a1cad3dac8da..d1d01aa8ae95aab876e59339c998718785276168 100644 (file)
@@ -4,7 +4,7 @@ use crate::codegen::SubsumedBranchHits;
 use crate::forms::{GenContext, Level};
 use crate::instructions::*;
 use crate::machine::disjuncts::*;
-use crate::machine::heap::{heap_bound_deref, heap_bound_store};
+use crate::machine::heap::*;
 use crate::parser::ast::*;
 use crate::targets::*;
 use crate::types::*;
@@ -920,19 +920,24 @@ impl Allocator for DebrayAllocator {
         self.arg_c += 1;
     }
 
-    fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize) {
-        read_heap_cell!(term.deref_loc(head_loc),
+    fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize) {
+        let head_cell = heap_bound_store(
+            heap,
+            heap_bound_deref(heap, heap_loc_as_cell!(head_loc)),
+        );
+
+        read_heap_cell!(head_cell,
             (HeapCellValueTag::Str, s) => {
-                let arity = cell_as_atom_cell!(term.heap[s]).get_arity();
+                let arity = cell_as_atom_cell!(heap[s]).get_arity();
 
                 self.reset_arg(arity);
                 self.arity = arity;
 
-                for (idx, arg) in term.heap[s+1 .. s+arity+1].iter().cloned().enumerate() {
+                for (idx, arg) in heap.splice(s+1 ..= s+arity).enumerate() {
                     if arg.is_var() {
                         let var = heap_bound_store(
-                            &term.heap,
-                            heap_bound_deref(&term.heap, arg),
+                            heap,
+                            heap_bound_deref(heap, arg),
                         );
 
                         if !var.is_var() {
index be96e30c5ee3266eb0ab0fd0fa8a138d4b6c18ba..4053b5a9a349664fdb32a46de0a987da4c2eff0f 100644 (file)
@@ -1,9 +1,10 @@
 use crate::arena::*;
 use crate::atom_table::*;
 use crate::instructions::*;
+use crate::functor_macro::*;
 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_indices::*;
 use crate::parser::ast::*;
@@ -25,18 +26,6 @@ use std::path::PathBuf;
 
 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)]
 pub enum AppendOrPrepend {
     Append,
@@ -171,17 +160,6 @@ impl ChunkedTermVec {
             .push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
     }
 
-    pub fn push_branch_arm(&mut self, branch: VecDeque<ChunkedTerms>) {
-        match self.chunk_vec.back_mut().unwrap() {
-            ChunkedTerms::Branch(branches) => {
-                branches.push(branch);
-            }
-            ChunkedTerms::Chunk { .. } => {
-                self.chunk_vec.push_back(ChunkedTerms::Branch(vec![branch]));
-            }
-        }
-    }
-
     pub fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
         if self.current_chunk_type.is_last() {
             self.current_chunk_type = ChunkType::Mid;
@@ -243,7 +221,6 @@ impl ChunkedTermVec {
 #[derive(Debug)]
 pub struct QueryClause {
     pub ct: ClauseType,
-    pub arity: usize,
     pub term: HeapCellValue,
     pub code_indices: IndexMap<usize, CodeIndex, FxBuildHasher>,
     pub call_policy: CallPolicy,
@@ -266,14 +243,14 @@ pub enum QueryTerm {
     GetLevel(usize), // var_num
 }
 
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
 pub struct Fact {
-    pub(crate) term: FocusedHeap,
+    pub(crate) term_loc: usize,
 }
 
 #[derive(Debug)]
 pub struct Rule {
-    pub(crate) term: FocusedHeap,
+    pub(crate) term_loc: usize,
     pub(crate) clauses: ChunkedTermVec,
 }
 
@@ -290,138 +267,34 @@ impl ListingSource {
     }
 }
 
-pub trait ClauseInfo {
-    fn is_consistent(&self, clauses: &PredicateQueue) -> bool {
-        match clauses.first() {
-            Some(cl) => {
-                self.name() == ClauseInfo::name(cl) && self.arity() == ClauseInfo::arity(cl)
-            }
-            None => true,
+pub fn clause_predicate_key_from_heap(
+    heap: &impl SizedHeap,
+    value: HeapCellValue,
+) -> Option<PredicateKey> {
+    read_heap_cell!(value,
+        (HeapCellValueTag::Atom, (name, _arity)) => {
+            debug_assert_eq!(_arity, 0);
+            Some((name, 0))
         }
-    }
-
-    fn name(&self) -> Option<Atom>;
-    fn arity(&self) -> usize;
-}
-
-impl ClauseInfo for PredicateKey {
-    #[inline]
-    fn name(&self) -> Option<Atom> {
-        Some(self.0)
-    }
-
-    #[inline]
-    fn arity(&self) -> usize {
-        self.1
-    }
-}
-
-fn clause_name(heap: &[HeapCellValue], term_loc: usize) -> Option<Atom> {
-    let name = term_name(heap, term_loc);
-
-    if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) {
-        term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| term_name(heap, arg_loc))
-    } else {
-        name
-    }
-}
-
-fn clause_arity(heap: &[HeapCellValue], term_loc: usize) -> usize {
-    let name = term_name(heap, term_loc);
-
-    if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) {
-        term_nth_arg(heap, term_loc, 1)
-            .map(|arg_loc| term_arity(heap, arg_loc))
-            .unwrap_or(0)
-    } else {
-        term_arity(heap, term_loc)
-    }
-}
-
-impl ClauseInfo for FocusedHeap {
-    #[inline]
-    fn name(&self) -> Option<Atom> {
-        clause_name(&self.heap, self.focus)
-    }
-
-    #[inline]
-    fn arity(&self) -> usize {
-        clause_arity(&self.heap, self.focus)
-    }
-}
-
-impl<'a> ClauseInfo for FocusedHeapRefMut<'a> {
-    #[inline]
-    fn name(&self) -> Option<Atom> {
-        clause_name(self.heap, self.focus)
-    }
-
-    #[inline]
-    fn arity(&self) -> usize {
-        clause_arity(self.heap, self.focus)
-    }
-}
-
-/*
-impl ClauseInfo for Term {
-    fn name(&self) -> Option<Atom> {
-        match self {
-            Term::Clause(_, name, terms) => {
-                match name {
-                    atom!(":-") => {
-                        match terms.len() {
-                            1 => None, // a declaration.
-                            2 => terms[0].name(),
-                            _ => Some(*name),
-                        }
-                    }
-                    _ => Some(*name), //str_buf),
-                }
+        _ => {
+            if value.is_ref() {
+                clause_predicate_key(heap, value.get_value() as usize)
+            } else {
+                None
             }
-            Term::Literal(_, Literal::Atom(name)) => Some(*name),
-            _ => None,
         }
-    }
-
-    fn arity(&self) -> usize {
-        match self {
-            Term::Clause(_, name, terms) => match &*name.as_str() {
-                ":-" => match terms.len() {
-                    1 => 0,
-                    2 => terms[0].arity(),
-                    _ => terms.len(),
-                },
-                _ => terms.len(),
-            },
-            _ => 0,
-        }
-    }
-}
-*/
-
-impl ClauseInfo for Rule {
-    fn name(&self) -> Option<Atom> {
-        self.term.name(self.term.focus)
-    }
-
-    fn arity(&self) -> usize {
-        self.term.arity(self.term.focus)
-    }
+    )
 }
 
-impl ClauseInfo for PredicateClause {
-    fn name(&self) -> Option<Atom> {
-        match self {
-            PredicateClause::Fact(ref fact, ..) => fact.term.name(fact.term.focus),
-            PredicateClause::Rule(ref rule, ..) => rule.term.name(rule.term.focus),
-        }
-    }
+pub fn clause_predicate_key(heap: &impl SizedHeap, term_loc: usize) -> Option<PredicateKey> {
+    let key_opt = term_predicate_key(heap, term_loc);
 
-    fn arity(&self) -> usize {
-        match self {
-            PredicateClause::Fact(ref fact, ..) => fact.term.arity(fact.term.focus),
-            PredicateClause::Rule(ref rule, ..) => rule.term.arity(rule.term.focus),
-        }
+    if Some((atom!(":-"), 2)) == key_opt {
+        term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| {
+            term_predicate_key(heap, arg_loc)
+        })
+    } else {
+        key_opt
     }
 }
 
@@ -432,33 +305,27 @@ pub enum PredicateClause {
 }
 
 impl PredicateClause {
-    pub(crate) fn args(&self) -> Option<&[HeapCellValue]> {
-        let (term, focus) = match self {
-            PredicateClause::Fact(Fact { term }, _) => (term, term.focus),
-            PredicateClause::Rule(Rule { term, .. }, _) => {
-                let focus = term.nth_arg(term.focus, 1).unwrap();
-                (term, focus)
+    pub(crate) fn args<'a>(&self, heap: &'a Heap) -> Option<std::ops::RangeInclusive<usize>> {
+        let focus = match self {
+            &PredicateClause::Fact(Fact { term_loc }, _) => term_loc,
+            &PredicateClause::Rule(Rule { term_loc, .. }, _) => {
+                term_nth_arg(heap, term_loc, 1).unwrap()
             }
         };
 
-        let arity = term.arity(focus);
+        let arity = clause_predicate_key(heap, focus)
+            .map(|(_name, arity)| arity)
+            .unwrap_or(0);
 
-        read_heap_cell!(term.deref_loc(focus),
+        read_heap_cell!(heap_bound_store(heap, heap_bound_deref(heap, heap[focus])),
             (HeapCellValueTag::Str, s) => {
-                Some(&term.heap[s+1 .. s+arity+1])
+                Some(s+1 ..= s+arity)
             }
             _ => {
                 None
             }
         )
     }
-
-    pub(crate) fn heap(&self) -> &[HeapCellValue] {
-        match self {
-            PredicateClause::Fact(ref fact, ..) => &fact.term.heap,
-            PredicateClause::Rule(ref rule, ..) => &rule.term.heap,
-        }
-    }
 }
 
 #[derive(Debug)]
@@ -477,10 +344,10 @@ pub enum ModuleSource {
 impl ModuleSource {
     pub(crate) fn as_functor_stub(&self) -> MachineStub {
         match self {
-            ModuleSource::Library(name) => {
-                functor!(atom!("library"), [atom(name)])
+            &ModuleSource::Library(name) => {
+                functor!(atom!("library"), [atom_as_cell(name)])
             }
-            ModuleSource::File(name) => {
+            &ModuleSource::File(name) => {
                 functor!(name)
             }
         }
@@ -813,6 +680,7 @@ impl ArenaFrom<i32> for Number {
     }
 }
 
+/*
 impl ArenaFrom<Number> for Literal {
     #[inline]
     fn arena_from(value: Number, arena: &mut Arena) -> Literal {
@@ -824,6 +692,21 @@ impl ArenaFrom<Number> for Literal {
         }
     }
 }
+*/
+
+impl ArenaFrom<u64> for HeapCellValue {
+    #[inline]
+    fn arena_from(value: u64, arena: &mut Arena) -> HeapCellValue {
+        fixnum!(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 {
     #[inline]
@@ -896,8 +779,8 @@ impl Number {
 
 #[derive(Debug, Clone)]
 pub(crate) enum OptArgIndexKey {
-    Literal(usize, usize, Literal, Vec<Literal>), // index, IndexingCode location, opt arg, alternatives
-    List(usize, usize),                           // index, IndexingCode location
+    Literal(usize, usize, HeapCellValue, Vec<HeapCellValue>), // index, IndexingCode location, opt arg, alternatives
+    List(usize, usize),                                       // index, IndexingCode location
     None,
     Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
 }
diff --git a/src/functor_macro.rs b/src/functor_macro.rs
new file mode 100644 (file)
index 0000000..081a441
--- /dev/null
@@ -0,0 +1,616 @@
+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 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),*]) => ({
+        build_functor!([$($dt($($value),*)),*],
+                       [$($res, )* FunctorElement::Cell(str_loc_as_cell!(1u64 + count!($($dt)*) + $res_len))],
+                       3 + $res_len,
+                       [$($subfunctor, )* FunctorElement::InnerFunctor(2, indexing_code_ptr($e))])
+    });
+    ([fixnum($e:expr) $(, $dt:ident($($value:tt),*))*],
+     [$($res:expr),*],
+     $res_len:expr,
+     [$($subfunctor:expr),*]) => ({
+         build_functor!([$($dt($($value),*)),*],
+                        [$($res, )* FunctorElement::Cell(fixnum_as_cell!(Fixnum::build_with($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),*])
+    });
+    ([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),*]) => ({
+        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> {
+    match code_ptr {
+        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![FunctorElement::Cell(atom_as_cell!(atom!("fail")))]
+        }
+    }
+}
+
+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();
+
+    for (idx, _) in key_value_pairs.iter().enumerate() {
+        arg_vec.push(FunctorElement::Cell(str_loc_as_cell!(2 + num_items * 2 + idx)));
+        arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(5 + idx)));
+    }
+
+    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 FunctorElement::*;
+    use std::string::String;
+
+    #[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(), 7);
+
+        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], pstr_loc_as_cell!(heap_index!(5)));
+        assert_eq!(heap.slice_to_str(heap_index!(5), " string".len()), " string");
+        assert_eq!(heap[6], 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!());
+    }
+
+    #[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!());
+    }
+}
index 5b62183665423eb9d48336e9c9c4cce7ba4c218e..89f392816b4b832033bccc89990715e343c65339 100644 (file)
@@ -116,24 +116,10 @@ impl<'a> EagerStackfulPreOrderHeapIter<'a> {
                     }
                 }
                 (HeapCellValueTag::PStrLoc, h) => {
-                    let h = if self.heap[h].get_tag() == HeapCellValueTag::PStr {
-                        h
-                    } else {
-                        debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::PStrOffset);
-                        self.heap[h].get_value() as usize
-                    };
-
-                    if self.heap[h].get_mark_bit() == self.mark_phase {
-                        continue;
-                    }
+                    let (_, tail_loc) = self.heap.scan_slice_to_str(h);
 
-                    self.heap[h].set_mark_bit(self.mark_phase);
-
-                    if self.heap[h].get_tag() == HeapCellValueTag::PStr {
-                        let value = self.heap[h+1];
-                        self.heap[h+1].set_mark_bit(self.mark_phase);
-                        self.iter_stack.push(value);
-                    }
+                    self.heap[tail_loc].set_mark_bit(self.mark_phase);
+                    self.iter_stack.push(self.heap[tail_loc]);
                 }
                 _ => {
                 }
@@ -249,7 +235,7 @@ impl ListElisionPolicy for NonListElider {
 
 #[derive(Debug)]
 pub struct StackfulPreOrderHeapIter<'a, ElideLists> {
-    pub heap: &'a mut [HeapCellValue],
+    pub heap: &'a mut Heap,
     pub machine_stack: &'a mut Stack,
     stack: Vec<IterStackLoc>,
     h: IterStackLoc,
@@ -264,14 +250,10 @@ impl<'a, ElideLists> Drop for StackfulPreOrderHeapIter<'a, ElideLists> {
             cell.set_forwarding_bit(false);
             cell.set_mark_bit(false);
         }
-
-        // self.heap.pop();
     }
 }
 
-pub trait FocusedHeapIter:
-    Deref<Target = [HeapCellValue]> + Iterator<Item = HeapCellValue>
-{
+pub trait FocusedHeapIter: Deref<Target = Heap> + Iterator<Item = HeapCellValue> {
     fn focus(&self) -> IterStackLoc;
 }
 
@@ -285,7 +267,7 @@ impl<'a, ElideLists: ListElisionPolicy> FocusedHeapIter
 }
 
 impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> {
-    type Target = [HeapCellValue];
+    type Target = Heap;
 
     fn deref(&self) -> &Self::Target {
         &self.heap
@@ -368,7 +350,7 @@ impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
 
 impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> {
     #[inline]
-    fn new(heap: &'a mut [HeapCellValue], stack: &'a mut Stack, root_loc: usize) -> Self {
+    fn new(heap: &'a mut Heap, stack: &'a mut Stack, root_loc: usize) -> Self {
         let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap);
         // heap.push(cell);
 
@@ -395,8 +377,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
             }
             (HeapCellValueTag::Str |
              HeapCellValueTag::AttrVar |
-             HeapCellValueTag::Var |
-             HeapCellValueTag::PStrLoc, vh) => {
+             HeapCellValueTag::Var, vh) => {
                 if self.heap[vh].get_mark_bit() {
                     self.read_cell_mut(loc).set_forwarding_bit(true);
                 }
@@ -438,7 +419,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
             }
 
             read_heap_cell!(*cell,
-               (HeapCellValueTag::Str | HeapCellValueTag::PStrLoc, vh) => {
+               (HeapCellValueTag::Str, vh) => {
                    let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap);
 
                    self.push_if_unmarked(loc);
@@ -469,20 +450,30 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
                    self.push_if_unmarked(loc);
                    self.stack.push(IterStackLoc::mark_loc(vs, HeapOrStackTag::Stack));
                }
-               (HeapCellValueTag::PStrOffset, offset) => {
-                   self.push_if_unmarked(IterStackLoc::iterable_loc(offset, HeapOrStackTag::Heap));
-                   self.stack.push(IterStackLoc::iterable_loc((h.value()+1) as usize, HeapOrStackTag::Heap));
+               (HeapCellValueTag::PStrLoc, vh) => {
+                   let cell = *cell;
+                   let (_, tail_loc) = self.heap.scan_slice_to_str(vh);
+
+                   // forward the current PStrLoc cell if the zero
+                   // byte at the end of the string buffer
+                   // is marked
+                   let buf_bytes = self.heap[tail_loc - 1].into_bytes();
+
+                   if buf_bytes[7] != 0u8 {
+                       let cell = self.read_cell_mut(h);
+                       cell.set_forwarding_bit(true);
+                   }
 
-                   return Some(self.read_cell(h));
-               }
-               (HeapCellValueTag::PStr) => {
-                   let tail_loc = IterStackLoc::iterable_loc((h.value()+1) as usize, HeapOrStackTag::Heap);
+                   // now mark it as if were a HeapCellValue, even
+                   // though it's not! this is fine as long as its tag
+                   // is never inspected, which it isn't.
 
-                   self.push_if_unmarked(IterStackLoc::iterable_loc(h.value() as usize, HeapOrStackTag::Heap));
-                   self.stack.push(tail_loc);
-                   self.forward_if_referent_marked(tail_loc);
+                   self.push_if_unmarked(
+                       IterStackLoc::iterable_loc(tail_loc - 1, HeapOrStackTag::Heap),
+                   );
+                   self.stack.push(IterStackLoc::mark_loc(tail_loc, HeapOrStackTag::Heap));
 
-                   return Some(self.read_cell(h));
+                   return Some(cell);
                }
                (HeapCellValueTag::Atom, (_name, arity)) => {
                    let l = h.value() as usize;
@@ -523,7 +514,7 @@ impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a
 
 #[inline(always)]
 pub(crate) fn cycle_detecting_stackless_preorder_iter(
-    heap: &'_ mut [HeapCellValue],
+    heap: &'_ mut Heap,
     start: usize,
 ) -> CycleDetectingIter<'_, true> {
     // const generics argument of true so that cycle discovery stops
@@ -533,7 +524,7 @@ pub(crate) fn cycle_detecting_stackless_preorder_iter(
 
 #[inline(always)]
 pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>(
-    heap: &'a mut Vec<HeapCellValue>,
+    heap: &'a mut Heap,
     stack: &'a mut Stack,
     root_loc: usize,
 ) -> StackfulPreOrderHeapIter<'a, ElideLists> {
@@ -543,13 +534,13 @@ pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>(
 #[derive(Debug)]
 pub(crate) struct PostOrderIterator<Iter: FocusedHeapIter> {
     focus: IterStackLoc,
-    base_iter: Iter,
+    pub(crate) base_iter: Iter,
     base_iter_valid: bool,
     parent_stack: Vec<(usize, HeapCellValue, IterStackLoc)>, // number of children, parent node, focus.
 }
 
 impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> {
-    type Target = [HeapCellValue];
+    type Target = Heap;
 
     fn deref(&self) -> &Self::Target {
         &self.base_iter
@@ -592,7 +583,7 @@ impl<Iter: FocusedHeapIter> Iterator for PostOrderIterator<Iter> {
                         (HeapCellValueTag::Lis) => {
                             self.parent_stack.push((2, item, focus));
                         }
-                        (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
+                        (HeapCellValueTag::PStrLoc) => { // HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
                             self.parent_stack.push((1, item, focus));
                         }
                         _ => {
@@ -678,6 +669,8 @@ pub(crate) fn stackful_post_order_iter<'a, ElideLists: ListElisionPolicy>(
 #[cfg(test)]
 mod tests {
     use super::*;
+
+    use crate::functor_macro::*;
     use crate::machine::gc::IteratorUMP;
     use crate::machine::mock_wam::*;
 
@@ -686,7 +679,7 @@ mod tests {
 
     #[inline(always)]
     pub(crate) fn stackless_preorder_iter(
-        heap: &mut [HeapCellValue],
+        heap: &mut Heap,
         start: usize,
     ) -> StacklessPreOrderHeapIter<IteratorUMP> {
         StacklessPreOrderHeapIter::<IteratorUMP>::new(heap, start)
@@ -705,15 +698,21 @@ mod tests {
     fn heap_stackless_iter_tests() {
         let mut wam = MockWAM::new();
 
+        // clear the heap of resource error data etc
+        wam.machine_st.heap.clear();
+
         let f_atom = atom!("f");
         let a_atom = atom!("a");
         let b_atom = atom!("b");
 
-        wam.machine_st
-            .heap
-            .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+        let mut functor_writer = Heap::functor_writer(functor!(
+            f_atom,
+            [atom_as_cell(a_atom),
+             atom_as_cell(b_atom)]),
+        );
 
-        wam.machine_st.heap.push(str_loc_as_cell!(0));
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3);
@@ -734,21 +733,23 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.extend(functor!(
+        let mut functor_writer = Heap::functor_writer(functor!(
             f_atom,
             [
-                atom(a_atom),
-                atom(b_atom),
-                atom(a_atom),
-                cell(str_loc_as_cell!(0))
+                atom_as_cell(a_atom),
+                atom_as_cell(b_atom),
+                atom_as_cell(a_atom),
+                str_loc_as_cell(0)
             ]
         ));
 
-        wam.machine_st.heap.push(str_loc_as_cell!(0));
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
         for _ in 0..20 {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5);
@@ -757,51 +758,10 @@ mod tests {
                 unmark_cell_bits!(iter.next().unwrap()),
                 atom_as_cell!(f_atom, 4)
             );
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0));
-
-            assert_eq!(
-                unmark_cell_bits!(iter.next().unwrap()),
-                atom_as_cell!(a_atom)
-            );
-
-            assert_eq!(
-                unmark_cell_bits!(iter.next().unwrap()),
-                atom_as_cell!(b_atom)
-            );
-
-            assert_eq!(
-                unmark_cell_bits!(iter.next().unwrap()),
-                atom_as_cell!(a_atom)
-            );
-
-            assert_eq!(iter.next(), None);
-        }
-
-        all_cells_unmarked(&wam.machine_st.heap);
-
-        wam.machine_st.heap.clear();
-
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
-
-        wam.machine_st.heap.extend(functor!(
-            f_atom,
-            [
-                atom(a_atom),
-                atom(b_atom),
-                atom(a_atom),
-                cell(str_loc_as_cell!(1))
-            ]
-        ));
-
-        for _ in 0..200000 {
-            let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
-
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                atom_as_cell!(f_atom, 4)
+                str_loc_as_cell!(0)
             );
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1));
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
                 atom_as_cell!(a_atom)
@@ -818,12 +778,12 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
         {
-            wam.machine_st.heap.push(heap_loc_as_cell!(0));
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap();
 
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
 
@@ -834,16 +794,20 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
         // term  is: [a, b]
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(a_atom));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(atom_as_cell!(b_atom));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(a_atom));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(atom_as_cell!(b_atom));
+            section.push_cell(empty_list_as_cell!());
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
@@ -873,12 +837,10 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
-
-        wam.machine_st.heap.pop();
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         // now make the list cyclic.
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        wam.machine_st.heap[4] = heap_loc_as_cell!(0);
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
@@ -909,181 +871,96 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
-        // first a 'dangling' partial string, later modified to be a two-part complete string,
-        // then a three-part cyclic string involving an uncompacted list of chars.
-        let pstr_var_cell =
-            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];
+        // first a 'dangling' partial string, later modified to be a
+        // two-part complete string, then a three-part cyclic string
+        // involving an uncompacted list of chars.
 
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+        wam.machine_st.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 mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2);
 
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                heap_loc_as_cell!(1),
+                pstr_loc_as_cell!(0)
             );
-
-            assert!(iter.next().is_none());
-        }
-
-        assert_eq!(wam.machine_st.heap[0], pstr_cell);
-        assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1));
-
-        wam.machine_st.heap[1] = pstr_loc_as_cell!(3);
-
-        let pstr_second_var_cell =
-            put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
-
-        let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
-
-        {
-            let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2);
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                heap_loc_as_cell!(4),
+                heap_loc_as_cell!(1),
             );
-
             assert!(iter.next().is_none());
         }
 
-        assert_eq!(wam.machine_st.heap[0], pstr_cell);
-        assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(3));
-        assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(0));
-        assert_eq!(wam.machine_st.heap[3], pstr_second_cell);
-        assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(4));
+        wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.push(pstr_loc_as_cell!(5));
-        wam.machine_st.heap.push(pstr_offset_as_cell!(0));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(2)));
+        wam.machine_st.allocate_pstr("def").unwrap();
 
-        wam.machine_st.heap[2] = heap_loc_as_cell!(4);
+        wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
+        wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
 
         {
-            let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2);
-
-            let pstr_offset_cell = pstr_offset_as_cell!(0);
+            let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5);
 
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                fixnum_as_cell!(Fixnum::build_with(2))
+                pstr_loc_as_cell!(0)
             );
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
-
-            assert_eq!(iter.next(), None);
-        }
-
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[1]),
-            pstr_loc_as_cell!(3)
-        );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell);
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
-            pstr_loc_as_cell!(5)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_offset_as_cell!(0)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
-            fixnum_as_cell!(Fixnum::build_with(2))
-        );
-
-        wam.machine_st.heap.truncate(4);
-
-        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)));
-
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
-
-        {
-            let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 6);
-            let pstr_offset_cell = pstr_offset_as_cell!(0);
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                pstr_loc_as_cell!(4)
+                pstr_loc_as_cell!(heap_index!(3))
             );
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                fixnum_as_cell!(Fixnum::build_with(0))
+                heap_loc_as_cell!(4),
             );
-
-            assert_eq!(iter.next(), None);
+            assert!(iter.next().is_none());
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
-
-        wam.machine_st.heap[5] = fixnum_as_cell!(Fixnum::build_with(1i64));
+        wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2);
 
         {
-            let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 6);
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-            assert_eq!(
-                unmark_cell_bits!(iter.next().unwrap()),
-                pstr_loc_as_cell!(4)
-            );
+            let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5);
 
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                pstr_offset_as_cell!(0)
+                pstr_loc_as_cell!(0)
             );
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                pstr_offset_as_cell!(0)
+                pstr_loc_as_cell!(heap_index!(3))
             );
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                fixnum_as_cell!(Fixnum::build_with(1))
+                pstr_loc_as_cell!(heap_index!(3) + 2)
             );
-
             assert_eq!(iter.next(), None);
         }
 
-        assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0));
-        assert_eq!(
-            wam.machine_st.heap[5],
-            fixnum_as_cell!(Fixnum::build_with(1i64))
-        );
-
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         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));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(str_loc_as_cell!(5));
+            section.push_cell(list_loc_as_cell!(3));
+            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 mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
@@ -1126,7 +1003,7 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
@@ -1167,7 +1044,7 @@ mod tests {
             // instance.
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
         assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5));
@@ -1197,7 +1074,7 @@ mod tests {
             // instance.
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
         assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5));
@@ -1249,15 +1126,19 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(heap_loc_as_cell!(1));
+            section.push_cell(heap_loc_as_cell!(2));
+            section.push_cell(heap_loc_as_cell!(3));
+            section.push_cell(heap_loc_as_cell!(3));
+            section.push_cell(heap_loc_as_cell!(0));
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 4);
@@ -1266,7 +1147,7 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -1288,9 +1169,13 @@ mod tests {
         wam.machine_st.heap.clear();
 
         // print L = [L|L].
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(list_loc_as_cell!(1));
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
@@ -1308,7 +1193,7 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -1326,21 +1211,25 @@ mod tests {
         wam.machine_st.heap.clear();
 
         // term is [X,f(Y),Z].
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2
-        wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3
-        wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4
-        wam.machine_st.heap.push(heap_loc_as_cell!(8));
-        wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6
-        wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7
-        wam.machine_st.heap.push(list_loc_as_cell!(9));
-        wam.machine_st.heap.push(heap_loc_as_cell!(9));
-        wam.machine_st.heap.push(empty_list_as_cell!());
-
-        wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7.
-        wam.machine_st.heap.push(heap_loc_as_cell!(12));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(heap_loc_as_cell!(1));
+            section.push_cell(heap_loc_as_cell!(3)); // 2
+            section.push_cell(list_loc_as_cell!(4)); // 3
+            section.push_cell(str_loc_as_cell!(6)); // 4
+            section.push_cell(heap_loc_as_cell!(8));
+            section.push_cell(atom_as_cell!(f_atom, 1)); // 6
+            section.push_cell(heap_loc_as_cell!(11)); // 7
+            section.push_cell(list_loc_as_cell!(9));
+            section.push_cell(heap_loc_as_cell!(9));
+            section.push_cell(empty_list_as_cell!());
+
+            section.push_cell(attr_var_as_cell!(11)); // linked from 7.
+            section.push_cell(heap_loc_as_cell!(12));
+            section.push_cell(heap_loc_as_cell!(0));
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 13);
@@ -1382,22 +1271,25 @@ mod tests {
         let clpz_atom = atom!("clpz");
         let p_atom = atom!("p");
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.pop();
-
-        wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12
-        wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13
-        wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14
-        wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15
-        wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16
-        wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17
-        wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18
-        wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19
-        wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20
-        wam.machine_st.heap.push(empty_list_as_cell!()); // 21
-        wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22
-        wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        wam.machine_st.heap.truncate(12);
+
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(heap_loc_as_cell!(13)); // 12
+            section.push_cell(list_loc_as_cell!(14)); // 13
+            section.push_cell(str_loc_as_cell!(16)); // 14
+            section.push_cell(heap_loc_as_cell!(19)); // 15
+            section.push_cell(atom_as_cell!(clpz_atom, 2)); // 16
+            section.push_cell(atom_as_cell!(a_atom)); // 17
+            section.push_cell(atom_as_cell!(b_atom)); // 18
+            section.push_cell(list_loc_as_cell!(20)); // 19
+            section.push_cell(str_loc_as_cell!(22)); // 20
+            section.push_cell(empty_list_as_cell!()); // 21
+            section.push_cell(atom_as_cell!(p_atom, 1)); // 22
+            section.push_cell(heap_loc_as_cell!(23)); // 23
+            section.push_cell(heap_loc_as_cell!(0));
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 24);
@@ -1535,9 +1427,7 @@ mod tests {
         wam.machine_st.heap.clear();
 
         {
-            wam.machine_st
-                .heap
-                .push(fixnum_as_cell!(Fixnum::build_with(0)));
+            wam.machine_st.heap.push_cell(fixnum_as_cell!(Fixnum::build_with(0))).unwrap();
 
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
 
@@ -1549,15 +1439,18 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
 
-        wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
+        writer.write_with(|section| {
+            section.push_cell(str_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(atom!("g"), 2));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(atom_as_cell!(atom!("y")));
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0);
@@ -1580,14 +1473,18 @@ mod tests {
             assert!(iter.next().is_none());
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2));
-        wam.machine_st.heap.push(str_loc_as_cell!(0));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
-        wam.machine_st.heap.push(str_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(atom_as_cell!(atom!("g"), 2));
+            section.push_cell(str_loc_as_cell!(0));
+            section.push_cell(atom_as_cell!(atom!("y")));
+            section.push_cell(str_loc_as_cell!(0));
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3);
@@ -1607,20 +1504,24 @@ mod tests {
             assert!(iter.next().is_none());
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("X")));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(list_loc_as_cell!(8));
-        wam.machine_st.heap.push(str_loc_as_cell!(4));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(str_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(atom!("g"), 2));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(atom_as_cell!(atom!("y")));
+            section.push_cell(atom_as_cell!(atom!("="), 2));
+            section.push_cell(atom_as_cell!(atom!("X")));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(list_loc_as_cell!(8));
+            section.push_cell(str_loc_as_cell!(4));
+            section.push_cell(empty_list_as_cell!());
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 7);
@@ -1663,7 +1564,7 @@ mod tests {
             assert!(iter.next().is_none());
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(wam.machine_st.heap[0], str_loc_as_cell!(1));
         assert_eq!(wam.machine_st.heap[1], atom_as_cell!(atom!("g"), 2));
@@ -1678,10 +1579,14 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(str_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(atom_as_cell!(atom!("f"), 2));
+            section.push_cell(heap_loc_as_cell!(1));
+            section.push_cell(heap_loc_as_cell!(1));
+            section.push_cell(str_loc_as_cell!(0));
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3);
@@ -1710,18 +1615,21 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
         // representation of one of the heap terms as in issue #1384.
-        wam.machine_st.heap.push(list_loc_as_cell!(7)); // 0
-        wam.machine_st.heap.push(heap_loc_as_cell!(0)); // 1
-        wam.machine_st.heap.push(list_loc_as_cell!(3)); // 2
-        wam.machine_st.heap.push(list_loc_as_cell!(5)); // 3
-        wam.machine_st.heap.push(empty_list_as_cell!()); // 4
-        wam.machine_st.heap.push(heap_loc_as_cell!(2)); // 5
-        wam.machine_st.heap.push(heap_loc_as_cell!(2)); // 6
-        wam.machine_st.heap.push(empty_list_as_cell!()); // 7
-        wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 8
-
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(7)); // 0
+            section.push_cell(heap_loc_as_cell!(0)); // 1
+            section.push_cell(list_loc_as_cell!(3)); // 2
+            section.push_cell(list_loc_as_cell!(5)); // 3
+            section.push_cell(empty_list_as_cell!()); // 4
+            section.push_cell(heap_loc_as_cell!(2)); // 5
+            section.push_cell(heap_loc_as_cell!(2)); // 6
+            section.push_cell(empty_list_as_cell!()); // 7
+            section.push_cell(heap_loc_as_cell!(3)); // 8
+            section.push_cell(heap_loc_as_cell!(0)); // 9
+        });
 
         {
             let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 9);
@@ -1776,21 +1684,29 @@ mod tests {
     fn heap_stackful_iter_tests() {
         let mut wam = MockWAM::new();
 
+        // clear the heap of resource error data etc
+        wam.machine_st.heap.clear();
+
         let f_atom = atom!("f");
         let a_atom = atom!("a");
         let b_atom = atom!("b");
 
-        wam.machine_st
-            .heap
-            .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+        let mut functor_writer = Heap::functor_writer(functor!(
+            f_atom,
+            [atom_as_cell(a_atom),
+             atom_as_cell(b_atom)]),
+        );
+
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        let h = wam.machine_st.heap.cell_len();
 
-        wam.machine_st.heap.push(str_loc_as_cell!(0));
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
         {
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                3,
+                h,
             );
 
             assert_eq!(
@@ -1811,21 +1727,26 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.extend(functor!(
+        let mut functor_writer = Heap::functor_writer(functor!(
             f_atom,
             [
-                atom(a_atom),
-                atom(b_atom),
-                atom(a_atom),
-                cell(str_loc_as_cell!(0))
+                atom_as_cell(a_atom),
+                atom_as_cell(b_atom),
+                atom_as_cell(a_atom),
+                str_loc_as_cell(0)
             ]
         ));
 
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        let h = wam.machine_st.heap.cell_len();
+
+        wam.machine_st.heap.push_cell(cell).unwrap();
+
         for _ in 0..20 {
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                4,
+                h,
             );
 
             assert_eq!(
@@ -1852,7 +1773,7 @@ mod tests {
         wam.machine_st.heap.clear();
 
         {
-            wam.machine_st.heap.push(heap_loc_as_cell!(0));
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap();
 
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
                 &mut wam.machine_st.heap,
@@ -1878,8 +1799,8 @@ mod tests {
 
         {
             // mutually referencing variables.
-            wam.machine_st.heap.push(heap_loc_as_cell!(1));
-            wam.machine_st.heap.push(heap_loc_as_cell!(0));
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap();
 
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
                 &mut wam.machine_st.heap,
@@ -1898,11 +1819,15 @@ mod tests {
         wam.machine_st.heap.clear();
 
         // term  is: [a, b]
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(a_atom));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(atom_as_cell!(b_atom));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(a_atom));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(atom_as_cell!(b_atom));
+            section.push_cell(empty_list_as_cell!());
+        });
 
         {
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
@@ -1935,10 +1860,8 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        wam.machine_st.heap.pop();
-
         // now make the list cyclic.
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        wam.machine_st.heap[4] = heap_loc_as_cell!(0);
 
         {
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
@@ -2001,7 +1924,7 @@ mod tests {
             );
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
         assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
@@ -2015,156 +1938,112 @@ mod tests {
         // two-part complete string, then a three-part cyclic string
         // involving an uncompacted list of chars.
 
-        let pstr_var_cell =
-            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.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 mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                0,
+                2,
             );
 
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                heap_loc_as_cell!(1),
+                pstr_loc_as_cell!(0)
             );
-
-            assert_eq!(iter.next(), None);
+            assert_eq!(
+                unmark_cell_bits!(iter.next().unwrap()),
+                heap_loc_as_cell!(1)
+            );
+            assert!(iter.next().is_none());
         }
 
-        // here
-
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
+        wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
+        wam.machine_st.allocate_pstr("def").unwrap();
 
-        let pstr_second_var_cell =
-            put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
-        let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+        wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
+        wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
 
         {
             let mut iter = stackful_preorder_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                0,
+                5,
             );
 
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                heap_loc_as_cell!(3),
+                pstr_loc_as_cell!(0)
             );
-
-            assert_eq!(iter.next(), None);
-        }
-
-        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 h = wam.machine_st.heap.len();
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-
-        {
-            let mut iter = stackful_preorder_iter::<NonListElider>(
-                &mut wam.machine_st.heap,
-                &mut wam.machine_st.stack,
-                h,
+            assert_eq!(
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(heap_index!(3))
             );
-
-            let pstr_offset_cell = pstr_offset_as_cell!(0);
-
-            // pstr_offset_cell.set_forwarding_bit(true);
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
             assert_eq!(
-                iter.next().unwrap(),
-                fixnum_as_cell!(Fixnum::build_with(0i64))
+                unmark_cell_bits!(iter.next().unwrap()),
+                heap_loc_as_cell!(4),
             );
-
             assert_eq!(iter.next(), None);
         }
 
-        /*
-        {
-            let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
-            let string: String = iter.chars().collect();
-            assert_eq!(string, "abc def");
-        }
-        */
-
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.pop();
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(1i64)));
-
-        let h = wam.machine_st.heap.len();
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2);
 
         {
             let mut iter = stackful_preorder_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                h,
+                5,
             );
 
-            let pstr_offset_cell = pstr_offset_as_cell!(0);
-
-            // pstr_offset_cell.set_forwarding_bit(true);
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
             assert_eq!(
-                iter.next().unwrap(),
-                fixnum_as_cell!(Fixnum::build_with(1i64))
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(0)
             );
-
-            let h = iter.focus();
-
-            assert_eq!(h.value(), 5);
-            assert_eq!(unmark_cell_bits!(iter.heap[4]), pstr_offset_as_cell!(0));
             assert_eq!(
-                unmark_cell_bits!(iter.heap[5]),
-                fixnum_as_cell!(Fixnum::build_with(1i64))
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(heap_index!(3))
+            );
+            assert_eq!(
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(heap_index!(3) + 2)
+            );
+            assert_eq!(
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(heap_index!(3) + 2)
             );
-
             assert_eq!(iter.next(), None);
         }
 
         wam.machine_st.heap.clear();
 
-        let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
+        let functor = functor!(
+            f_atom,
+            [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)]
+        );
 
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
 
-        wam.machine_st.heap.extend(functor);
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(str_loc_as_cell!(5));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(str_loc_as_cell!(5));
+            section.push_cell(empty_list_as_cell!());
+        });
 
-        let h = wam.machine_st.heap.len();
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        let mut functor_writer = Heap::functor_writer(functor);
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
         {
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                h,
+                0,
             );
 
             assert_eq!(
@@ -2219,7 +2098,7 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap[4] = list_loc_as_cell!(1);
 
@@ -2227,7 +2106,7 @@ mod tests {
             let mut iter = stackful_preorder_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                h,
+                0,
             );
 
             assert_eq!(
@@ -2284,13 +2163,17 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(list_loc_as_cell!(1));
+        });
 
         {
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
@@ -2319,13 +2202,17 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(pstr_as_cell!(atom!("a string")));
-        wam.machine_st.heap.push(empty_list_as_cell!());
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_pstr("a string");
+            section.push_cell(empty_list_as_cell!());
+            section.push_cell(pstr_loc_as_cell!(0));
+        });
 
         {
             let mut iter = stackful_preorder_iter::<NonListElider>(
@@ -2335,38 +2222,41 @@ mod tests {
             );
 
             assert_eq!(
-                unmark_cell_bits!(iter.next().unwrap()),
-                pstr_as_cell!(atom!("a string"))
+                iter.heap.slice_to_str(0, "a string".len()),
+                "a string"
+            );
+            assert_eq!(
+                iter.next().unwrap(),
+                empty_list_as_cell!()
             );
-
-            assert_eq!(iter.next().unwrap(), empty_list_as_cell!());
-
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("X")));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(list_loc_as_cell!(8));
-        wam.machine_st.heap.push(str_loc_as_cell!(4));
-        wam.machine_st.heap.push(empty_list_as_cell!());
-
-        let h = wam.machine_st.heap.len();
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(str_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(atom!("g"), 2));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(atom_as_cell!(atom!("y")));
+            section.push_cell(atom_as_cell!(atom!("="), 2));
+            section.push_cell(atom_as_cell!(atom!("X")));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(list_loc_as_cell!(8));
+            section.push_cell(str_loc_as_cell!(4));
+            section.push_cell(empty_list_as_cell!());
+            section.push_cell(heap_loc_as_cell!(0));
+        });
 
         {
             let mut iter = stackful_preorder_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                h,
+                10,
             );
 
             assert_eq!(
@@ -2392,21 +2282,29 @@ mod tests {
     fn heap_stackful_post_order_iter() {
         let mut wam = MockWAM::new();
 
+        // clear the heap of resource error data etc
+        wam.machine_st.heap.clear();
+
         let f_atom = atom!("f");
         let a_atom = atom!("a");
         let b_atom = atom!("b");
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
+        let mut functor_writer = Heap::functor_writer(functor!(
+            f_atom,
+            [atom_as_cell(a_atom),
+             atom_as_cell(b_atom)]),
+        );
+
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        let h = wam.machine_st.heap.cell_len();
 
-        wam.machine_st
-            .heap
-            .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
         {
             let mut iter = stackful_post_order_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                0,
+                h,
             );
 
             assert_eq!(
@@ -2427,23 +2325,28 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
-        wam.machine_st.heap.extend(functor!(
+
+        let mut functor_writer = Heap::functor_writer(functor!(
             f_atom,
             [
-                atom(a_atom),
-                atom(b_atom),
-                atom(a_atom),
-                cell(str_loc_as_cell!(1))
+                atom_as_cell(a_atom),
+                atom_as_cell(b_atom),
+                atom_as_cell(a_atom),
+                str_loc_as_cell(0)
             ]
         ));
 
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        let h = wam.machine_st.heap.cell_len();
+
+        wam.machine_st.heap.push_cell(cell).unwrap();
+
         for _ in 0..20 {
             // 0000 {
             let mut iter = stackful_post_order_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                0,
+                h,
             );
 
             assert_eq!(
@@ -2458,9 +2361,10 @@ mod tests {
                 unmark_cell_bits!(iter.next().unwrap()),
                 atom_as_cell!(a_atom)
             );
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1));
-
+            assert_eq!(
+                unmark_cell_bits!(iter.next().unwrap()),
+                str_loc_as_cell!(0)
+            );
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
                 atom_as_cell!(f_atom, 4)
@@ -2472,7 +2376,7 @@ mod tests {
         wam.machine_st.heap.clear();
 
         {
-            wam.machine_st.heap.push(heap_loc_as_cell!(0));
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap();
 
             let mut iter = stackful_post_order_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
@@ -2498,8 +2402,8 @@ mod tests {
 
         {
             // mutually referencing variables.
-            wam.machine_st.heap.push(heap_loc_as_cell!(1));
-            wam.machine_st.heap.push(heap_loc_as_cell!(0));
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap();
 
             let mut iter = stackful_post_order_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
@@ -2518,20 +2422,21 @@ mod tests {
         wam.machine_st.heap.clear();
 
         // term  is: [a, b]
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(a_atom));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(atom_as_cell!(b_atom));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
 
-        let h = wam.machine_st.heap.len();
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(a_atom));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(atom_as_cell!(b_atom));
+            section.push_cell(empty_list_as_cell!());
+        });
 
         {
             let mut iter = stackful_post_order_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                h,
+                0,
             );
 
             assert_eq!(
@@ -2558,18 +2463,14 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.pop();
-
         // now make the list cyclic.
-        let h = wam.machine_st.heap.len();
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        wam.machine_st.heap[4] = heap_loc_as_cell!(0);
 
         {
             let mut iter = stackful_post_order_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                h,
+                4,
             );
 
             // the cycle will be iterated twice before being detected.
@@ -2618,7 +2519,7 @@ mod tests {
             );
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
         assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
@@ -2632,140 +2533,106 @@ mod tests {
         // two-part complete string, then a three-part cyclic string
         // involving an uncompacted list of chars.
 
-        let pstr_var_cell =
-            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.allocate_pstr("abc ").unwrap();
 
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
-
-        let h = wam.machine_st.heap.len() - 1;
+        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 mut iter = stackful_post_order_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                h,
+                2,
             );
 
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
                 heap_loc_as_cell!(1),
             );
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-
-            assert_eq!(iter.next(), None);
-        }
-
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.push(pstr_loc_as_cell!(2));
-
-        let pstr_second_var_cell =
-            put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
-        let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
-
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
-
-        let h = wam.machine_st.heap.len() - 1;
-
-        {
-            let mut iter = stackful_post_order_iter::<NonListElider>(
-                &mut wam.machine_st.heap,
-                &mut wam.machine_st.stack,
-                h,
-            );
-
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                heap_loc_as_cell!(3),
+                pstr_loc_as_cell!(0)
             );
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-
             assert_eq!(iter.next(), None);
         }
 
-        wam.machine_st.heap.pop();
-        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)));
-
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+        wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
+        wam.machine_st.allocate_pstr("def").unwrap();
 
-        let h = wam.machine_st.heap.len() - 1;
+        wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
+        wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
 
         {
             let mut iter = stackful_post_order_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                h,
+                5,
             );
 
             assert_eq!(
-                iter.next().unwrap(),
-                fixnum_as_cell!(Fixnum::build_with(0i64))
+                unmark_cell_bits!(iter.next().unwrap()),
+                heap_loc_as_cell!(4),
             );
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                pstr_offset_as_cell!(0)
+                pstr_loc_as_cell!(heap_index!(3))
+            );
+            assert_eq!(
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(0)
             );
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-
             assert_eq!(iter.next(), None);
         }
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.pop();
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(1i64)));
-
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
-
-        let h = wam.machine_st.heap.len() - 1;
+        wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2);
 
         {
             let mut iter = stackful_post_order_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                h,
+                5,
             );
 
             assert_eq!(
-                iter.next().unwrap(),
-                fixnum_as_cell!(Fixnum::build_with(1i64))
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(heap_index!(3) + 2)
             );
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                pstr_offset_as_cell!(0)
+                pstr_loc_as_cell!(heap_index!(3) + 2)
+            );
+            assert_eq!(
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(heap_index!(3))
+            );
+            assert_eq!(
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(0)
             );
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-
             assert_eq!(iter.next(), None);
         }
 
         wam.machine_st.heap.clear();
 
-        let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
+        let functor = functor!(
+            f_atom,
+            [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)]
+        );
+
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(str_loc_as_cell!(5));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(str_loc_as_cell!(5));
+            section.push_cell(empty_list_as_cell!());
+        });
 
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut functor_writer = Heap::functor_writer(functor);
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
 
-        wam.machine_st.heap.extend(functor);
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
         {
             let mut iter = stackful_post_order_iter::<NonListElider>(
@@ -2827,7 +2694,7 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap[4] = list_loc_as_cell!(1);
 
@@ -2894,7 +2761,7 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
         wam.machine_st.heap.clear();
     }
 
@@ -2902,15 +2769,21 @@ mod tests {
     fn heap_stackless_post_order_iter() {
         let mut wam = MockWAM::new();
 
+        // clear the heap of resource error data etc
+        wam.machine_st.heap.clear();
+
         let f_atom = atom!("f");
         let a_atom = atom!("a");
         let b_atom = atom!("b");
 
-        wam.machine_st
-            .heap
-            .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+        let mut functor_writer = Heap::functor_writer(functor!(
+            f_atom,
+            [atom_as_cell(a_atom),
+             atom_as_cell(b_atom)]),
+        );
 
-        wam.machine_st.heap.push(str_loc_as_cell!(0));
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
         {
             let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 3);
@@ -2933,17 +2806,18 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.extend(functor!(
+        let mut functor_writer = Heap::functor_writer(functor!(
             f_atom,
             [
-                atom(a_atom),
-                atom(b_atom),
-                atom(a_atom),
-                cell(str_loc_as_cell!(0))
+                atom_as_cell(a_atom),
+                atom_as_cell(b_atom),
+                atom_as_cell(a_atom),
+                str_loc_as_cell(0)
             ]
         ));
 
-        wam.machine_st.heap.push(str_loc_as_cell!(0));
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
         for _ in 0..20 {
             let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 5);
@@ -2974,7 +2848,7 @@ mod tests {
         wam.machine_st.heap.clear();
 
         {
-            wam.machine_st.heap.push(heap_loc_as_cell!(0));
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap();
 
             let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0);
 
@@ -2989,8 +2863,8 @@ mod tests {
 
         {
             // mutually referencing variables.
-            wam.machine_st.heap.push(heap_loc_as_cell!(1));
-            wam.machine_st.heap.push(heap_loc_as_cell!(0));
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
+            wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap();
 
             let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0);
 
@@ -3010,11 +2884,15 @@ mod tests {
         wam.machine_st.heap.clear();
 
         // term  is: [a, b]
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(a_atom));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(atom_as_cell!(b_atom));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(a_atom));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(atom_as_cell!(b_atom));
+            section.push_cell(empty_list_as_cell!());
+        });
 
         {
             let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0);
@@ -3043,10 +2921,8 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        wam.machine_st.heap.pop();
-
         // now make the list cyclic.
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        wam.machine_st.heap[4] = heap_loc_as_cell!(0);
 
         {
             let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0);
@@ -3093,7 +2969,7 @@ mod tests {
             );
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1));
         assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
@@ -3107,11 +2983,10 @@ mod tests {
         // two-part complete string, then a three-part cyclic string
         // involving an uncompacted list of chars.
 
-        let pstr_var_cell =
-            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.allocate_pstr("abc ").unwrap();
 
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+        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 mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 2);
@@ -3120,108 +2995,68 @@ mod tests {
                 unmark_cell_bits!(iter.next().unwrap()),
                 heap_loc_as_cell!(1),
             );
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
+            assert_eq!(
+                unmark_cell_bits!(iter.next().unwrap()),
+                pstr_loc_as_cell!(0)
+            );
 
             assert_eq!(iter.next(), None);
         }
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.push(pstr_loc_as_cell!(2));
-
-        let pstr_second_var_cell =
-            put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
-
-        let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+        wam.machine_st.heap[2] = heap_loc_as_cell!(2);
+        wam.machine_st.allocate_pstr("def").unwrap();
 
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+        wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
 
         {
             let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4);
 
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                heap_loc_as_cell!(3),
+                heap_loc_as_cell!(1),
             );
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-
-            assert_eq!(iter.next(), None);
-        }
-
-        all_cells_unmarked(&wam.machine_st.heap);
-
-        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(0)));
-
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
-
-        {
-            let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7);
-            let mut pstr_loc_cell = pstr_loc_as_cell!(0);
-
-            pstr_loc_cell.set_forwarding_bit(true);
-
-            // assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64)));
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                heap_loc_as_cell!(3)
+                pstr_loc_as_cell!(0)
             );
-
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
-
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.pop();
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(1)));
-
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+        wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2);
 
         {
-            let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7);
+            let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4);
 
-            //assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1)));
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                heap_loc_as_cell!(3)
+                pstr_loc_as_cell!(heap_index!(3) + 2)
             );
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
-            assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
             assert_eq!(iter.next(), None);
         }
 
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
+
         wam.machine_st.heap.clear();
 
-        let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
+        let functor = functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)]);
 
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
 
-        wam.machine_st.heap.extend(functor);
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(str_loc_as_cell!(5));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(str_loc_as_cell!(5));
+            section.push_cell(empty_list_as_cell!());
+        });
 
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        let mut functor_writer = Heap::functor_writer(functor);
+        functor_writer(&mut wam.machine_st.heap).unwrap();
 
         {
-            let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 9);
+            let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0);
 
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
@@ -3264,7 +3099,7 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap[4] = list_loc_as_cell!(1);
 
@@ -3312,6 +3147,6 @@ mod tests {
             assert_eq!(iter.next(), None);
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
     }
 }
index 962c71ed95b64ad9849d3a7655055b7ac11f4ca7..d3598f791c18f36507e95c1b7cad5f14707fdd51 100644 (file)
@@ -9,7 +9,6 @@ use crate::forms::*;
 use crate::heap_iter::*;
 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::stack::*;
 use crate::machine::streams::*;
@@ -25,7 +24,6 @@ use std::convert::TryFrom;
 use std::iter::once;
 use std::net::{IpAddr, TcpListener};
 use std::rc::Rc;
-use std::sync::Arc;
 
 /* contains the location, name, precision and Specifier of the parent op. */
 #[derive(Debug, Copy, Clone)]
@@ -206,11 +204,12 @@ impl NumberFocus {
 
 #[derive(Debug, Clone, Copy)]
 struct CommaSeparatedCharList {
-    pstr: PartialString,
-    offset: usize,
+    // pstr: PartialString,
+    // offset: usize,
+    pstr_loc: usize,
     max_depth: usize,
-    end_cell: HeapCellValue,
-    end_h: Option<usize>,
+    // end_cell: HeapCellValue,
+    // end_h: Option<usize>,
 }
 
 #[derive(Debug, Clone)]
@@ -473,7 +472,6 @@ pub fn fmt_float(mut fl: f64) -> String {
 pub struct HCPrinter<'a, Outputter> {
     outputter: Outputter,
     iter: StackfulPreOrderHeapIter<'a, ListElider>,
-    atom_tbl: Arc<AtomTable>,
     op_dir: &'a OpDir,
     state_stack: Vec<TokenOrRedirect>,
     toplevel_spec: Option<DirectedOp>,
@@ -488,9 +486,19 @@ pub struct HCPrinter<'a, Outputter> {
     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 {
     ($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(' ');
             $action;
         } else {
@@ -528,7 +536,6 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String>
 impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
     pub fn new(
         heap: &'a mut Heap,
-        atom_tbl: Arc<AtomTable>,
         stack: &'a mut Stack,
         op_dir: &'a OpDir,
         output: Outputter,
@@ -537,7 +544,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         HCPrinter {
             outputter: output,
             iter: stackful_preorder_iter(heap, stack, root_loc),
-            atom_tbl,
             op_dir,
             state_stack: vec![],
             toplevel_spec: None,
@@ -553,17 +559,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>) {
         if let Some(op) = parent_op {
             if op.is_left() && op.is_prefix() {
@@ -1117,9 +1112,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
 
     // 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 {
-        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 char_count > 0 {
                     self.state_stack.push(TokenOrRedirect::Close);
@@ -1129,13 +1125,31 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                 return true;
             }
 
-            append_str!(self, "'.'");
-            push_char!(self, '(');
+            macro_rules! emit_char {
+                ($c:expr) => ({
+                    append_str!(self, "'.'");
+                    push_char!(self, '(');
 
-            print_char!(self, self.quoted, c);
-            push_char!(self, ',');
+                    print_char!(self, self.quoted, $c);
+                    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
@@ -1146,7 +1160,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
     fn print_proper_string(&mut self, focus: usize, max_depth: usize) {
         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| {
             // refrain from quoting characters other than '"' and '\'
             // unless self.quoted is true.
@@ -1158,19 +1173,43 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         };
 
         if max_depth == 0 {
-            for c in iter.chars() {
-                for c in char_to_string(c).chars() {
-                    push_char!(self, c);
+            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() {
+                        push_char!(self, c);
+                    }
                 }
             }
         } else {
             let mut char_count = 0;
 
-            for c in iter.chars().take(max_depth) {
-                char_count += 1;
+            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;
 
-                for c in char_to_string(c).chars() {
-                    push_char!(self, c);
+                    for c in char_to_string(c).chars() {
+                        push_char!(self, c);
+                    }
                 }
             }
 
@@ -1188,10 +1227,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                 self.iter.pop_stack();
                 self.iter.pop_stack();
             }
-            HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset => {
+            HeapCellValueTag::PStrLoc => {
                 self.iter.pop_stack();
             }
-            HeapCellValueTag::CStr => {}
+            // HeapCellValueTag::CStr => {}
             _ => {
                 unreachable!();
             }
@@ -1202,19 +1241,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         let focus = self.iter.focus();
         let mut heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus.value() as usize);
 
-        let next_h;
-        let next_hare;
-
-        if heap_pstr_iter.next().is_some() {
-            next_h = heap_pstr_iter.focus;
-            next_hare = heap_pstr_iter.focus();
+        let is_cyclic = if heap_pstr_iter.next().is_some() {
             for _ in heap_pstr_iter.by_ref() {}
+            heap_pstr_iter.is_cyclic()
         } else {
             return self.push_list(max_depth);
-        }
+        };
 
         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) {
             self.remove_list_children(focus.value() as usize);
@@ -1224,9 +1259,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
 
         let at_cdr = self.outputter.ends_with("|");
 
-        if self.double_quotes && !self.ignore_ops && end_cell.is_string_terminator(self.iter.heap) {
-            self.remove_list_children(focus.value() as usize);
-            return self.print_proper_string(focus.value() as usize, max_depth);
+        if self.double_quotes && !self.ignore_ops && !is_cyclic {
+            if end_cell.is_string_terminator(self.iter.heap) {
+                self.remove_list_children(focus.value() as usize);
+                return self.print_proper_string(focus.value() as usize, max_depth);
+            }
         }
 
         if self.ignore_ops {
@@ -1255,37 +1292,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                 (HeapCellValueTag::Lis) => {
                     self.push_list(max_depth)
                 }
-                _ => {
+                (HeapCellValueTag::PStrLoc, h) => {
                     let switch = Rc::new(Cell::new((!at_cdr, 0)));
                     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) {
-                        let pstr = cell_as_string!(self.iter.heap[h]);
-                        self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList(CommaSeparatedCharList {
-                            pstr, offset, max_depth, end_cell: next_h, end_h,
-                        }));
+                        self.state_stack.push(
+                            TokenOrRedirect::CommaSeparatedCharList(
+                                CommaSeparatedCharList {
+                                    pstr_loc: h, max_depth,
+                                }
+                            ),
+                        );
                     } else {
                         self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
                     }
 
                     self.open_list(switch);
                 }
+                _ => {
+                    unreachable!()
+                }
             );
         }
     }
@@ -1515,32 +1542,29 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
 
     fn print_comma_separated_char_list(&mut self, char_list: CommaSeparatedCharList) {
         let CommaSeparatedCharList {
-            pstr,
-            offset,
+            pstr_loc,
             max_depth,
-            end_cell,
-            end_h,
         } = char_list;
-        let pstr_str = pstr.as_str_from(offset);
 
-        if let Some(c) = pstr_str.chars().next() {
-            let offset = offset + c.len_utf8();
+        let c = self.iter.heap.char_at(pstr_loc);
+
+        if c != '\u{0}' || pstr_loc % std::mem::size_of::<HeapCellValue>() == 0 {
+            // if a null character in a pstr has location aligned
+            // to a cell boundary, the string is ['\\x0\\'].
 
             if !self.max_depth_exhausted(max_depth) {
                 self.state_stack
                     .push(TokenOrRedirect::CommaSeparatedCharList(
                         CommaSeparatedCharList {
-                            pstr,
-                            offset,
+                            pstr_loc: pstr_loc + c.len_utf8(),
                             max_depth: max_depth.saturating_sub(1),
-                            end_cell,
-                            end_h,
                         },
                     ));
 
                 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);
                 }
 
@@ -1552,14 +1576,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         } else if self.max_depth_exhausted(max_depth) {
             self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
             self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
-        } else if end_cell != empty_list_as_cell!() {
-            if let Some(end_h) = end_h {
-                self.iter
-                    .push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap));
+        } else {
+            /*
+            let end_cell_h = Heap::neighboring_cell_offset(pstr_loc);
+            let end_cell = self.iter.heap[end_cell_h];
+            let end_cell = heap_bound_store(
+                self.iter.heap,
+                heap_bound_deref(self.iter.heap, end_cell),
+            );
+
+            if end_cell != empty_list_as_cell!() {
+                self.iter.push_stack(
+                    IterStackLoc::iterable_loc(end_cell_h, HeapOrStackTag::Heap),
+                );
             }
+            */
 
-            self.state_stack
-                .push(TokenOrRedirect::FunctorRedirect(max_depth + 1));
+            self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth + 1));
             self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
         }
     }
@@ -1652,10 +1685,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
             (HeapCellValueTag::Atom, (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) => {
                 let (name, arity) = cell_as_atom_cell!(self.iter.heap[s])
                     .get_name_and_arity();
@@ -1682,7 +1717,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
             (HeapCellValueTag::F64, f) => {
                 self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(*f)), &op);
             }
-            (HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
+            (HeapCellValueTag::PStrLoc) => { // HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
                 self.print_list_like(max_depth);
             }
             (HeapCellValueTag::Lis) => {
@@ -1819,6 +1854,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
 mod tests {
     use super::*;
 
+    use crate::functor_macro::*;
     use crate::machine::mock_wam::*;
 
     #[test]
@@ -1826,25 +1862,30 @@ mod tests {
     fn term_printing_tests() {
         let mut wam = MockWAM::new();
 
+        // clear the heap of resource error data etc
+        wam.machine_st.heap.clear();
+
         let f_atom = atom!("f");
         let a_atom = atom!("a");
         let b_atom = atom!("b");
         let c_atom = atom!("c");
 
-        wam.machine_st
-            .heap
-            .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+        let mut functor_writer = Heap::functor_writer(functor!(
+            f_atom,
+            [atom_as_cell(a_atom),
+             atom_as_cell(b_atom)]),
+        );
 
-        wam.machine_st.heap.push(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(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
-                0,
+                3,
             );
 
             let output = printer.print();
@@ -1852,31 +1893,31 @@ mod tests {
             assert_eq!(output.result(), "f(a,b)");
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.extend(functor!(
+        let mut functor_writer = Heap::functor_writer(functor!(
             f_atom,
             [
-                atom(a_atom),
-                atom(b_atom),
-                atom(a_atom),
-                cell(str_loc_as_cell!(0))
+                atom_as_cell(a_atom),
+                atom_as_cell(b_atom),
+                atom_as_cell(a_atom),
+                str_loc_as_cell(0)
             ]
         ));
 
-        let h = wam.machine_st.heap.len();
-        wam.machine_st.heap.push(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(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
-                h,
+                5,
             );
 
             let output = printer.print();
@@ -1884,19 +1925,22 @@ mod tests {
             assert_eq!(output.result(), "f(a,b,a,...)");
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
         // print L = [L|L].
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
+        writer.write_with(|section| {
+            section.push_cell(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(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
@@ -1909,7 +1953,6 @@ mod tests {
 
             let mut printer = HCPrinter::new(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
@@ -1925,24 +1968,32 @@ mod tests {
             assert_eq!(output.result(), "[L|L]");
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         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();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(str_loc_as_cell!(5));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(str_loc_as_cell!(5));
+            section.push_cell(empty_list_as_cell!());
+        });
 
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(str_loc_as_cell!(5));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        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)]
+        ));
 
-        wam.machine_st.heap.extend(functor);
+        functor_writer(&mut wam.machine_st.heap).unwrap();
 
         {
             let printer = HCPrinter::new(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
@@ -1954,14 +2005,13 @@ mod tests {
             assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)]");
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap[4] = list_loc_as_cell!(1);
 
         {
             let printer = HCPrinter::new(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
@@ -1973,12 +2023,11 @@ mod tests {
             assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|...]");
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         {
             let mut printer = HCPrinter::new(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
@@ -1994,23 +2043,27 @@ mod tests {
             assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|L]");
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         // issue #382
         wam.machine_st.heap.clear();
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
 
-        for idx in 0..3000 {
-            wam.machine_st.heap.push(heap_loc_as_cell!(2 * idx + 1));
-            wam.machine_st.heap.push(list_loc_as_cell!(2 * idx + 2 + 1));
-        }
+        let mut writer = wam.machine_st.heap.reserve(6002).unwrap();
 
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+
+            for idx in 0..3000 {
+                section.push_cell(heap_loc_as_cell!(2 * idx + 1));
+                section.push_cell(list_loc_as_cell!(2 * idx + 2 + 1));
+            }
+
+            section.push_cell(empty_list_as_cell!());
+        });
 
         {
             let mut printer = HCPrinter::new(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
@@ -2024,24 +2077,22 @@ mod tests {
             assert_eq!(output.result(), "[_1,_3,_5,_7,_9|...]");
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        put_partial_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
-
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+        wam.machine_st.allocate_pstr("abc").unwrap();
 
-        let h = wam.machine_st.heap.len() - 1;
+        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(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
-                h,
+                2,
             );
 
             let output = printer.print();
@@ -2049,28 +2100,28 @@ mod tests {
             assert_eq!(output.result(), "[a,b,c|_1]");
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
-        wam.machine_st.heap.pop();
-        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.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!());
+        wam.machine_st.heap[1] = list_loc_as_cell!(3);
 
         {
             let mut printer = HCPrinter::new(
                 &mut wam.machine_st.heap,
-                Arc::clone(&wam.machine_st.atom_tbl),
                 &mut wam.machine_st.stack,
                 &wam.op_dir,
                 PrinterOutputter::new(),
-                0,
+                2,
             );
 
             printer.double_quotes = true;
@@ -2080,7 +2131,7 @@ mod tests {
             assert_eq!(output.result(), "\"abcabc\"");
         }
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
@@ -2089,14 +2140,14 @@ mod tests {
             "=(X,[a,b,c|X])"
         );
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             &wam.parse_and_print_term("[a,b,\"a\",[a,b,c]].").unwrap(),
             "[a,b,[a],[a,b,c]]"
         );
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             &wam.parse_and_print_term("[\"abc\",e,f,[g,e,h,Y,v|[X,Y]]].")
@@ -2104,11 +2155,11 @@ mod tests {
             "[[a,b,c],e,f,[g,e,h,Y,v,X,Y]]"
         );
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(&wam.parse_and_print_term("f((a,b)).").unwrap(), "f((a,b))");
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.op_dir
             .insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX));
@@ -2120,14 +2171,14 @@ mod tests {
             "[a|[]+b]"
         );
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             &wam.parse_and_print_term("[a|[b|c]*d].").unwrap(),
             "[a|[b|c]*d]"
         );
 
-        all_cells_unmarked(&wam.machine_st.heap);
+        all_cells_unmarked(wam.machine_st.heap.splice(..));
 
         wam.op_dir
             .insert((atom!("fy"), Fixity::Pre), OpDesc::build_with(9, FY));
index a199e625b43b6b6e2fb7e4a47c88e90afad3e90b..d9a4f036cbc7119713a782017acc6e3f5d1aa308 100644 (file)
@@ -1,7 +1,8 @@
 use crate::atom_table::*;
 use crate::forms::*;
 use crate::instructions::*;
-use crate::parser::ast::*;
+use crate::machine::heap::*;
+use crate::parser::ast::Fixnum;
 use crate::types::*;
 
 use fxhash::FxBuildHasher;
@@ -144,7 +145,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
     fn add_static_indexed_choice_for_constant(
         &mut self,
         external: usize,
-        constant: Literal,
+        constant: HeapCellValue,
         index: usize,
     ) {
         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(
         &mut self,
         external: usize,
-        constant: Literal,
+        constant: HeapCellValue,
         index: usize,
     ) {
         let third_level_index = if self.append_or_prepend.is_append() {
@@ -235,8 +236,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
 
     fn index_overlapping_constant(
         &mut self,
-        orig_constant: Literal,
-        overlapping_constant: Literal,
+        orig_constant: HeapCellValue,
+        overlapping_constant: HeapCellValue,
         index: usize,
     ) {
         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 {
             let indexing_code_len = self.indexing_code.len();
 
@@ -663,8 +664,8 @@ pub(crate) fn merge_clause_index(
 }
 
 pub(crate) fn remove_constant_indices(
-    constant: Literal,
-    overlapping_constants: &[Literal],
+    constant: HeapCellValue,
+    overlapping_constants: &[HeapCellValue],
     indexing_code: &mut [IndexingLine],
     offset: usize,
 ) {
@@ -1096,12 +1097,28 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
 }
 
 pub(crate) fn constant_key_alternatives(
-    constant: Literal,
-    atom_tbl: &AtomTable,
+    constant: HeapCellValue,
+    // atom_tbl: &AtomTable,
     // arena: &mut Arena,
-) -> Vec<Literal> {
+) -> Vec<HeapCellValue> {
     let mut constants = vec![];
 
+    match Number::try_from(constant) {
+        Ok(Number::Integer(n)) => {
+            let result = (&*n).try_into();
+            if let Ok(value) = result {
+                constants.push(
+                    Fixnum::build_with_checked(value)
+                        .map(|n| fixnum_as_cell!(n))
+                        .unwrap()
+                );
+            }
+        }
+        _ => {
+        }
+    }
+
+    /*
     match constant {
         Literal::Atom(ref name) => {
             if let Some(c) = name.as_char() {
@@ -1131,20 +1148,21 @@ pub(crate) fn constant_key_alternatives(
         }
         _ => {}
     }
+    */
 
     constants
 }
 
 #[derive(Debug)]
 pub(crate) struct StaticCodeIndices {
-    constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
+    constants: IndexMap<HeapCellValue, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
     lists: VecDeque<IndexedChoiceInstruction>,
     structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
 }
 
 #[derive(Debug)]
 pub(crate) struct DynamicCodeIndices {
-    constants: IndexMap<Literal, VecDeque<usize>, FxBuildHasher>,
+    constants: IndexMap<HeapCellValue, VecDeque<usize>, FxBuildHasher>,
     lists: VecDeque<usize>,
     structures: IndexMap<(Atom, usize), VecDeque<usize>, FxBuildHasher>,
 }
@@ -1156,7 +1174,7 @@ pub(crate) trait Indexer {
 
     fn constants(
         &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 structures(
         &mut self,
@@ -1204,7 +1222,7 @@ impl Indexer for StaticCodeIndices {
     #[inline]
     fn constants(
         &mut self,
-    ) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
+    ) -> &mut IndexMap<HeapCellValue, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
         &mut self.constants
     }
 
@@ -1328,7 +1346,7 @@ impl Indexer for DynamicCodeIndices {
     }
 
     #[inline]
-    fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>, FxBuildHasher> {
+    fn constants(&mut self) -> &mut IndexMap<HeapCellValue, VecDeque<usize>, FxBuildHasher> {
         &mut self.constants
     }
 
@@ -1449,11 +1467,10 @@ impl<I: Indexer> CodeOffsets<I> {
 
     fn index_constant(
         &mut self,
-        atom_tbl: &AtomTable,
-        constant: Literal,
+        constant: HeapCellValue,
         index: usize,
-    ) -> Vec<Literal> {
-        let overlapping_constants = constant_key_alternatives(constant, atom_tbl);
+    ) -> Vec<HeapCellValue> {
+        let overlapping_constants = constant_key_alternatives(constant);
         let code = self.indices.constants().entry(constant).or_default();
 
         let is_initial_index = code.is_empty();
@@ -1491,11 +1508,10 @@ impl<I: Indexer> CodeOffsets<I> {
 
     pub(crate) fn index_term(
         &mut self,
-        heap: &[HeapCellValue],
+        heap: &Heap,
         optimal_arg: HeapCellValue,
         index: usize,
         clause_index_info: &mut ClauseIndexInfo,
-        atom_tbl: &AtomTable,
     ) {
         read_heap_cell!(optimal_arg,
             (HeapCellValueTag::Str, s) => {
@@ -1514,36 +1530,32 @@ impl<I: Indexer> CodeOffsets<I> {
             (HeapCellValueTag::Atom, (name, arity)) => {
                 debug_assert_eq!(arity, 0);
 
-                let overlapping_constants = self.index_constant(atom_tbl, Literal::Atom(name), index);
+                let overlapping_constants = self.index_constant(atom_as_cell!(name), index);
 
                 clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
                     self.optimal_index,
                     0,
-                    Literal::Atom(name),
+                    atom_as_cell!(name),
                     overlapping_constants,
                 );
             }
             (HeapCellValueTag::Lis
-             | HeapCellValueTag::CStr
+             // | HeapCellValueTag::CStr
              | HeapCellValueTag::PStrLoc) => {
                 clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
                 self.index_list(index);
             }
-            _ => {
-                match Literal::try_from(optimal_arg) {
-                    Ok(lit) => {
-                        let overlapping_constants = self.index_constant(atom_tbl, lit, index);
-
-                        clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
-                            self.optimal_index,
-                            0,
-                            lit,
-                            overlapping_constants,
-                        );
-                    }
-                    _ => {}
-                }
+            _ if optimal_arg.is_constant() => {
+                let overlapping_constants = self.index_constant(optimal_arg, index);
+
+                clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
+                    self.optimal_index,
+                    0,
+                    optimal_arg,
+                    overlapping_constants,
+                );
             }
+            _ => {}
         );
     }
 
index c139f006de8b762ae9f7660db4e38925d68b3a62..b641c756c8b29ab26d063dc40132ce9feb663cce 100644 (file)
@@ -14,9 +14,7 @@ use std::iter::*;
 use std::ops::Deref;
 use std::vec::Vec;
 
-pub(crate) trait TermIterator:
-    Deref<Target = [HeapCellValue]> + Iterator<Item = HeapCellValue>
-{
+pub(crate) trait TermIterator: Deref<Target = Heap> + Iterator<Item = HeapCellValue> {
     fn focus(&self) -> IterStackLoc;
     fn level(&mut self) -> Level;
 }
@@ -30,7 +28,7 @@ pub(crate) struct TargetIterator<I: FocusedHeapIter, const SKIP_ROOT: bool> {
 }
 
 fn record_path(
-    heap: &[HeapCellValue],
+    heap: &impl SizedHeap,
     root_terms: &mut BitSet<usize>,
     mut root_loc: usize,
 ) -> usize {
@@ -47,9 +45,9 @@ fn record_path(
                 }
             }
             (HeapCellValueTag::Lis) => {
-               root_terms.insert(root_loc);
-               break;
-           }
+                       root_terms.insert(root_loc);
+                       break;
+               }
             _ => {
                 if cell.is_ref() {
                     root_terms.insert(cell.get_value() as usize);
@@ -63,14 +61,14 @@ fn record_path(
     root_loc
 }
 
-fn find_root_terms(heap: &[HeapCellValue], root_loc: usize) -> (usize, BitSet<usize>) {
+fn find_root_terms(heap: &impl SizedHeap, root_loc: usize) -> (usize, BitSet<usize>) {
     let mut root_terms = BitSet::<usize>::default();
     let root_loc = record_path(heap, &mut root_terms, root_loc);
     (root_loc, root_terms)
 }
 
 fn find_shallow_terms(
-    heap: &[HeapCellValue],
+    heap: &impl SizedHeap,
     root_loc: usize,
 ) -> IndexMap<usize, BitSet<usize>, FxBuildHasher> {
     let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default());
@@ -101,8 +99,8 @@ fn find_shallow_terms(
 
 impl<I: FocusedHeapIter, const SKIP_ROOT: bool> TargetIterator<I, SKIP_ROOT> {
     fn new(iter: I, root_loc: usize, arg_c: usize) -> Self {
-        let (derefed_root_loc, root_terms) = find_root_terms(&iter, root_loc);
-        let shallow_terms = find_shallow_terms(&iter, derefed_root_loc);
+        let (derefed_root_loc, root_terms) = find_root_terms(iter.deref(), root_loc);
+        let shallow_terms = find_shallow_terms(iter.deref(), derefed_root_loc);
 
         Self {
             shallow_terms,
@@ -184,7 +182,7 @@ impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Iterator for TargetIterator<I, S
 }
 
 impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Deref for TargetIterator<I, SKIP_ROOT> {
-    type Target = [HeapCellValue];
+    type Target = Heap;
 
     fn deref(&self) -> &Self::Target {
         self.iter.deref()
@@ -205,7 +203,6 @@ pub(crate) fn fact_iterator<'a, const SKIP_ROOT: bool>(
     stack: &'a mut Stack,
     root_loc: usize,
 ) -> FactIterator<'a, SKIP_ROOT> {
-    // let cell = heap[root_loc];
     TargetIterator::new(stackful_preorder_iter(heap, stack, root_loc), root_loc, 0)
 }
 
@@ -217,7 +214,6 @@ pub(crate) fn query_iterator<'a, const SKIP_ROOT: bool>(
     stack: &'a mut Stack,
     root_loc: usize,
 ) -> QueryIterator<'a, SKIP_ROOT> {
-    // let cell = heap[root_loc];
     TargetIterator::new(stackful_post_order_iter(heap, stack, root_loc), root_loc, 1)
 }
 
index 2a736a1ea8cf1f757eb0baec15696a5b01e91ee8..9dde8d9c357f3cca06176064aff9ffc4c77ee554 100644 (file)
@@ -11,9 +11,13 @@ pub(crate) mod macros;
 #[macro_use]
 pub(crate) mod atom_table;
 #[macro_use]
-pub(crate) mod arena;
+pub mod arena;
 #[macro_use]
 pub(crate) mod parser;
+pub mod types;
+#[macro_use]
+pub mod functor_macro;
+
 mod allocator;
 mod arithmetic;
 pub(crate) mod codegen;
@@ -38,7 +42,6 @@ pub(crate) mod read;
 #[cfg(feature = "repl")]
 mod repl_helper;
 mod targets;
-pub(crate) mod types;
 
 #[cfg(target_arch = "wasm32")]
 use wasm_bindgen::prelude::*;
index e3e25a6ab19925b2525ef07258158492db38ddec..9432c68103521f4e9c5b27b1922072aa6e302a4c 100644 (file)
@@ -125,7 +125,7 @@ call(_, _, _, _, _, _, _, _, _).
 %
 % 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
 %    to `false` since it supports unbounded integer arithmethic. Read only.
 %  * `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).
 %  * `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(max_arity, 1023).
+current_prolog_flag(Flag, Value) :- Flag == max_arity, !, Value = 255.
+current_prolog_flag(max_arity, 255).
 current_prolog_flag(Flag, Value) :- Flag == bounded, !, Value = false.
 current_prolog_flag(bounded, false).
 current_prolog_flag(Flag, Value) :- Flag == integer_rounding_function, !, Value == toward_zero.
index 69696794630e75b645cca9b5834da942982c5f2f..74c846838d97694c39f5bb64f5712047d8aeacba 100644 (file)
@@ -205,7 +205,6 @@ load_loop(Stream, Evacuable) :-
        read_term(Stream, Term, [singletons(Singletons)])
     ;  Term = end_of_file
     ),
-    % write('Term: '), writeq(Term), nl,
     (  Term == end_of_file ->
        close(Stream),
        '$conclude_load'(Evacuable)
@@ -219,7 +218,6 @@ load_loop(Stream, Evacuable) :-
 
 compile_term(Term, Evacuable) :-
     expand_terms_and_goals(Term, Terms),
-    % write('Terms: '), writeq(Terms),nl,
     !,
     (  var(Terms) ->
        instantiation_error(load/1)
@@ -300,7 +298,7 @@ expand_term_goals(Terms0, Terms) :-
           (  atom(Module) ->
              prolog_load_context(module, Target),
              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), _),
                    (  loader:print_goal_expansion_warning(Pred),
                       builtins:(Body1 = Body0)
@@ -310,7 +308,7 @@ expand_term_goals(Terms0, Terms) :-
           )
        ;  module_expanded_head_variables(Head1, HeadVars),
           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), _),
                 (  loader:print_goal_expansion_warning(Pred),
                    builtins:(Body1 = Body0)
index 9410c1cd9fc0a9a60d7f6e53a39076c97797f667..2d1bb0bef7d9b81390923e2c26665c70653257bf 100644 (file)
@@ -48,7 +48,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| {
         let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor);
         let stub = stub_gen();
@@ -57,7 +57,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| {
         let eval_error = machine_st.evaluation_error(EvalError::Undefined);
         let stub = stub_gen();
@@ -69,7 +69,7 @@ fn undefined_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> Machine
 fn numerical_type_error(
     valid_type: ValidType,
     n: Number,
-    stub_gen: impl Fn() -> FunctorStub + 'static,
+    stub_gen: impl Fn() -> MachineStub + 'static,
 ) -> MachineStubGen {
     Box::new(move |machine_st| {
         let type_error = machine_st.type_error(valid_type, n);
@@ -522,7 +522,7 @@ pub(crate) fn min(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
 
 pub fn rational_from_number(
     n: Number,
-    stub_gen: impl Fn() -> FunctorStub + 'static,
+    stub_gen: impl Fn() -> MachineStub + 'static,
     arena: &mut Arena,
 ) -> Result<TypedArenaPtr<Rational>, MachineStubGen> {
     match n {
@@ -1117,7 +1117,7 @@ impl MachineState {
     pub fn get_rational(
         &mut self,
         at: &ArithmeticTerm,
-        caller: impl Fn() -> FunctorStub + 'static,
+        caller: impl Fn() -> MachineStub + 'static,
     ) -> Result<TypedArenaPtr<Rational>, MachineStub> {
         let n = self.get_number(at)?;
 
@@ -1131,6 +1131,8 @@ impl MachineState {
         &mut self,
         value: HeapCellValue,
     ) -> Result<Number, MachineStub> {
+        debug_assert!(value.is_ref());
+
         let stub_gen = || functor_stub(atom!("is"), 2);
 
         let root_loc = if value.is_ref() && !value.is_stack_var() {
@@ -1155,7 +1157,7 @@ impl MachineState {
                      (HeapCellValueTag::Str, s) => {
                          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) => {
                          (atom!("."), 2)
                      }
@@ -1435,7 +1437,7 @@ mod tests {
             parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap();
 
         assert_eq!(
-            wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
+            wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)),
             Ok(Number::Fixnum(Fixnum::build_with(8))),
         );
 
@@ -1445,7 +1447,7 @@ mod tests {
             parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap();
 
         assert_eq!(
-            wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
+            wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)),
             Ok(Number::Fixnum(Fixnum::build_with(19))),
         );
 
@@ -1455,7 +1457,7 @@ mod tests {
             parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap();
 
         assert_eq!(
-            wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
+            wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)),
             Ok(Number::Fixnum(Fixnum::build_with(-1)))
         );
     }
index c288511b66d6893bf12a39521faebb4f25401fb1..584abc80642e39c180cb983f40e8499bf84a4c35 100644 (file)
@@ -38,6 +38,7 @@ verify_attrs([], _, _, []).
 
 
 call_goals([ListOfGoalLists | ListsCubed]) :-
+    '$debug_hook',
     call_goals_0(ListOfGoalLists),
     call_goals(ListsCubed).
 call_goals([]).
index 794c0e76e89c7179b8c9b455e621cecf886ed141..6b5ae9b309ed307279ea22e1ec017752c8b0a836 100644 (file)
@@ -6,7 +6,6 @@ use crate::types::*;
 use indexmap::IndexSet;
 
 use std::cmp::Ordering;
-use std::vec::IntoIter;
 
 pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
 
@@ -55,32 +54,36 @@ impl MachineState {
         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
             .attr_var_init
             .bindings
             .iter()
             .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 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 {
             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!(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() {
             vec![]
         } else {
@@ -104,10 +107,10 @@ impl MachineState {
         });
 
         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);
 
         let e = self.e;
@@ -121,14 +124,18 @@ impl MachineState {
         and_frame[arity + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
         and_frame[arity + 3] = fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
 
-        self.verify_attributes();
+        self.verify_attributes()?;
 
         self.num_of_args = 3;
         self.b0 = self.b;
         self.p = p;
+
+        Ok(())
     }
 
     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_vars = vec![];
         let root_loc = if cell.is_ref() {
index 983f59615eb4c848a561209905a54a7b14127b40..71beaa47a41e388e86fa11411b15de49b00f5029 100644 (file)
@@ -1232,15 +1232,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 
     fn compile_standalone_clause(
         &mut self,
-        term: FocusedHeap,
+        term: TermWriteResult,
         settings: CodeGenSettings,
     ) -> Result<StandaloneCompileResult, SessionError> {
         let mut preprocessor = Preprocessor::new(settings);
 
-        let clause = self.try_term_to_tl(term, &mut preprocessor)?;
-        let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
+        let clause = preprocessor.try_term_to_tl(self, term)?;
+        let machine_st = LS::machine_st(&mut self.payload);
+        let mut cg = CodeGenerator::new(settings);
 
-        let clause_code = cg.compile_predicate(vec![clause])?;
+        let clause_code = cg.compile_predicate(&mut machine_st.heap, vec![clause])?;
 
         Ok(StandaloneCompileResult {
             clause_code,
@@ -1265,11 +1266,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         let mut preprocessor = Preprocessor::new(settings);
 
         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 mut code = cg.compile_predicate(clauses)?;
+        let machine_st = LS::machine_st(&mut self.payload);
+
+        let mut cg = CodeGenerator::new(settings);
+        let mut code = cg.compile_predicate(&mut machine_st.heap, clauses)?;
 
         if settings.is_extensible {
             let mut clause_clause_locs = VecDeque::new();
@@ -1466,7 +1469,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
     pub(super) fn incremental_compile_clause(
         &mut self,
         key: PredicateKey,
-        clause: FocusedHeap,
+        clause: TermWriteResult,
         compilation_target: CompilationTarget,
         non_counted_bt: bool,
         append_or_prepend: AppendOrPrepend,
@@ -2005,7 +2008,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         &mut self,
         key: PredicateKey,
         compilation_target: CompilationTarget,
-        clause_clauses: Vec<FocusedHeap>,
+        clause_clauses: Vec<TermWriteResult>,
         append_or_prepend: AppendOrPrepend,
     ) -> Result<(), SessionError> {
         let clause_clause_compilation_target = match compilation_target {
@@ -2099,15 +2102,19 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
     }
 
     pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> {
-        let key = self
+        let key = match self
             .payload
             .predicates
             .first()
-            .and_then(|cl| {
-                let arity = ClauseInfo::arity(cl);
-                ClauseInfo::name(cl).map(|name| (name, arity))
-            })
-            .ok_or(SessionError::NamelessEntry)?;
+            .map(|term| term.focus) {
+                Some(focus) => {
+                    clause_predicate_key(self.machine_heap(), focus)
+                        .ok_or(SessionError::NamelessEntry)?
+                }
+                None => {
+                    return Err(SessionError::NamelessEntry);
+                }
+            };
 
         let listing_src_file_name = self.listing_src_file_name();
 
@@ -2285,34 +2292,40 @@ impl Machine {
     ) -> Result<(), SessionError> {
         let body_cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg]));
 
-        let new_header_loc = self.machine_st.heap.len();
+        let new_header_loc = self.machine_st.heap.cell_len();
         let arity = vars.len();
+        let term_loc = self.machine_st.heap.cell_len() + 1 + arity;
 
-        self.machine_st.heap.push(atom_as_cell!(atom!(""), arity));
+        let mut writer = self.machine_st.heap.reserve(4 + arity)
+            .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
 
-        for var in vars {
-            self.machine_st.heap.push(var);
-        }
+        writer.write_with(move |section| {
+            section.push_cell(atom_as_cell!(atom!(""), arity));
 
-        let head_loc = if arity > 0 {
-            str_loc_as_cell!(new_header_loc)
-        } else {
-            heap_loc_as_cell!(new_header_loc)
-        };
+            for var in vars {
+                section.push_cell(var);
+            }
 
-        let term_loc = self.machine_st.heap.len();
+            let head_loc = if arity > 0 {
+                str_loc_as_cell!(new_header_loc)
+            } else {
+                heap_loc_as_cell!(new_header_loc)
+            };
 
-        self.machine_st.heap.push(atom_as_cell!(atom!(":-"), 2));
-        self.machine_st.heap.push(head_loc);
-        self.machine_st.heap.push(body_cell);
+            section.push_cell(atom_as_cell!(atom!(":-"), 2));
+            section.push_cell(head_loc);
+            section.push_cell(body_cell);
+        });
 
         let mut compile = || {
-            use crate::heap_iter::eager_stackful_preorder_iter;
-
             let mut loader: Loader<'_, InlineLoadState<'_>> =
                 Loader::new(self, InlineTermStream {});
 
-            let mut term = loader.copy_term_from_heap(str_loc_as_cell!(term_loc));
+            let machine_st = InlineLoadState::machine_st(&mut loader.payload);
+
+            let term_loc = str_loc_as_cell!(term_loc);
+            let term = TermWriteResult::from(&mut machine_st.heap, term_loc)
+                .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
 
             let settings = CodeGenSettings {
                 global_clock_tick: None,
@@ -2320,12 +2333,6 @@ impl Machine {
                 non_counted_bt: true,
             };
 
-            let value = term.heap[term.focus];
-
-            term.inverse_var_locs = inverse_var_locs_from_iter(
-                eager_stackful_preorder_iter(&mut term.heap, value),
-            );
-
             loader.compile_standalone_clause(term, settings)
         };
 
index c02854ffdcb24212eee874b65720915b8cde5737..5bb2fe900df5bf430afc5047f5d406228d70bf9c 100644 (file)
@@ -1,10 +1,11 @@
 use crate::atom_table::*;
 use crate::machine::get_structure_index;
+use crate::machine::heap::*;
 use crate::machine::stack::*;
 use crate::types::*;
 
 use std::mem;
-use std::ops::IndexMut;
+use std::ops::{IndexMut, Range};
 
 type Trail = Vec<(Ref, HeapCellValue)>;
 
@@ -17,22 +18,31 @@ pub enum AttrVarPolicy {
 pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
     fn store(&self, value: HeapCellValue) -> HeapCellValue;
     fn deref(&self, value: HeapCellValue) -> HeapCellValue;
-    fn push(&mut self, value: HeapCellValue);
+    // fn push_cell(&mut self, value: HeapCellValue) -> Result<(), usize>;
     fn push_attr_var_queue(&mut self, attr_var_loc: usize);
     fn stack(&mut self) -> &mut Stack;
     fn threshold(&self) -> usize;
+    // returns the tail location of the pstr on success
+    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize>;
+    fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize;
+    fn pstr_at(&self, loc: usize) -> bool;
+    fn next_non_pstr_cell_index(&self, loc: 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>(
     target: T,
     addr: HeapCellValue,
     attr_var_policy: AttrVarPolicy,
-) {
+) -> Result<(), usize> {
     let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
 
-    copy_term_state.copy_term_impl(addr);
-    copy_term_state.copy_attr_var_lists();
+    copy_term_state.copy_term_impl(addr)?;
+    copy_term_state.copy_attr_var_lists()?;
     copy_term_state.unwind_trail();
+
+    Ok(())
 }
 
 #[derive(Debug)]
@@ -67,14 +77,14 @@ impl<T: CopierTarget> CopyTermState<T> {
         self.trail.push((Ref::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 {
             read_heap_cell!(self.target[addr + offset],
                 (HeapCellValueTag::Lis, h) => {
                     if h >= self.old_h {
                         *self.value_at_scan() = list_loc_as_cell!(h);
                         self.scan += 1;
-                        return;
+                        return Ok(());
                     }
                 }
                 _ => {
@@ -83,14 +93,10 @@ impl<T: CopierTarget> CopyTermState<T> {
         }
 
         let threshold = self.target.threshold();
+        self.target.copy_slice_to_end(addr .. addr + 2)?;
 
         *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
             .target
             .store(self.target.deref(heap_loc_as_cell!(addr + 1)));
@@ -113,80 +119,72 @@ impl<T: CopierTarget> CopyTermState<T> {
         }
 
         self.scan += 1;
+        Ok(())
     }
 
-    fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) {
-        read_heap_cell!(self.target[pstr_loc],
-            (HeapCellValueTag::PStrLoc, h) => {
-                debug_assert!(h >= self.old_h);
+    /*
+     * write a null byte to the first word of a partial string to
+     * flag that it has been copied followed by the copied
+     * string's index in the next 7 bytes. write the bytes in big
+     * endian order so that the null byte is at index 0.
+     */
+    fn write_pstr_index(&mut self, head_cell_idx: usize, threshold: usize) {
+        let bytes = u64::to_be_bytes(threshold as u64);
+        debug_assert_eq!(bytes[0], 0);
+        self.target[head_cell_idx] = HeapCellValue::from_bytes(bytes);
+    }
 
-                *self.value_at_scan() = match scan_tag {
-                    HeapCellValueTag::PStrLoc => {
-                        pstr_loc_as_cell!(h)
-                    }
-                    tag => {
-                        debug_assert_eq!(tag, HeapCellValueTag::PStrOffset);
-                        pstr_offset_as_cell!(h)
-                    }
-                };
+    fn copy_partial_string(&mut self, pstr_loc: usize) -> Result<(), usize> {
+        let head_cell_idx = self.target.pstr_head_cell_index(pstr_loc);
+        let head_byte_idx = heap_index!(head_cell_idx);
+        let pstr_offset = pstr_loc - head_byte_idx;
 
-                self.scan += 1;
-                return;
-            }
-            (HeapCellValueTag::Var, h) => {
-                debug_assert!(h >= self.old_h);
-                debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
+        // if a partial string has been copied previously, we
+        // track it by writing a null byte to its first word, which is trailed,
+        // and then the new pstr_loc in the word's remaining 7 bytes. see write_pstr_index
+        // comment.
 
-                *self.value_at_scan() = pstr_offset_as_cell!(h);
-                self.scan += 1;
+        if self.target[head_cell_idx].into_bytes()[0] == 0u8 {
+            let head_bytes = self.target[head_cell_idx].into_bytes();
+            let new_pstr_loc = u64::from_be_bytes(head_bytes) as usize;
 
-                return;
-            }
-            _ => {}
-        );
+            *self.value_at_scan() = pstr_loc_as_cell!(heap_index!(new_pstr_loc) + pstr_offset);
+            self.scan += 1;
+            return Ok(());
+        }
 
         let threshold = self.target.threshold();
+        let tail_loc = self.target.copy_pstr_to_threshold(head_byte_idx)?;
 
-        let replacement = read_heap_cell!(self.target[pstr_loc],
-            (HeapCellValueTag::CStr) => {
-                debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
+        *self.value_at_scan() = pstr_loc_as_cell!(heap_index!(threshold) + pstr_offset);
 
-                *self.value_at_scan() = pstr_offset_as_cell!(threshold);
-                self.target.push(self.target[pstr_loc]);
+        self.trail.push((Ref::heap_cell(head_cell_idx), self.target[head_cell_idx]));
+        self.write_pstr_index(head_cell_idx, threshold);
 
-                heap_loc_as_cell!(threshold)
-            }
-            _ => {
-                *self.value_at_scan() = if scan_tag == HeapCellValueTag::PStrLoc {
-                    pstr_loc_as_cell!(threshold)
-                } else {
-                    debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
-                    pstr_offset_as_cell!(threshold)
-                };
+        let tail_cell = self.target[tail_loc];
+        let mut writer = self.target.reserve(1)?;
 
-                self.target.push(self.target[pstr_loc]);
-                self.target.push(self.target[pstr_loc + 1]);
-
-                pstr_loc_as_cell!(threshold)
-            }
-        );
+        writer.write_with(|section| {
+            section.push_cell(tail_cell);
+        });
 
         self.scan += 1;
 
-        let trail_item = mem::replace(&mut self.target[pstr_loc], replacement);
-        self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
+        Ok(())
     }
 
-    fn copy_attr_var_lists(&mut self) {
+    fn copy_attr_var_lists(&mut self) -> Result<(), usize> {
         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.push_attr_var_queue(threshold - 1);
-                self.copy_attr_var_list(list_loc);
+                self.copy_attr_var_list(list_loc)?;
             }
         }
+
+        Ok(())
     }
 
     /*
@@ -194,36 +192,36 @@ impl<T: CopierTarget> CopyTermState<T> {
      * structure which is ensured by this function and not at all by
      * 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() {
             let threshold = self.target.threshold();
             let heap_loc = list_addr.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));
-            self.target.push(heap_loc_as_cell!(threshold + 1));
+            writer.write_with(|section| {
+                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],
-                (HeapCellValueTag::Atom) => {
-                    self.target.push(self.target[str_loc]);
-                }
-                (HeapCellValueTag::Str) => {
-                    self.copy_term_impl(self.target[str_loc]);
-                }
-                _ => {
-                    unreachable!();
+                if str_cell.to_atom().is_some() {
+                    section.push_cell(str_cell);
                 }
-            );
+            });
 
+            debug_assert_eq!(str_cell.get_tag(), HeapCellValueTag::Str);
+            self.copy_term_impl(str_cell)?;
             list_addr = self.target[heap_loc + 1];
 
             if HeapCellValueTag::Lis == list_addr.get_tag() {
                 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,
             (HeapCellValueTag::Var, h) => {
                 self.target[frontier] = heap_loc_as_cell!(frontier);
@@ -250,8 +248,12 @@ impl<T: CopierTarget> CopyTermState<T> {
                 self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h)));
 
                 if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
-                    self.target.push(attr_var_as_cell!(threshold));
-                    self.target.push(heap_loc_as_cell!(threshold + 1));
+                    let mut writer = self.target.reserve(2).unwrap();
+
+                    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];
                     self.trail.push((Ref::heap_cell(h + 1), old_list_link));
@@ -266,9 +268,11 @@ impl<T: CopierTarget> CopyTermState<T> {
                 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 rd = self.target.deref(addr);
         let ra = self.target.store(rd);
@@ -278,7 +282,7 @@ impl<T: CopierTarget> CopyTermState<T> {
                 if h >= self.old_h {
                     *self.value_at_scan() = ra;
                     self.scan += 1;
-                    return;
+                    return Ok(());
                 }
             }
             (HeapCellValueTag::Lis, h) => {
@@ -292,46 +296,57 @@ impl<T: CopierTarget> CopyTermState<T> {
                     );
 
                     self.scan += 1;
-                    return;
+                    return Ok(());
                 }
             }
             _ => {}
         );
 
         if rd == ra {
-            self.reinstantiate_var(ra, self.scan);
+            self.reinstantiate_var(ra, self.scan)?;
             self.scan += 1;
         } else {
             *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],
-            (HeapCellValueTag::Atom, (name, arity)) => {
+            (HeapCellValueTag::Atom, (_name, arity)) => {
                 let threshold = self.target.threshold();
 
                 *self.value_at_scan() = str_loc_as_cell!(threshold);
 
+                self.target.copy_slice_to_end(addr .. addr + 1 + arity)?;
+
                 let trail_item = mem::replace(
                     &mut self.target[addr],
                     str_loc_as_cell!(threshold),
                 );
 
                 self.trail.push((Ref::heap_cell(addr), trail_item));
+/*
                 self.target.push(atom_as_cell!(name, arity));
 
                 for i in 0..arity {
                     let hcv = self.target[addr + 1 + i];
                     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);
+*/
+                if !self.target.pstr_at(addr + 1 + arity) {
+                    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.
+                        let mut writer = self.target.reserve(1).unwrap();
+
+                        writer.write_with(|section| {
+                            section.push_cell(index_cell);
+                        });
+                    }
                 }
             }
             (HeapCellValueTag::Str, h) => {
@@ -343,37 +358,51 @@ impl<T: CopierTarget> CopyTermState<T> {
         );
 
         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.target.push(addr);
+        let mut writer = self.target.reserve(1)?;
+
+        writer.write_with(|section| {
+            section.push_cell(addr);
+        });
 
         while self.scan < self.target.threshold() {
+            if self.target.pstr_at(self.scan) {
+                self.scan = self.target.next_non_pstr_cell_index(self.scan);
+                continue;
+            }
+
             let addr = *self.value_at_scan();
 
             read_heap_cell!(addr,
                 (HeapCellValueTag::Lis, h) => {
                     if h >= self.old_h {
                         self.scan += 1;
+                        continue;
                     } else {
-                        self.copy_list(h);
+                        self.copy_list(h)
                     }
                 }
                 (HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
-                    self.copy_var(addr);
+                    self.copy_var(addr)
                 }
                 (HeapCellValueTag::Str, h) => {
-                    self.copy_structure(h);
+                    self.copy_structure(h)
                 }
-                (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => {
-                    self.copy_partial_string(addr.get_tag(), pstr_loc);
+                (HeapCellValueTag::PStrLoc, pstr_loc) => {
+                    self.copy_partial_string(pstr_loc)
                 }
                 _ => {
                     self.scan += 1;
+                    continue;
                 }
-            );
+            )?;
         }
+
+        Ok(())
     }
 
     fn unwind_trail(mut self) {
@@ -395,19 +424,25 @@ impl<T: CopierTarget> CopyTermState<T> {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use crate::functor_macro::*;
     use crate::machine::mock_wam::*;
 
     #[test]
     fn copier_tests() {
         let mut wam = MockWAM::new();
 
+        // clear the heap of resource error data etc
+        wam.machine_st.heap.clear();
+
         let f_atom = atom!("f");
         let a_atom = atom!("a");
         let b_atom = atom!("b");
 
-        wam.machine_st
-            .heap
-            .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+        let mut functor_writer = Heap::functor_writer(
+            functor!(f_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[1], atom_as_cell!(a_atom));
@@ -415,7 +450,7 @@ mod tests {
 
         {
             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.
@@ -430,69 +465,62 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
-        let pstr_var_cell =
-            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];
+        let mut writer = wam.machine_st.heap.reserve(4).unwrap();
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+        writer.write_with(|section| {
+            section.push_pstr("abc ");
+            section.push_cell(pstr_loc_as_cell!(heap_index!(2)));
 
-        let pstr_second_var_cell =
-            put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
-        let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
-
-        wam.machine_st.heap.pop();
-        wam.machine_st
-            .heap
-            .push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
-
-        wam.machine_st.heap.push(pstr_offset_as_cell!(0));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(0i64)));
+            section.push_pstr("def");
+            section.push_cell(pstr_loc_as_cell!(0));
+        });
 
         {
             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[0], pstr_cell);
-        assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2));
-        assert_eq!(wam.machine_st.heap[2], pstr_second_cell);
-        assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4));
-        assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0));
         assert_eq!(
-            wam.machine_st.heap[5],
-            fixnum_as_cell!(Fixnum::build_with(0i64))
+            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.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!(5)));
 
-        assert_eq!(wam.machine_st.heap[7], pstr_cell);
-        assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9));
-        assert_eq!(wam.machine_st.heap[9], pstr_second_cell);
-        assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11));
-        assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7));
         assert_eq!(
-            wam.machine_st.heap[12],
-            fixnum_as_cell!(Fixnum::build_with(0i64))
+            wam.machine_st.heap.slice_to_str(heap_index!(5), "abc ".len()),
+            "abc "
         );
+        assert_eq!(wam.machine_st.heap[6], pstr_loc_as_cell!(heap_index!(7)));
+        assert_eq!(
+            wam.machine_st.heap.slice_to_str(heap_index!(7), "def".len()),
+            "def"
+        );
+        assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(heap_index!(5)));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.extend(functor!(
+        let mut functor_writer = Heap::functor_writer(functor!(
             f_atom,
             [
-                atom(a_atom),
-                atom(b_atom),
-                atom(a_atom),
-                cell(str_loc_as_cell!(0))
+                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);
+            copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
         }
 
         assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4));
index 6df242ac60de54d357d1cee785fad02656465021..99ae40b4606dddba17a3619984347bc560b45e3c 100644 (file)
@@ -1,4 +1,5 @@
 use crate::atom_table::*;
+use crate::machine::heap::*;
 use crate::types::*;
 
 /* 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
  * - 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
- *   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
  *   phase
  *
@@ -22,7 +23,7 @@ use crate::types::*;
 
 #[derive(Debug)]
 pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> {
-    pub(crate) heap: &'a mut [HeapCellValue],
+    pub(crate) heap: &'a mut Heap,
     start: usize,
     current: usize,
     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> {
-    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);
         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.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));
                         }
                     }
@@ -205,8 +206,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
                     }
                     HeapCellValueTag::PStrLoc => {
                         let h = self.next as usize;
-                        let cell = self.heap[h];
-                        let last_cell_loc = h + 1;
+                        let (_, last_cell_loc) = self.heap.scan_slice_to_str(h);
 
                         if self.heap[last_cell_loc].get_forwarding_bit() {
                             if self.cycle_detection_active() {
@@ -225,39 +225,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
                         self.heap[last_cell_loc].set_value(self.current as u64);
                         self.current = last_cell_loc;
 
-                        return Some(cell);
-                    }
-                    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);
+                        return Some(pstr_loc_as_cell!(h));
                     }
                     tag @ HeapCellValueTag::Atom => {
                         let cell = HeapCellValue::build_with(tag, self.next);
@@ -269,11 +237,6 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
                             return None;
                         }
                     }
-                    HeapCellValueTag::PStr => {
-                        if self.backward() {
-                            return None;
-                        }
-                    }
                     _ => {
                         return Some(self.backward_and_return());
                     }
index d7f351554af2134a328d3119b2d398e17574620f..a7b2a128947e49a9efc63e459679da683e8b911e 100644 (file)
@@ -3,6 +3,7 @@ use crate::forms::*;
 use crate::instructions::*;
 use crate::iterators::fact_iterator;
 use crate::machine::Stack;
+use crate::machine::heap::*;
 use crate::machine::loader::*;
 use crate::machine::machine_errors::CompilationError;
 use crate::machine::preprocessor::*;
@@ -320,13 +321,12 @@ impl VariableClassifier {
         }
     }
 
-    pub fn classify_fact(
+    pub fn classify_fact<'a, LS: LoadState<'a>>(
         mut self,
-        term: &mut FocusedHeap,
+        loader: &mut Loader<'a, LS>,
+        term: &TermWriteResult,
     ) -> Result<ClassifyFactResult, CompilationError> {
-        let focus = term.focus;
-        self.classify_head_variables(term, focus)?;
-
+        self.classify_head_variables(loader, &term, term.focus)?;
         Ok(self.branch_map.separate_and_classify_variables(
             self.var_num,
             self.global_cut_var_num,
@@ -337,12 +337,14 @@ impl VariableClassifier {
     pub fn classify_rule<'a, LS: LoadState<'a>>(
         mut self,
         loader: &mut Loader<'a, LS>,
-        term: &mut FocusedHeap,
+        term: &TermWriteResult,
     ) -> Result<ClassifyRuleResult, CompilationError> {
-        let head_loc = term.nth_arg(term.focus, 1).unwrap();
-        let body_loc = term.nth_arg(term.focus, 2).unwrap();
+        let heap = &mut LS::machine_st(&mut loader.payload).heap;
+
+        let head_loc = term_nth_arg(heap, term.focus, 1).unwrap();
+        let body_loc = term_nth_arg(heap, term.focus, 2).unwrap();
 
-        self.classify_head_variables(term, head_loc)?;
+        self.classify_head_variables(loader, &term, head_loc)?;
         self.root_set.insert(self.current_branch_num.clone());
 
         let mut query_terms = self.classify_body_variables(loader, term, body_loc)?;
@@ -385,8 +387,8 @@ impl VariableClassifier {
         &mut self,
         arg_c: usize,
         arity: usize,
-        term: &mut FocusedHeap,
-        term_loc: usize,
+        term: &mut FocusedHeapRefMut,
+        inverse_var_locs: &InverseVarLocs,
         context: GenContext,
     ) {
         let classify_info = ClassifyInfo { arg_c, arity };
@@ -394,9 +396,9 @@ impl VariableClassifier {
         let mut lvl = Level::Shallow;
         let mut stack = Stack::uninitialized();
         let mut iter = fact_iterator::<false>(
-            &mut term.heap,
+            term.heap,
             &mut stack,
-            term_loc,
+            term.focus,
         );
 
         // second arg is true to iterate the root, which may be a variable
@@ -407,7 +409,7 @@ impl VariableClassifier {
             }
 
             let var_loc = subterm.get_value() as usize;
-            let var = to_classified_var(&term.inverse_var_locs, var_loc);
+            let var = to_classified_var(inverse_var_locs, var_loc);
 
             self.probe_body_var(
                 context,
@@ -468,27 +470,21 @@ impl VariableClassifier {
         self.probe_body_var(context, var_info);
     }
 
-    fn classify_head_variables(
+    fn classify_head_variables<'a, LS: LoadState<'a>>(
         &mut self,
-        term: &mut FocusedHeap,
+        loader: &mut Loader<'a, LS>,
+        term: &TermWriteResult,
         head_loc: usize,
     ) -> Result<(), CompilationError> {
-        let arity = read_heap_cell!(term.deref_loc(head_loc),
-            (HeapCellValueTag::Str, s) => {
-                cell_as_atom_cell!(term.heap[s]).get_arity()
-            }
-            (HeapCellValueTag::Atom) => {
-                return Ok(());
-            }
-            _ => {
-                return Err(CompilationError::InvalidRuleHead);
-            }
-        );
+        let heap = &mut LS::machine_st(&mut loader.payload).heap;
+        let arity = term_predicate_key(heap, head_loc)
+            .and_then(|(_, arity)| Some(arity))
+            .ok_or(CompilationError::InvalidRuleHead)?;
 
         let mut classify_info = ClassifyInfo { arg_c: 1, arity };
 
         if arity > 0 {
-            let (_term_loc, value) = subterm_index(&term.heap, head_loc);
+            let (_term_loc, value) = subterm_index(heap, head_loc);
             let str_offset = value.get_value() as usize;
 
             debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str);
@@ -497,7 +493,7 @@ impl VariableClassifier {
                 let mut lvl = Level::Shallow;
                 let mut stack = Stack::uninitialized();
                 let mut iter = fact_iterator::<false>(
-                    &mut term.heap,
+                    heap,
                     &mut stack,
                     idx,
                 );
@@ -571,11 +567,11 @@ impl VariableClassifier {
     fn classify_body_variables<'a, LS: LoadState<'a>>(
         &mut self,
         loader: &mut Loader<'a, LS>,
-        terms: &mut FocusedHeap,
+        terms: &TermWriteResult,
         term_loc: usize,
     ) -> Result<ChunkedTermVec, CompilationError> {
         let mut state_stack = vec![TraversalState::Term {
-            subterm: terms.heap[term_loc],
+            subterm: loader.machine_heap()[term_loc],
             term_loc,
         }];
         let mut build_stack = ChunkedTermVec::new();
@@ -684,13 +680,21 @@ impl VariableClassifier {
                             for (arg_c, term_loc) in
                                 ($term_loc + 1 ..= $term_loc + $key.1).enumerate()
                             {
-                                self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context);
+                                let mut term = FocusedHeapRefMut::from(loader.machine_heap(), term_loc);
+
+                                self.probe_body_term(
+                                    arg_c + 1,
+                                    $key.1,
+                                    &mut term,
+                                    &terms.inverse_var_locs,
+                                    context,
+                                );
                             }
 
                             build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
                                 loader,
                                 $key,
-                                terms.as_ref_mut($term_loc),
+                                &terms,
                                 HeapCellValue::build_with($tag, $term_loc as u64),
                                 self.call_policy,
                             )));
@@ -706,9 +710,17 @@ impl VariableClassifier {
                             let context = build_stack.current_gen_context();
 
                             for (arg_c, term_loc) in
-                                ($term_loc + 1..$term_loc + $key.1 + 1).enumerate()
+                                ($term_loc + 1 ..= $term_loc + $key.1).enumerate()
                             {
-                                self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context);
+                                let mut term = FocusedHeapRefMut::from(loader.machine_heap(), term_loc);
+
+                                self.probe_body_term(
+                                    arg_c + 1,
+                                    $key.1,
+                                    &mut term,
+                                    &terms.inverse_var_locs,
+                                    context,
+                                );
                             }
 
                             build_stack.push_chunk_term(QueryTerm::Clause(
@@ -716,7 +728,7 @@ impl VariableClassifier {
                                     loader,
                                     $key,
                                     $module_name,
-                                    terms.as_ref_mut($term_loc),
+                                    &terms,
                                     HeapCellValue::build_with($tag, $term_loc as u64),
                                     self.call_policy,
                                 ),
@@ -725,26 +737,28 @@ impl VariableClassifier {
                     }
 
                     loop {
+                        let heap = loader.machine_heap();
+
                         read_heap_cell!(subterm,
                             (HeapCellValueTag::Str, subterm_loc) => {
-                                let (name, arity) = cell_as_atom_cell!(terms.heap[subterm_loc])
+                                let (name, arity) = cell_as_atom_cell!(heap[subterm_loc])
                                     .get_name_and_arity();
 
                                 match (name, arity) {
                                     (atom!("->") | atom!(";") | atom!(","), 3) => {
-                                        if blunt_index_ptr(&mut terms.heap, (name, 2), subterm_loc) {
-                                            subterm = terms.heap[subterm_loc];
+                                        if blunt_index_ptr(heap, (name, 2), subterm_loc) {
+                                            subterm = heap[subterm_loc];
                                             continue;
                                         }
 
                                         add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc);
                                     }
                                     (atom!(","), 2) => {
-                                        let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
-                                        let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap();
-                                        let head = terms.heap[head_loc];
+                                        let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
+                                        let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap();
+                                        let head = heap[head_loc];
 
-                                        let iter = unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(","))
+                                        let iter = unfold_by_str_locs(heap, tail_loc, atom!(","))
                                             .into_iter()
                                             .rev()
                                             .chain(std::iter::once((head, head_loc)))
@@ -754,15 +768,15 @@ impl VariableClassifier {
                                         state_stack.extend(iter);
                                     }
                                     (atom!(";"), 2) => {
-                                        let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
-                                        let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap();
+                                        let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
+                                        let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap();
 
-                                        let head = terms.heap[head_loc];
+                                        let head = heap[head_loc];
 
                                         let first_branch_num = self.current_branch_num.split();
                                         let branches: Vec<_> = std::iter::once((head, head_loc))
                                             .chain(
-                                                unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(";"))
+                                                unfold_by_str_locs(heap, tail_loc, atom!(";"))
                                                     .into_iter(),
                                             )
                                             .collect();
@@ -807,11 +821,11 @@ impl VariableClassifier {
                                         build_stack.current_chunk_num += 1;
                                     }
                                     (atom!("->"), 2) => {
-                                        let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
-                                        let then_term_loc = terms.nth_arg(subterm_loc, 2).unwrap();
+                                        let if_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
+                                        let then_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap();
 
-                                        let if_term = terms.heap[if_term_loc];
-                                        let then_term = terms.heap[then_term_loc];
+                                        let if_term = heap[if_term_loc];
+                                        let then_term = heap[then_term_loc];
 
                                         let prev_b = if matches!(
                                             state_stack.last(),
@@ -851,8 +865,8 @@ impl VariableClassifier {
                                         self.var_num += 1;
                                     }
                                     (atom!("\\+"), 1) => {
-                                        let not_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
-                                        let not_term = terms.heap[not_term_loc];
+                                        let not_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
+                                        let not_term = heap[not_term_loc];
                                         let build_stack_len = build_stack.len();
 
                                         build_stack.reserve_branch(2);
@@ -886,18 +900,19 @@ impl VariableClassifier {
                                         self.var_num += 1;
                                     }
                                     (atom!(":"), 2) => {
-                                        let module_name_loc = terms.nth_arg(subterm_loc, 1).unwrap();
-                                        let predicate_term_loc = terms.nth_arg(subterm_loc, 2).unwrap();
+                                        let module_name_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
+                                        let predicate_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap();
+                                        let mut focused = FocusedHeapRefMut::from(heap, module_name_loc);
 
-                                        let module_name = terms.deref_loc(module_name_loc);
-                                        let predicate_term = terms.deref_loc(predicate_term_loc);
+                                        let module_name = focused.deref_loc(module_name_loc);
+                                        let predicate_term = focused.deref_loc(predicate_term_loc);
 
                                         read_heap_cell!(module_name,
                                             (HeapCellValueTag::Atom, (module_name, arity)) => {
                                                 if arity == 0 {
                                                     read_heap_cell!(predicate_term,
                                                         (HeapCellValueTag::Str, s) => {
-                                                            let key = cell_as_atom_cell!(terms.heap[s])
+                                                            let key = cell_as_atom_cell!(heap[s])
                                                                 .get_name_and_arity();
 
                                                             add_qualified_chunk!(
@@ -933,25 +948,40 @@ impl VariableClassifier {
 
                                         let context = build_stack.current_gen_context();
 
-                                        self.probe_body_term(1, 0, terms, module_name_loc, context);
-                                        self.probe_body_term(2, 0, terms, predicate_term_loc, context);
+                                        focused.focus = module_name_loc;
 
-                                        let h = terms.heap.len();
+                                        self.probe_body_term(
+                                            1, 0, &mut focused, &terms.inverse_var_locs, context,
+                                        );
+
+                                        focused.focus = predicate_term_loc;
+
+                                        self.probe_body_term(
+                                            2, 0, &mut focused, &terms.inverse_var_locs, context,
+                                        );
+
+                                        let h = heap.cell_len();
 
-                                        terms.heap.push(atom_as_cell!(atom!("call"), 1));
-                                        terms.heap.push(str_loc_as_cell!(subterm_loc));
+                                        heap.push_cell(atom_as_cell!(atom!("call"), 1))
+                                            .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+                                        heap.push_cell(str_loc_as_cell!(subterm_loc))
+                                            .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
 
                                         build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
                                             loader,
                                             (atom!("call"), 1),
-                                            terms.as_ref_mut(h),
+                                            terms,
                                             str_loc_as_cell!(h),
                                             self.call_policy,
                                         )));
                                     }
                                     (atom!("$call_with_inference_counting"), 1) => {
-                                        let term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
-                                        let subterm  = terms.deref_loc(term_loc);
+                                        let term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
+                                        let heap = loader.machine_heap();
+                                        let subterm = heap_bound_store(
+                                            heap,
+                                            heap_bound_deref(heap, heap[term_loc]),
+                                        );
 
                                         state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
                                         state_stack.push(TraversalState::Term { subterm, term_loc });
@@ -973,17 +1003,9 @@ impl VariableClassifier {
                                     add_chunk!((name, 0), HeapCellValueTag::Var, term_loc);
                                 }
                             }
-                            (HeapCellValueTag::Char, c) => {
-                                if c == '!' {
-                                    let context = build_stack.current_gen_context();
-                                    state_stack.push(self.new_cut_state(context));
-                                } else {
-                                    return Err(CompilationError::InadmissibleQueryTerm);
-                                }
-                            }
                             (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
                                 if h != term_loc {
-                                    subterm = terms.heap[h];
+                                    subterm = heap[h];
                                     term_loc = h;
                                     continue;
                                 }
index de40d8b7d45249dc5dfb011db01321044f8a86bd..3f9dc80ff91a3840285147445821077430f3a3d3 100644 (file)
@@ -1,5 +1,6 @@
 use crate::arena::*;
 use crate::atom_table::*;
+use crate::functor_macro::*;
 use crate::instructions::*;
 use crate::machine::arithmetic_ops::*;
 use crate::machine::machine_errors::*;
@@ -24,7 +25,10 @@ macro_rules! try_or_throw {
         match $e {
             Ok(val) => val,
             Err(msg) => {
-                $s.throw_exception(msg);
+                if !msg.is_empty() {
+                    $s.throw_exception(msg);
+                }
+
                 $s.backtrack();
                 continue;
             }
@@ -32,6 +36,15 @@ macro_rules! try_or_throw {
     }};
 }
 
+macro_rules! backtrack_on_resource_error {
+    ($machine_st:expr, $val:expr) => {
+        step_or_resource_error!($machine_st, $val, {
+            $machine_st.backtrack();
+            continue;
+        })
+    };
+}
+
 macro_rules! increment_call_count {
     ($s:expr) => {{
         if !$s.increment_call_count() {
@@ -55,6 +68,15 @@ macro_rules! try_or_throw_gen {
     }};
 }
 
+macro_rules! push_cell {
+    ($machine_st:expr, $cell:expr) => {{
+        step_or_resource_error!($machine_st, $machine_st.heap.push_cell($cell), {
+            $machine_st.backtrack();
+            continue;
+        })
+    }};
+}
+
 static INSTRUCTIONS_PER_INTERRUPT_POLL: usize = 256;
 
 impl MachineState {
@@ -113,12 +135,15 @@ impl MachineState {
     }
 
     pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) {
-        let old_h = self.heap.len();
+        let old_h = self.heap.cell_len();
 
         let a1 = self.registers[1];
         let a2 = self.registers[2];
 
-        copy_term(CopyTerm::new(self), a1, attr_var_policy);
+        step_or_resource_error!(
+            self,
+            copy_term(CopyTerm::new(self), a1, attr_var_policy)
+        );
 
         unify_fn!(*self, heap_loc_as_cell!(old_h), a2);
     }
@@ -135,10 +160,16 @@ impl MachineState {
 
         list.dedup_by(|v1, v2| compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal));
 
-        let heap_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, list.into_iter()));
+        let heap_addr = resource_error_call_result!(
+            self,
+            sized_iter_to_heap_list(
+                &mut self.heap,
+                list.len(),
+                list.into_iter(),
+            )
+        );
 
         let target_addr = self.registers[2];
-
         unify_fn!(*self, target_addr, heap_addr);
         Ok(())
     }
@@ -160,8 +191,14 @@ impl MachineState {
             compare_term_test!(self, a1.0, a2.0, var_comparison).unwrap_or(Ordering::Less)
         });
 
-        let key_pairs = key_pairs.into_iter().map(|kp| kp.1);
-        let heap_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, key_pairs));
+        let heap_addr = resource_error_call_result!(
+            self,
+            sized_iter_to_heap_list(
+                &mut self.heap,
+                key_pairs.len(),
+                key_pairs.into_iter().map(|kp| kp.1),
+            )
+        );
 
         let target_addr = self.registers[2];
 
@@ -201,13 +238,13 @@ impl MachineState {
                 v
             }
             (HeapCellValueTag::PStrLoc |
-             HeapCellValueTag::Lis |
-             HeapCellValueTag::CStr) => {
+             HeapCellValueTag::Lis) => {
+             // HeapCellValueTag::CStr) => {
                 l
             }
             (HeapCellValueTag::Fixnum |
              HeapCellValueTag::CutPoint |
-             HeapCellValueTag::Char |
+             // HeapCellValueTag::Char |
              HeapCellValueTag::F64) => {
                 c
             }
@@ -242,6 +279,7 @@ impl MachineState {
         )
     }
 
+    /*
     #[inline(always)]
     pub(crate) fn constant_to_literal(&self, addr: HeapCellValue) -> Literal {
         read_heap_cell!(addr,
@@ -288,6 +326,7 @@ impl MachineState {
             }
         )
     }
+    */
 
     #[inline(always)]
     pub(crate) fn select_switch_on_structure_index(
@@ -464,9 +503,9 @@ impl Machine {
                     }
                 }
                 IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
-                    let lit = self.machine_st.constant_to_literal(addr);
+                    // let lit = self.machine_st.constant_to_literal(addr);
 
-                    let offset = match hm.get(&lit) {
+                    let offset = match hm.get(&addr) {
                         Some(offset) => *offset,
                         _ => IndexingCodePtr::Fail,
                     };
@@ -1213,22 +1252,32 @@ impl Machine {
                         self.machine_st.allocate(num_cells);
                     }
                     &Instruction::DefaultCallAcyclicTerm => {
-                        let addr = self.machine_st.registers[1];
+                        let addr = self.deref_register(1);
 
-                        if self.machine_st.is_cyclic_term(addr) {
-                            self.machine_st.backtrack();
-                        } else {
-                            self.machine_st.p += 1;
+                        if addr.is_ref() {
+                            self.machine_st.heap[0] = addr;
+
+                            if self.machine_st.is_cyclic_term(0) {
+                                self.machine_st.backtrack();
+                                continue;
+                            }
                         }
+
+                        self.machine_st.p += 1;
                     }
                     &Instruction::DefaultExecuteAcyclicTerm => {
-                        let addr = self.machine_st.registers[1];
+                        let addr = self.deref_register(1);
 
-                        if self.machine_st.is_cyclic_term(addr) {
-                            self.machine_st.backtrack();
-                        } else {
-                            self.machine_st.p = self.machine_st.cp;
+                        if addr.is_ref() {
+                            self.machine_st.heap[0] = addr;
+
+                            if self.machine_st.is_cyclic_term(0) {
+                                self.machine_st.backtrack();
+                                continue;
+                            }
                         }
+
+                        self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::DefaultCallArg => {
                         try_or_throw!(self.machine_st, self.machine_st.try_arg());
@@ -1465,24 +1514,34 @@ impl Machine {
                         step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallAcyclicTerm => {
-                        let addr = self.machine_st.registers[1];
+                        let addr = self.deref_register(1);
 
-                        if self.machine_st.is_cyclic_term(addr) {
-                            self.machine_st.backtrack();
-                        } else {
-                            increment_call_count!(self.machine_st);
-                            self.machine_st.p += 1;
+                        if addr.is_ref() {
+                            self.machine_st.heap[0] = addr;
+
+                            if self.machine_st.is_cyclic_term(0) {
+                                self.machine_st.backtrack();
+                                continue;
+                            }
                         }
+
+                        increment_call_count!(self.machine_st);
+                        self.machine_st.p += 1;
                     }
                     &Instruction::ExecuteAcyclicTerm => {
-                        let addr = self.machine_st.registers[1];
+                        let addr = self.deref_register(1);
 
-                        if self.machine_st.is_cyclic_term(addr) {
-                            self.machine_st.backtrack();
-                        } else {
-                            increment_call_count!(self.machine_st);
-                            self.machine_st.p = self.machine_st.cp;
+                        if addr.is_ref() {
+                            self.machine_st.heap[0] = addr;
+
+                            if self.machine_st.is_cyclic_term(0) {
+                                self.machine_st.backtrack();
+                                continue;
+                            }
                         }
+
+                        increment_call_count!(self.machine_st);
+                        self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::CallArg => {
                         try_or_throw!(self.machine_st, self.machine_st.try_arg());
@@ -2250,9 +2309,11 @@ impl Machine {
                                     self.machine_st.backtrack();
                                 }
                             }
+                            /*
                             (HeapCellValueTag::Char) => {
                                 self.machine_st.p += 1;
                             }
+                            */
                             _ => {
                                 self.machine_st.backtrack();
                             }
@@ -2281,9 +2342,11 @@ impl Machine {
                                     self.machine_st.backtrack();
                                 }
                             }
+                            /*
                             (HeapCellValueTag::Char) => {
                                 self.machine_st.p = self.machine_st.cp;
                             }
+                            */
                             _ => {
                                 self.machine_st.backtrack();
                             }
@@ -2295,7 +2358,7 @@ impl Machine {
                             .store(self.machine_st.deref(self.machine_st[r]));
 
                         read_heap_cell!(d,
-                            (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 |
+                            (HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | // HeapCellValueTag::Char |
                              HeapCellValueTag::Cons) => {
                                 self.machine_st.p += 1;
                             }
@@ -2327,7 +2390,7 @@ impl Machine {
                             .store(self.machine_st.deref(self.machine_st[r]));
 
                         read_heap_cell!(d,
-                            (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 |
+                            (HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | // HeapCellValueTag::Char |
                              HeapCellValueTag::Cons) => {
                                 self.machine_st.p = self.machine_st.cp;
                             }
@@ -2360,8 +2423,8 @@ impl Machine {
 
                         read_heap_cell!(d,
                             (HeapCellValueTag::Lis |
-                             HeapCellValueTag::PStrLoc |
-                             HeapCellValueTag::CStr) => {
+                             HeapCellValueTag::PStrLoc) => {
+                             // HeapCellValueTag::CStr) => {
                                 self.machine_st.p += 1;
                             }
                             (HeapCellValueTag::Str, s) => {
@@ -2393,8 +2456,8 @@ impl Machine {
 
                         read_heap_cell!(d,
                             (HeapCellValueTag::Lis |
-                             HeapCellValueTag::PStrLoc |
-                             HeapCellValueTag::CStr) => {
+                             HeapCellValueTag::PStrLoc) => {
+                             // HeapCellValueTag::CStr) => {
                                 self.machine_st.p = self.machine_st.cp;
                             }
                             (HeapCellValueTag::Str, s) => {
@@ -2632,8 +2695,6 @@ impl Machine {
                     &Instruction::CallNamed(arity, name, ref idx) => {
                         let idx = idx.get();
 
-                        // println!("calling {}/{}", name.as_str(), arity);
-
                         try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
 
                         if self.machine_st.fail {
@@ -2645,8 +2706,6 @@ impl Machine {
                     &Instruction::ExecuteNamed(arity, name, ref idx) => {
                         let idx = idx.get();
 
-                        // println!("executing {}/{}", name.as_str(), arity);
-
                         try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
 
                         if self.machine_st.fail {
@@ -2658,8 +2717,6 @@ impl Machine {
                     &Instruction::DefaultCallNamed(arity, name, ref idx) => {
                         let idx = idx.get();
 
-                        // println!("calling {}/{}", name.as_str(), arity);
-
                         try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
 
                         if self.machine_st.fail {
@@ -2669,8 +2726,6 @@ impl Machine {
                     &Instruction::DefaultExecuteNamed(arity, name, ref idx) => {
                         let idx = idx.get();
 
-                        // println!("executing {}/{}", name.as_str(), arity);
-
                         try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
 
                         if self.machine_st.fail {
@@ -2688,8 +2743,7 @@ impl Machine {
                         self.machine_st.p = self.machine_st.cp;
                     }
                     &Instruction::GetConstant(_, c, reg) => {
-                        let value = self.machine_st.deref(self.machine_st[reg]);
-                        self.machine_st.write_literal_to_var(value, c);
+                        unify!(self.machine_st, self.machine_st[reg], c);
                         step_or_fail!(self, self.machine_st.p += 1);
                     }
                     &Instruction::GetList(_, reg) => {
@@ -2698,17 +2752,7 @@ impl Machine {
 
                         read_heap_cell!(store_v,
                             (HeapCellValueTag::PStrLoc, h) => {
-                                let (h, n) = pstr_loc_and_offset(&self.machine_st.heap, h);
-
-                                self.machine_st.s = HeapPtr::PStrChar(h, n.get_num() as usize);
-                                self.machine_st.s_offset = 0;
-                                self.machine_st.mode = MachineMode::Read;
-                            }
-                            (HeapCellValueTag::CStr) => {
-                                let h = self.machine_st.heap.len();
-                                self.machine_st.heap.push(store_v);
-
-                                self.machine_st.s = HeapPtr::PStrChar(h, 0);
+                                self.machine_st.s = HeapPtr::PStr(h);
                                 self.machine_st.s_offset = 0;
                                 self.machine_st.mode = MachineMode::Read;
                             }
@@ -2731,9 +2775,9 @@ impl Machine {
                                 self.machine_st.mode = MachineMode::Read;
                             }
                             (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                                let h = self.machine_st.heap.len();
+                                let h = self.machine_st.heap.cell_len();
 
-                                self.machine_st.heap.push(list_loc_as_cell!(h+1));
+                                push_cell!(self.machine_st, list_loc_as_cell!(h+1));
                                 self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
 
                                 self.machine_st.mode = MachineMode::Write;
@@ -2746,29 +2790,61 @@ impl Machine {
 
                         self.machine_st.p += 1;
                     }
-                    &Instruction::GetPartialString(_, string, reg, has_tail) => {
+                    &Instruction::GetPartialString(_, ref string, reg) => {
+                        use crate::machine::partial_string::{HeapPStrIter, PStrCmpResult};
+
                         let deref_v = self.machine_st.deref(self.machine_st[reg]);
                         let store_v = self.machine_st.store(deref_v);
 
                         read_heap_cell!(store_v,
                             (HeapCellValueTag::Str |
                              HeapCellValueTag::Lis |
-                             HeapCellValueTag::PStrLoc |
-                             HeapCellValueTag::CStr) => {
-                                self.machine_st.match_partial_string(store_v, string, has_tail);
+                             HeapCellValueTag::PStrLoc) => {
+                                debug_assert!(store_v.is_ref());
+
+                                self.machine_st.heap[0] = store_v;
+                                let heap_pstr_iter = HeapPStrIter::new(&self.machine_st.heap, 0);
+
+                                match heap_pstr_iter.compare_pstr_to_string(string) {
+                                    Some(PStrCmpResult::CompletePStrMatch { chars_matched, pstr_loc }) => {
+                                        self.machine_st.s_offset = chars_matched;
+                                        self.machine_st.s = HeapPtr::PStr(pstr_loc);
+                                        self.machine_st.mode = MachineMode::Read;
+                                    }
+                                    Some(PStrCmpResult::PartialPStrMatch { string, var_loc }) => {
+                                        let cell = backtrack_on_resource_error!(
+                                            self.machine_st,
+                                            self.machine_st.allocate_pstr(string)
+                                        );
+
+                                        self.machine_st.mode = MachineMode::Write;
+                                        unify!(self.machine_st, cell, heap_loc_as_cell!(var_loc));
+                                    }
+                                    Some(PStrCmpResult::ListMatch { list_loc }) => {
+                                        self.machine_st.s_offset = 0;
+                                        self.machine_st.s = HeapPtr::HeapCell(list_loc);
+                                        self.machine_st.mode = MachineMode::Read;
+                                    }
+                                    None => {
+                                        self.machine_st.backtrack();
+                                        continue;
+                                    }
+                                }
                             }
                             (HeapCellValueTag::AttrVar |
                              HeapCellValueTag::StackVar |
                              HeapCellValueTag::Var) => {
-                                let target_cell = self.machine_st.push_str_to_heap(
-                                    &string.as_str(),
-                                    has_tail,
+                                let target_cell = backtrack_on_resource_error!(
+                                    self.machine_st,
+                                    self.machine_st.allocate_pstr(string)
                                 );
 
                                 self.machine_st.bind(
                                     store_v.as_var().unwrap(),
                                     target_cell,
                                 );
+
+                                self.machine_st.mode = MachineMode::Write;
                             }
                             _ => {
                                 self.machine_st.backtrack();
@@ -2801,10 +2877,10 @@ impl Machine {
                                 );
                             }
                             (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                                let h = self.machine_st.heap.len();
+                                let h = self.machine_st.heap.cell_len();
 
-                                self.machine_st.heap.push(str_loc_as_cell!(h+1));
-                                self.machine_st.heap.push(atom_as_cell!(name, arity));
+                                push_cell!(self.machine_st, str_loc_as_cell!(h+1));
+                                push_cell!(self.machine_st, atom_as_cell!(name, arity));
 
                                 self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
                                 self.machine_st.mode = MachineMode::Write;
@@ -2838,8 +2914,7 @@ impl Machine {
                         match self.machine_st.mode {
                             MachineMode::Read => {
                                 let addr = self.machine_st.read_s();
-
-                                self.machine_st.write_literal_to_var(addr, v);
+                                unify!(&mut self.machine_st, addr, v);
 
                                 if self.machine_st.fail {
                                     self.machine_st.backtrack();
@@ -2849,7 +2924,7 @@ impl Machine {
                                 }
                             }
                             MachineMode::Write => {
-                                self.machine_st.heap.push(v);
+                                push_cell!(self.machine_st, v);
                             }
                         }
 
@@ -2874,17 +2949,17 @@ impl Machine {
                                 let value = self
                                     .machine_st
                                     .store(self.machine_st.deref(self.machine_st[reg]));
-                                let h = self.machine_st.heap.len();
+                                let h = self.machine_st.heap.cell_len();
 
                                 read_heap_cell!(value,
                                     (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => {
                                         let value = self.machine_st.heap[hc];
 
-                                        self.machine_st.heap.push(value);
+                                        push_cell!(self.machine_st, value);
                                         self.machine_st.s_offset += 1;
                                     }
                                     _ => {
-                                        self.machine_st.heap.push(heap_loc_as_cell!(h));
+                                        push_cell!(self.machine_st, heap_loc_as_cell!(h));
                                         (self.machine_st.bind_fn)(
                                             &mut self.machine_st,
                                             Ref::heap_cell(h),
@@ -2900,13 +2975,14 @@ impl Machine {
                     &Instruction::UnifyVariable(reg) => {
                         match self.machine_st.mode {
                             MachineMode::Read => {
-                                self.machine_st[reg] = self.machine_st.read_s();
+                                let value = self.machine_st.read_s();
+                                self.machine_st[reg] = value;
                                 self.machine_st.s_offset += 1;
                             }
                             MachineMode::Write => {
-                                let h = self.machine_st.heap.len();
+                                let h = self.machine_st.heap.cell_len();
 
-                                self.machine_st.heap.push(heap_loc_as_cell!(h));
+                                push_cell!(self.machine_st, heap_loc_as_cell!(h));
                                 self.machine_st[reg] = heap_loc_as_cell!(h);
                             }
                         }
@@ -2929,8 +3005,8 @@ impl Machine {
                                 }
                             }
                             MachineMode::Write => {
-                                let h = self.machine_st.heap.len();
-                                self.machine_st.heap.push(heap_loc_as_cell!(h));
+                                let h = self.machine_st.heap.cell_len();
+                                push_cell!(self.machine_st, heap_loc_as_cell!(h));
 
                                 let addr = self.machine_st.store(self.machine_st[reg]);
                                 (self.machine_st.bind_fn)(
@@ -2942,7 +3018,7 @@ impl Machine {
                                 // the former code of this match arm was:
 
                                 // let addr = self.machine_st.store(self.machine_st[reg]);
-                                // self.machine_st.heap.push(HeapCellValue::Addr(addr));
+                                // push_cell!(self.machine_st, HeapCellValue::Addr(addr));
 
                                 // the old code didn't perform the occurs
                                 // check when enabled and so it was changed to
@@ -2959,10 +3035,10 @@ impl Machine {
                                 self.machine_st.s_offset += n;
                             }
                             MachineMode::Write => {
-                                let h = self.machine_st.heap.len();
+                                let h = self.machine_st.heap.cell_len();
 
                                 for i in h..h + n {
-                                    self.machine_st.heap.push(heap_loc_as_cell!(i));
+                                    push_cell!(self.machine_st, heap_loc_as_cell!(i));
                                 }
                             }
                         }
@@ -3094,38 +3170,26 @@ impl Machine {
                             }
                         }
                     }
-                    &Instruction::PutConstant(_, c, reg) => {
-                        self.machine_st[reg] = c;
+                    &Instruction::PutConstant(_, cell, reg) => {
+                        self.machine_st[reg] = cell;
                         self.machine_st.p += 1;
                     }
                     &Instruction::PutList(_, reg) => {
-                        self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.len());
+                        self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.cell_len());
                         self.machine_st.p += 1;
                     }
-                    &Instruction::PutPartialString(_, string, reg, has_tail) => {
-                        let pstr_addr = if has_tail {
-                            if string != atom!("") {
-                                let h = self.machine_st.heap.len();
-                                self.machine_st.heap.push(string_as_pstr_cell!(string));
-
-                                // the tail will be pushed by the next
-                                // instruction, so don't push one here.
-
-                                pstr_loc_as_cell!(h)
-                            } else {
-                                empty_list_as_cell!()
-                            }
-                        } else {
-                            string_as_cstr_cell!(string)
-                        };
+                    &Instruction::PutPartialString(_, ref string, reg) => {
+                        self.machine_st[reg] = backtrack_on_resource_error!(
+                            self.machine_st,
+                            self.machine_st.allocate_pstr(&string)
+                        );
 
-                        self.machine_st[reg] = pstr_addr;
                         self.machine_st.p += 1;
                     }
                     &Instruction::PutStructure(name, arity, reg) => {
-                        let h = self.machine_st.heap.len();
+                        let h = self.machine_st.heap.cell_len();
 
-                        self.machine_st.heap.push(atom_as_cell!(name, arity));
+                        push_cell!(self.machine_st, atom_as_cell!(name, arity));
                         self.machine_st[reg] = str_loc_as_cell!(h);
 
                         self.machine_st.p += 1;
@@ -3139,9 +3203,9 @@ impl Machine {
                         if addr.is_protected(self.machine_st.e) {
                             self.machine_st.registers[arg] = addr;
                         } else {
-                            let h = self.machine_st.heap.len();
+                            let h = self.machine_st.heap.cell_len();
 
-                            self.machine_st.heap.push(heap_loc_as_cell!(h));
+                            push_cell!(self.machine_st, heap_loc_as_cell!(h));
                             (self.machine_st.bind_fn)(
                                 &mut self.machine_st,
                                 Ref::heap_cell(h),
@@ -3165,8 +3229,8 @@ impl Machine {
                                 self.machine_st.registers[arg] = self.machine_st[norm];
                             }
                             RegType::Temp(_) => {
-                                let h = self.machine_st.heap.len();
-                                self.machine_st.heap.push(heap_loc_as_cell!(h));
+                                let h = self.machine_st.heap.cell_len();
+                                push_cell!(self.machine_st, heap_loc_as_cell!(h));
 
                                 self.machine_st[norm] = heap_loc_as_cell!(h);
                                 self.machine_st.registers[arg] = heap_loc_as_cell!(h);
@@ -3176,7 +3240,7 @@ impl Machine {
                         self.machine_st.p += 1;
                     }
                     &Instruction::SetConstant(c) => {
-                        self.machine_st.heap.push(c);
+                        push_cell!(self.machine_st, c);
                         self.machine_st.p += 1;
                     }
                     &Instruction::SetLocalValue(reg) => {
@@ -3184,37 +3248,37 @@ impl Machine {
                         let stored_v = self.machine_st.store(addr);
 
                         if stored_v.is_stack_var() {
-                            let h = self.machine_st.heap.len();
-                            self.machine_st.heap.push(heap_loc_as_cell!(h));
+                            let h = self.machine_st.heap.cell_len();
+                            push_cell!(self.machine_st, heap_loc_as_cell!(h));
                             (self.machine_st.bind_fn)(
                                 &mut self.machine_st,
                                 Ref::heap_cell(h),
                                 stored_v,
                             );
                         } else {
-                            self.machine_st.heap.push(stored_v);
+                            push_cell!(self.machine_st, stored_v);
                         }
 
                         self.machine_st.p += 1;
                     }
                     &Instruction::SetVariable(reg) => {
-                        let h = self.machine_st.heap.len();
+                        let h = self.machine_st.heap.cell_len();
 
-                        self.machine_st.heap.push(heap_loc_as_cell!(h));
+                        push_cell!(self.machine_st, heap_loc_as_cell!(h));
                         self.machine_st[reg] = heap_loc_as_cell!(h);
 
                         self.machine_st.p += 1;
                     }
                     &Instruction::SetValue(reg) => {
                         let heap_val = self.machine_st.store(self.machine_st[reg]);
-                        self.machine_st.heap.push(heap_val);
+                        push_cell!(self.machine_st, heap_val);
                         self.machine_st.p += 1;
                     }
                     &Instruction::SetVoid(n) => {
-                        let h = self.machine_st.heap.len();
+                        let h = self.machine_st.heap.cell_len();
 
                         for i in h..h + n {
-                            self.machine_st.heap.push(heap_loc_as_cell!(i));
+                            push_cell!(self.machine_st, heap_loc_as_cell!(i));
                         }
 
                         self.machine_st.p += 1;
@@ -3331,11 +3395,11 @@ impl Machine {
                     }
                     &Instruction::CallCopyToLiftedHeap => {
                         self.copy_to_lifted_heap();
-                        self.machine_st.p += 1;
+                        step_or_fail!(self, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteCopyToLiftedHeap => {
                         self.copy_to_lifted_heap();
-                        self.machine_st.p = self.machine_st.cp;
+                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallCreatePartialString => {
                         self.create_partial_string();
@@ -3487,15 +3551,6 @@ impl Machine {
                             self.dynamic_module_resolution(arity - 2)
                         );
 
-                        /*
-                        println!(
-                            "(slow) calling {}:{}/{}",
-                            module_name.as_str(),
-                            key.0.as_str(),
-                            key.1,
-                        );
-                        */
-
                         try_or_throw!(self.machine_st, self.call_clause(module_name, key));
 
                         if self.machine_st.fail {
@@ -3508,15 +3563,6 @@ impl Machine {
                             self.dynamic_module_resolution(arity - 2)
                         );
 
-                        /*
-                        println!(
-                            "(slow) executing {}:{}/{}",
-                            module_name.as_str(),
-                            key.0.as_str(),
-                            key.1,
-                        );
-                        */
-
                         try_or_throw!(self.machine_st, self.execute_clause(module_name, key));
 
                         if self.machine_st.fail {
@@ -4251,11 +4297,11 @@ impl Machine {
                     }
                     &Instruction::CallSetBall => {
                         self.set_ball();
-                        self.machine_st.p += 1;
+                        step_or_fail!(self, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteSetBall => {
                         self.set_ball();
-                        self.machine_st.p = self.machine_st.cp;
+                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallPushBallStack => {
                         self.push_ball_stack();
@@ -4590,19 +4636,19 @@ impl Machine {
                         step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadHTML => {
-                        self.load_html();
+                        backtrack_on_resource_error!(self.machine_st, self.load_html());
                         step_or_fail!(self, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadHTML => {
-                        self.load_html();
+                        backtrack_on_resource_error!(self.machine_st, self.load_html());
                         step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallLoadXML => {
-                        self.load_xml();
+                        backtrack_on_resource_error!(self.machine_st, self.load_xml());
                         step_or_fail!(self, self.machine_st.p += 1);
                     }
                     &Instruction::ExecuteLoadXML => {
-                        self.load_xml();
+                        backtrack_on_resource_error!(self.machine_st, self.load_xml());
                         step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                     }
                     &Instruction::CallGetEnv => {
@@ -5079,13 +5125,18 @@ impl Machine {
                         let r = self.machine_st.registers[2];
                         let r = self.machine_st.store(self.machine_st.deref(r));
 
-                        let h = self.machine_st.heap.len();
-                        self.machine_st
-                            .heap
-                            .extend(functor!(atom!("-"), [fixnum(n), fixnum(p)]));
+                        let mut writer = Heap::functor_writer(
+                            functor!(atom!("-"), [fixnum(n), fixnum(p)]),
+                        );
+
+                        let str_cell = backtrack_on_resource_error!(
+                            &mut self.machine_st,
+                            writer(&mut self.machine_st.heap)
+                        );
 
                         let r = r.as_var().unwrap();
-                        self.machine_st.bind(r, str_loc_as_cell!(h));
+
+                        self.machine_st.bind(r, str_cell);
 
                         step_or_fail!(self, self.machine_st.p += 1);
                     }
@@ -5097,13 +5148,18 @@ impl Machine {
                         let r = self.machine_st.registers[2];
                         let r = self.machine_st.store(self.machine_st.deref(r));
 
-                        let h = self.machine_st.heap.len();
-                        self.machine_st
-                            .heap
-                            .extend(functor!(atom!("-"), [fixnum(n), fixnum(p)]));
+                        let mut writer = Heap::functor_writer(
+                            functor!(atom!("-"), [fixnum(n), fixnum(p)]),
+                        );
+
+                        let str_cell = backtrack_on_resource_error!(
+                            &mut self.machine_st,
+                            writer(&mut self.machine_st.heap)
+                        );
 
                         let r = r.as_var().unwrap();
-                        self.machine_st.bind(r, str_loc_as_cell!(h));
+
+                        self.machine_st.bind(r, str_cell);
 
                         step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
                     }
index 456f075fe9773dc406cdb05444778d60bd885a2e..f0f480f3900cb99fb943f70797872ec732226b95 100644 (file)
@@ -1,15 +1,22 @@
-#![allow(dead_code)]
-
+#[cfg(test)]
 use crate::atom_table::*;
+#[cfg(test)]
 use crate::machine::heap::*;
+#[cfg(test)]
 use crate::types::*;
 
+#[cfg(test)]
+use fxhash::FxBuildHasher;
+#[cfg(test)]
+use indexmap::IndexMap;
+
 #[cfg(test)]
 use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc};
 
 #[cfg(test)]
 use std::ops::Deref;
 
+#[cfg(test)]
 pub(crate) trait UnmarkPolicy {
     fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
     where
@@ -29,8 +36,7 @@ pub(crate) trait UnmarkPolicy {
     fn record_focus(_iter: &mut StacklessPreOrderHeapIter<Self>)
     where
         Self: Sized,
-    {
-    }
+    {}
 }
 
 #[cfg(test)]
@@ -71,8 +77,10 @@ impl UnmarkPolicy for IteratorUMP {
     }
 }
 
+#[cfg(test)]
 struct MarkerUMP {}
 
+#[cfg(test)]
 impl UnmarkPolicy for MarkerUMP {
     #[inline(always)]
     fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> {
@@ -100,18 +108,23 @@ impl UnmarkPolicy for MarkerUMP {
     }
 }
 
+#[cfg(test)]
+type PStrLocValuesMap = IndexMap<usize, usize, FxBuildHasher>;
+
+#[cfg(test)]
 #[derive(Debug)]
 pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
-    pub(crate) heap: &'a mut [HeapCellValue],
+    pub(crate) heap: &'a mut Heap,
     start: usize,
     current: usize,
     next: u64,
     iter_state: UMP,
+    pstr_loc_values: PStrLocValuesMap,
 }
 
 #[cfg(test)]
 impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> {
-    type Target = [HeapCellValue];
+    type Target = Heap;
 
     fn deref(&self) -> &Self::Target {
         self.heap
@@ -126,6 +139,7 @@ impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
     }
 }
 
+#[cfg(test)]
 impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> {
     fn drop(&mut self) {
         UMP::invert_marker(self);
@@ -138,8 +152,9 @@ impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> {
     }
 }
 
+#[cfg(test)]
 impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> {
-    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);
         let next = heap[start].get_value();
 
@@ -149,13 +164,15 @@ impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> {
             current: start,
             next,
             iter_state: MarkerUMP {},
+            pstr_loc_values: PStrLocValuesMap::with_hasher(FxBuildHasher::default()),
         }
     }
 }
 
 #[cfg(test)]
 impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> {
-    pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self {
+    #[cfg(test)]
+    pub(crate) fn new(heap: &'a mut Heap, start: usize) -> Self {
         heap[start].set_forwarding_bit(true);
         let next = heap[start].get_value();
 
@@ -165,10 +182,12 @@ impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> {
             current: start,
             next,
             iter_state: IteratorUMP { mark_phase: true },
+            pstr_loc_values: PStrLocValuesMap::with_hasher(FxBuildHasher::default()),
         }
     }
 }
 
+#[cfg(test)]
 impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
     fn backward_and_return(&mut self) -> HeapCellValue {
         let mut current = self.heap[self.current];
@@ -214,7 +233,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
                             return Some(cell);
                         }
 
-                        if self.next < self.heap.len() as u64 && UMP::report_var_link(self) {
+                        if self.next < self.heap.cell_len() as u64 && UMP::report_var_link(self) {
                             let tag = HeapCellValueTag::AttrVar;
                             return Some(HeapCellValue::build_with(tag, next as u64));
                         }
@@ -226,7 +245,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
                             return Some(cell);
                         }
 
-                        if self.next < self.heap.len() as u64 && UMP::report_var_link(self) {
+                        if self.next < self.heap.cell_len() as u64 && UMP::report_var_link(self) {
                             let tag = HeapCellValueTag::Var;
                             return Some(HeapCellValue::build_with(tag, next as u64));
                         }
@@ -241,7 +260,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
 
                         let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
 
-                        for cell in &mut self.heap[h + 1..h + arity + 1] {
+                        for cell in &mut self.heap.splice_mut(h + 1..h + arity + 1) {
                             cell.set_forwarding_bit(true);
                         }
 
@@ -270,48 +289,21 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
                     }
                     HeapCellValueTag::PStrLoc => {
                         let h = self.next as usize;
+                        let (_, last_cell_loc) = self.heap.scan_slice_to_str(h);
+
+                        self.pstr_loc_values.insert(self.current, h);
 
-                        if self.heap[h + 1].get_forwarding_bit() {
+                        if self.heap[last_cell_loc].get_forwarding_bit() {
                             return Some(self.backward_and_return());
                         }
 
-                        let cell = self.heap[h];
-
-                        let last_cell_loc = h + 1;
-
                         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;
 
                         self.heap[last_cell_loc].set_forwarding_bit(true);
 
-                        return Some(cell);
-                    }
-                    HeapCellValueTag::PStrOffset => {
-                        let h = self.next as usize;
-                        let cell = self.heap[h];
-
-                        let last_cell_loc = h + 1;
-
-                        if self.heap[last_cell_loc].get_forwarding_bit() {
-                            return Some(self.backward_and_return());
-                        }
-
-                        if self.heap[h].get_tag() == HeapCellValueTag::PStr {
-                            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);
+                        return Some(pstr_loc_as_cell!(h));
                     }
                     tag @ HeapCellValueTag::Atom => {
                         let cell = HeapCellValue::build_with(tag, self.next);
@@ -323,7 +315,15 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
                             return None;
                         }
                     }
-                    HeapCellValueTag::PStr => {
+                    HeapCellValueTag::Cons if self.heap.pstr_at(self.current) => {
+                        let pstr_loc_loc = self.heap[self.current].get_value() as usize;
+                        let pstr_loc_val = self.pstr_loc_values.get(&pstr_loc_loc).unwrap();
+
+                        self.heap[self.current].set_value(self.next);
+
+                        self.next = *pstr_loc_val as u64;
+                        self.current = pstr_loc_loc;
+
                         if self.backward() {
                             return None;
                         }
@@ -366,6 +366,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
     }
 }
 
+#[cfg(test)]
 impl<'a, UMP: UnmarkPolicy> Iterator for StacklessPreOrderHeapIter<'a, UMP> {
     type Item = HeapCellValue;
 
@@ -375,157 +376,167 @@ impl<'a, UMP: UnmarkPolicy> Iterator for StacklessPreOrderHeapIter<'a, UMP> {
     }
 }
 
-pub fn mark_cells(heap: &mut Heap, start: usize) {
-    let mut iter = StacklessPreOrderHeapIter::<MarkerUMP>::new(heap, start);
-    while iter.forward().is_some() {}
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
+    use crate::functor_macro::*;
     use crate::machine::mock_wam::*;
 
+    fn mark_cells(heap: &mut Heap, start: usize) {
+        let mut iter = StacklessPreOrderHeapIter::<MarkerUMP>::new(heap, start);
+        while iter.forward().is_some() {}
+    }
+
     #[test]
     fn heap_marking_tests() {
         let mut wam = MockWAM::new();
 
+        // clear the heap of resource error data etc
+        wam.machine_st.heap.clear();
+
         let f_atom = atom!("f");
         let a_atom = atom!("a");
         let b_atom = atom!("b");
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
+        let mut functor_writer = Heap::functor_writer(
+            functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom)]),
+        );
 
-        wam.machine_st
-            .heap
-            .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        let h = wam.machine_st.heap.cell_len();
 
-        mark_cells(&mut wam.machine_st.heap, 0);
+        wam.machine_st.heap.push_cell(cell).unwrap();
+
+        mark_cells(&mut wam.machine_st.heap, h);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
-            str_loc_as_cell!(1)
+            unmark_cell_bits!(wam.machine_st.heap[3]),
+            str_loc_as_cell!(0)
         );
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[1]),
+            unmark_cell_bits!(wam.machine_st.heap[0]),
             atom_as_cell!(f_atom, 2)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
+            unmark_cell_bits!(wam.machine_st.heap[1]),
             atom_as_cell!(a_atom)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
+            unmark_cell_bits!(wam.machine_st.heap[2]),
             atom_as_cell!(b_atom)
         );
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
+        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(1)
+                ]
+            ),
+        );
 
-        wam.machine_st.heap.extend(functor!(
-            f_atom,
-            [
-                atom(a_atom),
-                atom(b_atom),
-                atom(a_atom),
-                cell(str_loc_as_cell!(1))
-            ]
-        ));
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        let h = wam.machine_st.heap.cell_len();
 
-        mark_cells(&mut wam.machine_st.heap, 0);
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        mark_cells(&mut wam.machine_st.heap, h);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
-            str_loc_as_cell!(1)
+            unmark_cell_bits!(wam.machine_st.heap[5]),
+            str_loc_as_cell!(0)
         );
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[1]),
+            unmark_cell_bits!(wam.machine_st.heap[0]),
             atom_as_cell!(f_atom, 4)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
+            unmark_cell_bits!(wam.machine_st.heap[1]),
             atom_as_cell!(a_atom)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
+            unmark_cell_bits!(wam.machine_st.heap[2]),
             atom_as_cell!(b_atom)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
+            unmark_cell_bits!(wam.machine_st.heap[3]),
             atom_as_cell!(a_atom)
         );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            str_loc_as_cell!(1)
-        );
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
         // make the structure doubly cyclic.
-        wam.machine_st.heap[2] = str_loc_as_cell!(1);
+        wam.machine_st.heap[1] = str_loc_as_cell!(0);
 
-        mark_cells(&mut wam.machine_st.heap, 0);
+        mark_cells(&mut wam.machine_st.heap, h);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
+        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)
+                ]
+            ),
+        );
 
-        wam.machine_st.heap.extend(functor!(
-            f_atom,
-            [
-                atom(a_atom),
-                atom(b_atom),
-                atom(a_atom),
-                cell(str_loc_as_cell!(1))
-            ]
-        ));
+        let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
+        let h = wam.machine_st.heap.cell_len();
 
-        mark_cells(&mut wam.machine_st.heap, 0);
+        wam.machine_st.heap.push_cell(cell).unwrap();
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        mark_cells(&mut wam.machine_st.heap, h);
+
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
-            str_loc_as_cell!(1)
+            unmark_cell_bits!(wam.machine_st.heap[5]),
+            str_loc_as_cell!(0)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[1]),
+            unmark_cell_bits!(wam.machine_st.heap[0]),
             atom_as_cell!(f_atom, 4)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
+            unmark_cell_bits!(wam.machine_st.heap[1]),
             atom_as_cell!(a_atom)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
+            unmark_cell_bits!(wam.machine_st.heap[2]),
             atom_as_cell!(b_atom)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
+            unmark_cell_bits!(wam.machine_st.heap[3]),
             atom_as_cell!(a_atom)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            str_loc_as_cell!(1)
+            unmark_cell_bits!(wam.machine_st.heap[4]),
+            str_loc_as_cell!(0)
         );
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap();
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -534,16 +545,20 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
-        // term is: [a, b]
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(a_atom));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(atom_as_cell!(b_atom));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
+
+        writer.write_with(|section| {
+            // term is: [a, b]
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(a_atom));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(atom_as_cell!(b_atom));
+            section.push_cell(empty_list_as_cell!());
+        });
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -566,18 +581,14 @@ mod tests {
             empty_list_as_cell!()
         );
 
-        wam.machine_st.heap.pop();
-
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
         // now make the list cyclic.
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        wam.machine_st.heap[4] = heap_loc_as_cell!(0);
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -600,7 +611,7 @@ mod tests {
             heap_loc_as_cell!(0)
         );
 
-        for cell in &mut wam.machine_st.heap {
+        for cell in &mut wam.machine_st.heap.splice_mut(..) {
             cell.set_mark_bit(false);
         }
 
@@ -609,24 +620,29 @@ mod tests {
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
         // term is: [a, <stream ptr>]
         let stream = Stream::from_static_string("test", &mut wam.machine_st.arena);
-        let stream_cell =
-            HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons));
+        let stream_cell = HeapCellValue::from(
+            ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons),
+        );
+
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(a_atom));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(stream_cell);
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(a_atom));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(stream_cell);
+            section.push_cell(empty_list_as_cell!());
+        });
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -650,14 +666,18 @@ mod tests {
 
         // now a cycle of variables.
 
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(heap_loc_as_cell!(1));
+            section.push_cell(heap_loc_as_cell!(2));
+            section.push_cell(heap_loc_as_cell!(3));
+            section.push_cell(heap_loc_as_cell!(0));
+        });
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -682,313 +702,231 @@ mod tests {
         // two-part complete string, then a three-part cyclic string
         // involving an uncompacted list of chars.
 
-        wam.machine_st.heap.push(pstr_loc_as_cell!(1));
-
-        let pstr_var_cell =
-            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];
-
-        mark_cells(&mut wam.machine_st.heap, 0);
-
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
-
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
-            pstr_loc_as_cell!(1)
-        );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            heap_loc_as_cell!(2)
-        );
+        let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap();
 
-        wam.machine_st.heap.pop();
+        wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        let pstr_cell_loc = wam.machine_st.heap.cell_len();
 
-        wam.machine_st.heap.push(pstr_loc_as_cell!(3));
+        wam.machine_st.heap.push_cell(pstr_loc_as_cell!(heap_index!(0))).unwrap();
 
-        let pstr_second_var_cell =
-            put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
-        let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+        mark_cells(&mut wam.machine_st.heap, pstr_cell_loc);
 
-        mark_cells(&mut wam.machine_st.heap, 0);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(3)
+            wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()),
+            "abc "
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell);
+        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[pstr_cell_loc]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
-            heap_loc_as_cell!(4)
+            unmark_cell_bits!(wam.machine_st.heap[1]),
+            heap_loc_as_cell!(1)
         );
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.push(pstr_loc_as_cell!(5));
-        wam.machine_st.heap.push(pstr_offset_as_cell!(1));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(2)));
-        wam.machine_st.heap.push(pstr_loc_as_cell!(5));
+        wam.machine_st.allocate_pstr("abc ").unwrap();
+        wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
 
-        mark_cells(&mut wam.machine_st.heap, 7);
+        mark_cells(&mut wam.machine_st.heap, 2);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
+
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(3)
+            wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()),
+            "abc "
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
-            pstr_loc_as_cell!(5)
+            wam.machine_st.heap[1],
+            pstr_loc_as_cell!(heap_index!(3))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_offset_as_cell!(1)
+            wam.machine_st.heap[2],
+            pstr_loc_as_cell!(heap_index!(0))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
-            fixnum_as_cell!(Fixnum::build_with(2))
+            wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()),
+            "abc "
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            pstr_loc_as_cell!(5)
+            wam.machine_st.heap[4],
+            heap_loc_as_cell!(4)
         );
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        // create a cycle offset two characters into the partial string at 0
+        wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(0) + 2);
 
-        wam.machine_st.heap[7] = heap_loc_as_cell!(2);
+        mark_cells(&mut wam.machine_st.heap, 2);
 
-        mark_cells(&mut wam.machine_st.heap, 7);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]);
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(3)
+            wam.machine_st.heap.slice_to_str(0, "abc ".len()),
+            "abc "
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
-            pstr_loc_as_cell!(5)
+            wam.machine_st.heap[1],
+            pstr_loc_as_cell!(heap_index!(3))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_offset_as_cell!(1)
+            wam.machine_st.heap[2],
+            pstr_loc_as_cell!(heap_index!(0))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
-            fixnum_as_cell!(Fixnum::build_with(2))
+            wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()),
+            "abc "
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            heap_loc_as_cell!(2)
+            wam.machine_st.heap[4],
+            pstr_loc_as_cell!(heap_index!(0) + 2)
         );
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        wam.machine_st.heap[4] = heap_loc_as_cell!(2);
 
-        wam.machine_st.heap[7] = pstr_loc_as_cell!(1);
+        wam.machine_st.heap.push_cell(heap_loc_as_cell!(2)).unwrap();
 
-        mark_cells(&mut wam.machine_st.heap, 7);
+        mark_cells(&mut wam.machine_st.heap, 5);
+
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]);
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(3)
+            wam.machine_st.heap.slice_to_str(0, "abc ".len()),
+            "abc "
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
-            pstr_loc_as_cell!(5)
+            wam.machine_st.heap[1],
+            pstr_loc_as_cell!(heap_index!(3))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_offset_as_cell!(1)
+            wam.machine_st.heap[2],
+            pstr_loc_as_cell!(heap_index!(0))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
-            fixnum_as_cell!(Fixnum::build_with(2))
+            wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()),
+            "abc "
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            pstr_loc_as_cell!(1)
+            wam.machine_st.heap[4],
+            heap_loc_as_cell!(2)
+        );
+        assert_eq!(
+            wam.machine_st.heap[5],
+            heap_loc_as_cell!(2)
         );
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        wam.machine_st.heap[4] = pstr_loc_as_cell!(0);
 
-        wam.machine_st.heap[7] = heap_loc_as_cell!(0);
+        mark_cells(&mut wam.machine_st.heap, 2);
 
-        mark_cells(&mut wam.machine_st.heap, 7);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(.. 5));
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]);
+        unmark_all_cells(wam.machine_st.heap.splice_mut(.. 5));
 
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(3)
+            wam.machine_st.heap.slice_to_str(0, "abc ".len()),
+            "abc "
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
-            pstr_loc_as_cell!(5)
+            wam.machine_st.heap[1],
+            pstr_loc_as_cell!(heap_index!(3))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_offset_as_cell!(1)
+            wam.machine_st.heap[2],
+            pstr_loc_as_cell!(heap_index!(0))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
-            fixnum_as_cell!(Fixnum::build_with(2))
+            wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()),
+            "abc "
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            heap_loc_as_cell!(0)
+            wam.machine_st.heap[4],
+            pstr_loc_as_cell!(heap_index!(0))
+        );
+        assert_eq!(
+            wam.machine_st.heap[5],
+            heap_loc_as_cell!(2)
         );
 
         wam.machine_st.heap.truncate(4);
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        let mut writer = wam.machine_st.heap.reserve(2).unwrap();
 
-        wam.machine_st
-            .heap
-            .push(atom_as_cell!(atom!("irrelevant stuff")));
-        wam.machine_st.heap.push(pstr_offset_as_cell!(1));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(2)));
+        writer.write_with(|section| {
+            section.push_cell(atom_as_cell!(atom!("irrelevant stuff")));
+            section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 2)); // offset two chars into pstr at 0
+        });
 
-        // this is at index 7
-        wam.machine_st.heap.push(pstr_loc_as_cell!(5));
+        wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap();
 
-        mark_cells(&mut wam.machine_st.heap, 7);
+        mark_cells(&mut wam.machine_st.heap, 6);
 
-        assert!(!wam.machine_st.heap[0].get_mark_bit());
+        // indices 0 and 3 are the beginning of one-cell partial
+        // strings, and they should be marked! despite the HeapCellValue casts
+        // otherwise not being sensible.
+        assert!(wam.machine_st.heap[0].get_mark_bit());
         assert!(wam.machine_st.heap[1].get_mark_bit());
-        assert!(wam.machine_st.heap[2].get_mark_bit());
+        assert!(!wam.machine_st.heap[2].get_mark_bit());
         assert!(wam.machine_st.heap[3].get_mark_bit());
         assert!(wam.machine_st.heap[4].get_mark_bit());
         assert!(wam.machine_st.heap[5].get_mark_bit());
         assert!(wam.machine_st.heap[6].get_mark_bit());
 
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(3)
-        );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell);
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
-            atom_as_cell!(atom!("irrelevant stuff"))
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_offset_as_cell!(1)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
-            fixnum_as_cell!(Fixnum::build_with(2))
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            pstr_loc_as_cell!(5)
-        );
-
-        wam.machine_st.heap.clear();
-
-        wam.machine_st
-            .heap
-            .push(atom_as_cell!(atom!("irrelevant stuff")));
-        wam.machine_st.heap.push(pstr_cell);
-        wam.machine_st.heap.push(pstr_loc_as_cell!(4));
-        wam.machine_st
-            .heap
-            .push(atom_as_cell!(atom!("irrelevant stuff")));
-        wam.machine_st.heap.push(pstr_second_cell);
-        wam.machine_st.heap.push(pstr_loc_as_cell!(7));
-        wam.machine_st
-            .heap
-            .push(atom_as_cell!(atom!("irrelevant stuff")));
-        wam.machine_st.heap.push(pstr_offset_as_cell!(1));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(2)));
-
-        wam.machine_st.heap.push(pstr_loc_as_cell!(7));
-
-        mark_cells(&mut wam.machine_st.heap, 9);
-
-        assert!(!wam.machine_st.heap[0].get_mark_bit());
-        assert!(wam.machine_st.heap[1].get_mark_bit());
-        assert!(wam.machine_st.heap[2].get_mark_bit());
-        assert!(!wam.machine_st.heap[3].get_mark_bit());
-        assert!(wam.machine_st.heap[4].get_mark_bit());
-        assert!(wam.machine_st.heap[5].get_mark_bit());
-        assert!(!wam.machine_st.heap[6].get_mark_bit());
-        assert!(wam.machine_st.heap[7].get_mark_bit());
-        assert!(wam.machine_st.heap[8].get_mark_bit());
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
-            atom_as_cell!(atom!("irrelevant stuff"))
+            wam.machine_st.heap.slice_to_str(0, "abc ".len()),
+            "abc "
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(4)
+            wam.machine_st.heap[1],
+            pstr_loc_as_cell!(heap_index!(3))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
-            atom_as_cell!(atom!("irrelevant stuff"))
+            wam.machine_st.heap[2],
+            pstr_loc_as_cell!(heap_index!(0))
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_loc_as_cell!(7)
+            wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()),
+            "abc "
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
+            wam.machine_st.heap[4],
             atom_as_cell!(atom!("irrelevant stuff"))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            pstr_offset_as_cell!(1)
+            wam.machine_st.heap[5],
+            pstr_loc_as_cell!(heap_index!(0) + 2)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[8]),
-            fixnum_as_cell!(Fixnum::build_with(2))
+            wam.machine_st.heap[6],
+            heap_loc_as_cell!(5)
         );
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        wam.machine_st.heap.clear();
 
-        wam.machine_st.heap[9] = heap_loc_as_cell!(5);
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
 
-        mark_cells(&mut wam.machine_st.heap, 9);
+        writer.write_with(|section| {
+            section.push_cell(atom_as_cell!(atom!("irrelevant stuff")));
+            section.push_pstr("abc ");
+            section.push_cell(pstr_loc_as_cell!(heap_index!(4)));
+            section.push_cell(atom_as_cell!(atom!("irrelevant stuff")));
+            section.push_pstr("def");
+            section.push_cell(pstr_loc_as_cell!(heap_index!(1) + 2));
+            section.push_cell(atom_as_cell!(atom!("irrelevant stuff")));
+            section.push_cell(pstr_loc_as_cell!(heap_index!(1) + 2));
+        });
+
+        mark_cells(&mut wam.machine_st.heap, 7);
 
         assert!(!wam.machine_st.heap[0].get_mark_bit());
         assert!(wam.machine_st.heap[1].get_mark_bit());
@@ -997,104 +935,49 @@ mod tests {
         assert!(wam.machine_st.heap[4].get_mark_bit());
         assert!(wam.machine_st.heap[5].get_mark_bit());
         assert!(!wam.machine_st.heap[6].get_mark_bit());
-        assert!(wam.machine_st.heap[7].get_mark_bit());
-        assert!(wam.machine_st.heap[8].get_mark_bit());
 
-        for cell in &wam.machine_st.heap {
-            assert!(!cell.get_forwarding_bit());
-        }
+        assert!(!wam.machine_st.heap[0].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[1].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[2].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[3].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[4].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[5].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[6].get_forwarding_bit());
+
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
-            atom_as_cell!(atom!("irrelevant stuff"))
-        );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(4)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
-            atom_as_cell!(atom!("irrelevant stuff"))
-        );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_loc_as_cell!(7)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
+            wam.machine_st.heap[0],
             atom_as_cell!(atom!("irrelevant stuff"))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            pstr_offset_as_cell!(1)
+            wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()),
+            "abc "
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[8]),
-            fixnum_as_cell!(Fixnum::build_with(2))
+            wam.machine_st.heap[2],
+            pstr_loc_as_cell!(heap_index!(4))
         );
-
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
-
-        wam.machine_st.heap[9] = pstr_loc_as_cell!(4);
-
-        mark_cells(&mut wam.machine_st.heap, 9);
-
-        assert!(!wam.machine_st.heap[0].get_mark_bit());
-        assert!(wam.machine_st.heap[1].get_mark_bit());
-        assert!(wam.machine_st.heap[2].get_mark_bit());
-        assert!(!wam.machine_st.heap[3].get_mark_bit());
-        assert!(wam.machine_st.heap[4].get_mark_bit());
-        assert!(wam.machine_st.heap[5].get_mark_bit());
-        assert!(!wam.machine_st.heap[6].get_mark_bit());
-        assert!(wam.machine_st.heap[7].get_mark_bit());
-        assert!(wam.machine_st.heap[8].get_mark_bit());
-
-        for cell in &wam.machine_st.heap {
-            assert!(!cell.get_forwarding_bit());
-        }
-
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
+            wam.machine_st.heap[3],
             atom_as_cell!(atom!("irrelevant stuff"))
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(4)
+            wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()),
+            "def"
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
-            atom_as_cell!(atom!("irrelevant stuff"))
+            wam.machine_st.heap[5],
+            pstr_loc_as_cell!(heap_index!(1) + 2)
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_loc_as_cell!(7)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
+            wam.machine_st.heap[6],
             atom_as_cell!(atom!("irrelevant stuff"))
         );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            pstr_offset_as_cell!(1)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[8]),
-            fixnum_as_cell!(Fixnum::build_with(2))
-        );
-
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
 
-        mark_cells(&mut wam.machine_st.heap, 9);
+        wam.machine_st.heap[7] = heap_loc_as_cell!(2);
 
-        wam.machine_st.heap[9] = heap_loc_as_cell!(2);
+        mark_cells(&mut wam.machine_st.heap, 7);
 
         assert!(!wam.machine_st.heap[0].get_mark_bit());
         assert!(wam.machine_st.heap[1].get_mark_bit());
@@ -1104,50 +987,49 @@ mod tests {
         assert!(wam.machine_st.heap[5].get_mark_bit());
         assert!(!wam.machine_st.heap[6].get_mark_bit());
         assert!(wam.machine_st.heap[7].get_mark_bit());
-        assert!(wam.machine_st.heap[8].get_mark_bit());
 
-        for cell in &wam.machine_st.heap {
-            assert!(!cell.get_forwarding_bit());
-        }
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
+
+        assert!(!wam.machine_st.heap[0].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[1].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[2].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[3].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[4].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[5].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[6].get_forwarding_bit());
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
+            wam.machine_st.heap[0],
             atom_as_cell!(atom!("irrelevant stuff"))
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(4)
+            wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()),
+            "abc "
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
-            atom_as_cell!(atom!("irrelevant stuff"))
+            wam.machine_st.heap[2],
+            pstr_loc_as_cell!(heap_index!(4))
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_loc_as_cell!(7)
+            wam.machine_st.heap[3],
+            atom_as_cell!(atom!("irrelevant stuff"))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
-            atom_as_cell!(atom!("irrelevant stuff"))
+            wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()),
+            "def"
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            pstr_offset_as_cell!(1)
+            wam.machine_st.heap[5],
+            pstr_loc_as_cell!(heap_index!(1) + 2)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[8]),
-            fixnum_as_cell!(Fixnum::build_with(2))
+            wam.machine_st.heap[6],
+            atom_as_cell!(atom!("irrelevant stuff"))
         );
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
-
-        wam.machine_st.heap[9] = pstr_loc_as_cell!(1);
+        wam.machine_st.heap[7] = pstr_loc_as_cell!(heap_index!(4));
 
-        mark_cells(&mut wam.machine_st.heap, 9);
+        mark_cells(&mut wam.machine_st.heap, 7);
 
         assert!(!wam.machine_st.heap[0].get_mark_bit());
         assert!(wam.machine_st.heap[1].get_mark_bit());
@@ -1157,181 +1039,143 @@ mod tests {
         assert!(wam.machine_st.heap[5].get_mark_bit());
         assert!(!wam.machine_st.heap[6].get_mark_bit());
         assert!(wam.machine_st.heap[7].get_mark_bit());
-        assert!(wam.machine_st.heap[8].get_mark_bit());
 
-        for cell in &wam.machine_st.heap {
-            assert!(!cell.get_forwarding_bit());
-        }
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
+
+        assert!(!wam.machine_st.heap[0].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[1].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[2].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[3].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[4].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[5].get_forwarding_bit());
+        assert!(!wam.machine_st.heap[6].get_forwarding_bit());
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
+            wam.machine_st.heap[0],
             atom_as_cell!(atom!("irrelevant stuff"))
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_loc_as_cell!(4)
+            wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()),
+            "abc "
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
-            atom_as_cell!(atom!("irrelevant stuff"))
+            wam.machine_st.heap[2],
+            pstr_loc_as_cell!(heap_index!(4))
         );
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell);
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_loc_as_cell!(7)
+            wam.machine_st.heap[3],
+            atom_as_cell!(atom!("irrelevant stuff"))
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
-            atom_as_cell!(atom!("irrelevant stuff"))
+            wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()),
+            "def"
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[7]),
-            pstr_offset_as_cell!(1)
+            wam.machine_st.heap[5],
+            pstr_loc_as_cell!(heap_index!(1) + 2)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[8]),
-            fixnum_as_cell!(Fixnum::build_with(2))
+            wam.machine_st.heap[6],
+            atom_as_cell!(atom!("irrelevant stuff"))
         );
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
-
         wam.machine_st.heap.clear();
 
-        // embedded cyclic partial string.
+        // embedded cyclic partial string
 
-        wam.machine_st.heap.push(pstr_cell);
-        wam.machine_st.heap.push(pstr_loc_as_cell!(2));
-        wam.machine_st.heap.push(pstr_offset_as_cell!(0));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(3)));
-        wam.machine_st.heap.push(list_loc_as_cell!(5));
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(8).unwrap();
 
-        mark_cells(&mut wam.machine_st.heap, 4);
+        writer.write_with(|section| {
+            section.push_pstr("abc ");
+            section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 3)); // 3 character offset into pstr_cell
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(pstr_loc_as_cell!(0));
+            section.push_cell(empty_list_as_cell!());
+            section.push_cell(heap_loc_as_cell!(2));
+        });
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        mark_cells(&mut wam.machine_st.heap, 5);
 
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
+
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[1]),
-            pstr_loc_as_cell!(2)
-        );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_offset_as_cell!(0)
+            wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()),
+            "abc "
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
-            fixnum_as_cell!(Fixnum::build_with(3))
+            wam.machine_st.heap[1],
+            pstr_loc_as_cell!(heap_index!(0) + 3)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
-            list_loc_as_cell!(5)
+            wam.machine_st.heap[2],
+            list_loc_as_cell!(3)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
+            wam.machine_st.heap[3],
             pstr_loc_as_cell!(0)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
+            wam.machine_st.heap[4],
             empty_list_as_cell!()
         );
-
-        wam.machine_st.heap.clear();
-
-        wam.machine_st.heap.push(pstr_cell);
-        wam.machine_st.heap.push(pstr_loc_as_cell!(2));
-        wam.machine_st.heap.push(pstr_offset_as_cell!(0));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(3)));
-        wam.machine_st.heap.push(list_loc_as_cell!(5));
-        wam.machine_st.heap.push(pstr_loc_as_cell!(0));
-        wam.machine_st.heap.push(heap_loc_as_cell!(4));
-
-        mark_cells(&mut wam.machine_st.heap, 4);
-
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
-
-        for cell in &mut wam.machine_st.heap {
-            cell.set_mark_bit(false);
-        }
-
-        assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell);
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[1]),
-            pstr_loc_as_cell!(2)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
-            pstr_offset_as_cell!(0)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
-            fixnum_as_cell!(Fixnum::build_with(3))
-        );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[4]),
-            list_loc_as_cell!(5)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[5]),
-            pstr_loc_as_cell!(0)
-        );
-        assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[6]),
-            heap_loc_as_cell!(4)
+            wam.machine_st.heap[5],
+            heap_loc_as_cell!(2)
         );
 
         wam.machine_st.heap.clear();
 
         // a chain of variables, ending in a self-referential variable.
 
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(heap_loc_as_cell!(1));
+            section.push_cell(heap_loc_as_cell!(2));
+            section.push_cell(heap_loc_as_cell!(3));
+            section.push_cell(heap_loc_as_cell!(3));
+        });
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
+
+        unmark_all_cells(wam.machine_st.heap.splice_mut(..));
 
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[0]),
+            wam.machine_st.heap[0],
             heap_loc_as_cell!(1)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[1]),
+            wam.machine_st.heap[1],
             heap_loc_as_cell!(2)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[2]),
+            wam.machine_st.heap[2],
             heap_loc_as_cell!(3)
         );
         assert_eq!(
-            unmark_cell_bits!(wam.machine_st.heap[3]),
+            wam.machine_st.heap[3],
             heap_loc_as_cell!(3)
         );
 
         wam.machine_st.heap.clear();
 
         // print L = [L|L].
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
+
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(list_loc_as_cell!(1));
+        });
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -1350,23 +1194,28 @@ mod tests {
 
         // term is [X,f(Y),Z].
         // Z is an attributed variable, but has a variable attributes list.
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2
-        wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3
-        wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4
-        wam.machine_st.heap.push(heap_loc_as_cell!(8));
-        wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6
-        wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7
-        wam.machine_st.heap.push(list_loc_as_cell!(9));
-        wam.machine_st.heap.push(heap_loc_as_cell!(9));
-        wam.machine_st.heap.push(empty_list_as_cell!());
-        wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7.
-        wam.machine_st.heap.push(heap_loc_as_cell!(12));
+
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(heap_loc_as_cell!(1));
+            section.push_cell(heap_loc_as_cell!(3)); // 2
+            section.push_cell(list_loc_as_cell!(4)); // 3
+            section.push_cell(str_loc_as_cell!(6)); // 4
+            section.push_cell(heap_loc_as_cell!(8));
+            section.push_cell(atom_as_cell!(f_atom, 1)); // 6
+            section.push_cell(heap_loc_as_cell!(11)); // 7
+            section.push_cell(list_loc_as_cell!(9));
+            section.push_cell(heap_loc_as_cell!(9));
+            section.push_cell(empty_list_as_cell!());
+            section.push_cell(attr_var_as_cell!(11)); // linked from 7.
+            section.push_cell(heap_loc_as_cell!(12));
+        });
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -1425,29 +1274,32 @@ mod tests {
         let clpz_atom = atom!("clpz");
         let p_atom = atom!("p");
 
-        for cell in &mut wam.machine_st.heap {
+        for cell in &mut wam.machine_st.heap.splice_mut(..) {
             cell.set_mark_bit(false);
             cell.set_forwarding_bit(false);
         }
 
-        wam.machine_st.heap.pop();
-
-        wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12
-        wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13
-        wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14
-        wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15
-        wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16
-        wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17
-        wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18
-        wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19
-        wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20
-        wam.machine_st.heap.push(empty_list_as_cell!()); // 21
-        wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22
-        wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23
+        wam.machine_st.heap[12] = heap_loc_as_cell!(13);
+
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(14)); // 13
+            section.push_cell(str_loc_as_cell!(16)); // 14
+            section.push_cell(heap_loc_as_cell!(19)); // 15
+            section.push_cell(atom_as_cell!(clpz_atom, 2)); // 16
+            section.push_cell(atom_as_cell!(a_atom)); // 17
+            section.push_cell(atom_as_cell!(b_atom)); // 18
+            section.push_cell(list_loc_as_cell!(20)); // 19
+            section.push_cell(str_loc_as_cell!(22)); // 20
+            section.push_cell(empty_list_as_cell!()); // 21
+            section.push_cell(atom_as_cell!(p_atom, 1)); // 22
+            section.push_cell(heap_loc_as_cell!(23)); // 23
+        });
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -1546,22 +1398,26 @@ mod tests {
             heap_loc_as_cell!(23)
         );
 
-        for cell in &mut wam.machine_st.heap {
+        for cell in &mut wam.machine_st.heap.splice_mut(..) {
             cell.set_mark_bit(false);
             cell.set_forwarding_bit(false);
         }
 
         // push some unrelated nonsense cells to the heap and check that they
         // are unmarked after the marker has finished at 0.
-        wam.machine_st.heap.push(heap_loc_as_cell!(5));
-        wam.machine_st.heap.push(heap_loc_as_cell!(5));
-        wam.machine_st.heap.push(list_loc_as_cell!(5));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(heap_loc_as_cell!(5));
+            section.push_cell(heap_loc_as_cell!(5));
+            section.push_cell(list_loc_as_cell!(5));
+        });
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap[0..24]);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(0..24));
 
-        for cell in &wam.machine_st.heap[24..] {
+        for cell in wam.machine_st.heap.splice(24..) {
             assert!(!cell.get_mark_bit());
         }
 
@@ -1677,32 +1533,37 @@ mod tests {
         wam.machine_st.heap.clear();
         wam.machine_st
             .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(0)));
+            .push_cell(fixnum_as_cell!(Fixnum::build_with(0)))
+            .unwrap();
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        assert_eq!(wam.machine_st.heap.len(), 1);
+        assert_eq!(wam.machine_st.heap.cell_len(), 1);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("y")));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("X")));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(list_loc_as_cell!(8));
-        wam.machine_st.heap.push(str_loc_as_cell!(4));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(str_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(atom!("g"), 2));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(atom_as_cell!(atom!("y")));
+            section.push_cell(atom_as_cell!(atom!("="), 2));
+            section.push_cell(atom_as_cell!(atom!("X")));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(list_loc_as_cell!(8));
+            section.push_cell(str_loc_as_cell!(4));
+            section.push_cell(empty_list_as_cell!());
+        });
 
         mark_cells(&mut wam.machine_st.heap, 7);
 
-        assert_eq!(wam.machine_st.heap.len(), 10);
+        assert_eq!(wam.machine_st.heap.cell_len(), 10);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -1747,14 +1608,18 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(str_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(atom_as_cell!(atom!("f"), 2));
+            section.push_cell(heap_loc_as_cell!(1));
+            section.push_cell(heap_loc_as_cell!(1));
+            section.push_cell(str_loc_as_cell!(0));
+        });
 
         mark_cells(&mut wam.machine_st.heap, 3);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -1773,19 +1638,22 @@ mod tests {
 
         // representation of one of the heap terms as in issue #1384.
 
-        wam.machine_st.heap.push(list_loc_as_cell!(1));
-        wam.machine_st.heap.push(empty_list_as_cell!());
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(empty_list_as_cell!());
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
 
-        wam.machine_st.heap.push(list_loc_as_cell!(5));
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(empty_list_as_cell!());
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(empty_list_as_cell!());
+            section.push_cell(heap_loc_as_cell!(2));
+            section.push_cell(list_loc_as_cell!(5));
+        });
 
         mark_cells(&mut wam.machine_st.heap, 7);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -1820,23 +1688,27 @@ mod tests {
 
         // representation of one of the heap terms as in issue #1384.
 
-        wam.machine_st.heap.push(list_loc_as_cell!(7));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
-        wam.machine_st.heap.push(list_loc_as_cell!(3)); // A = [B|[]].
-        wam.machine_st.heap.push(list_loc_as_cell!(5)); // B = [A|A].
-        wam.machine_st.heap.push(empty_list_as_cell!());
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
-        wam.machine_st.heap.push(empty_list_as_cell!()); // C = [[]|B].
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(7));
+            section.push_cell(heap_loc_as_cell!(0));
+            section.push_cell(list_loc_as_cell!(3)); // A = [B|[]].
+            section.push_cell(list_loc_as_cell!(5)); // B = [A|A].
+            section.push_cell(empty_list_as_cell!());
+            section.push_cell(heap_loc_as_cell!(2));
+            section.push_cell(heap_loc_as_cell!(2));
+            section.push_cell(empty_list_as_cell!()); // C = [[]|B].
+            section.push_cell(heap_loc_as_cell!(3));
+            section.push_cell(heap_loc_as_cell!(0));
+        });
 
         mark_cells(&mut wam.machine_st.heap, 9);
 
         assert!(wam.machine_st.heap[0].get_mark_bit());
         assert!(!wam.machine_st.heap[1].get_mark_bit());
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap[2..]);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(2..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
@@ -1874,31 +1746,31 @@ mod tests {
             unmark_cell_bits!(wam.machine_st.heap[8]),
             heap_loc_as_cell!(3)
         );
+        assert_eq!(
+            unmark_cell_bits!(wam.machine_st.heap[9]),
+            heap_loc_as_cell!(0)
+        );
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(str_loc_as_cell!(1));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2));
-        wam.machine_st.heap.push(str_loc_as_cell!(4));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(2)));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("-"), 2));
-        wam.machine_st.heap.push(str_loc_as_cell!(7));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(1)));
-        wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(3)));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(4)));
+        let mut writer = wam.machine_st.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(str_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(atom!("+"), 2));
+            section.push_cell(str_loc_as_cell!(4));
+            section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
+            section.push_cell(atom_as_cell!(atom!("-"), 2));
+            section.push_cell(str_loc_as_cell!(7));
+            section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
+            section.push_cell(atom_as_cell!(atom!("+"), 2));
+            section.push_cell(fixnum_as_cell!(Fixnum::build_with(3)));
+            section.push_cell(fixnum_as_cell!(Fixnum::build_with(4)));
+        });
 
         mark_cells(&mut wam.machine_st.heap, 0);
 
-        all_cells_marked_and_unforwarded(&wam.machine_st.heap);
+        all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..));
 
         assert_eq!(
             unmark_cell_bits!(wam.machine_st.heap[0]),
index 0f42b8c6812b3c32ed7c3c3983b833b78d8969f1..34731462f29ab1e705498462a71a749774e628ca 100644 (file)
-use crate::arena::*;
 use crate::atom_table::*;
 use crate::forms::*;
-use crate::machine::machine_indices::*;
-use crate::machine::partial_string::*;
-use crate::parser::ast::*;
+use crate::functor_macro::*;
 use crate::types::*;
 
-use crate::parser::dashu::{Integer, Rational};
-
+use std::alloc;
 use std::convert::TryFrom;
+use std::mem;
+use std::ops::{Bound, Index, IndexMut, Range, RangeBounds};
+use std::ptr;
+use std::sync::Once;
 
-pub(crate) type Heap = Vec<HeapCellValue>;
+use super::MachineState;
 
-impl From<Literal> for HeapCellValue {
-    #[inline]
-    fn from(literal: Literal) -> Self {
-        match literal {
-            Literal::Atom(name) => atom_as_cell!(name),
-            Literal::Char(c) => char_as_cell!(c),
-            Literal::CodeIndex(ptr) => {
-                untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr))
+use bitvec::prelude::*;
+use bitvec::slice::BitSlice;
+
+#[derive(Debug)]
+pub struct Heap {
+    inner: InnerHeap,
+    pstr_vec: BitVec,
+    resource_err_loc: usize,
+}
+
+impl Drop for Heap {
+    fn drop(&mut self) {
+        unsafe {
+            let layout = alloc::Layout::array::<u8>(self.inner.byte_cap).unwrap();
+            alloc::dealloc(self.inner.ptr, layout);
+        }
+    }
+}
+
+#[derive(Debug)]
+struct InnerHeap {
+    ptr: *mut u8,
+    byte_len: usize,
+    byte_cap: usize,
+}
+
+impl InnerHeap {
+    unsafe fn grow(&mut self) -> bool {
+        let new_cap = if self.byte_cap == 0 {
+            256 * 256 * 8
+        } else {
+            2 * self.byte_cap
+        };
+
+        let new_layout = alloc::Layout::array::<u8>(new_cap).unwrap();
+
+        assert!(
+            new_layout.size() <= isize::MAX as usize,
+            "Allocation too large. We should probably GC (TODO)"
+        );
+
+        let new_ptr = if self.byte_cap == 0 {
+            alloc::alloc(new_layout)
+        } else {
+            let old_layout = alloc::Layout::array::<u8>(self.byte_cap).unwrap();
+            alloc::realloc(self.ptr, old_layout, new_layout.size())
+        };
+
+        if !new_ptr.is_null() {
+            self.ptr = new_ptr;
+            self.byte_cap = new_cap;
+
+            true
+        } else {
+            false
+        }
+    }
+}
+
+unsafe impl Send for Heap {}
+unsafe impl Sync for Heap {}
+
+static RESOURCE_ERROR_OFFSET_INIT: Once = Once::new();
+
+// return the string at ptr and the tail location relative to ptr.
+// pstr_vec records the location of each string cell starting at index
+// 0.
+fn scan_slice_to_str(orig_ptr: *const u8, pstr_vec: &BitSlice) -> (&str, usize) {
+    unsafe {
+        debug_assert_eq!(pstr_vec[0], true);
+        const ALIGN_CELL: usize = Heap::heap_cell_alignment();
+
+        let tail_cell_offset = pstr_vec[0..].first_zero().unwrap();
+        let offset = (ALIGN_CELL - orig_ptr.align_offset(ALIGN_CELL)) % 8;
+        let buf_len = heap_index!(tail_cell_offset) - offset;
+        let slice = std::slice::from_raw_parts(orig_ptr, buf_len);
+
+        // skip the final buffer byte which may not be 0 depending on
+        // the context, i.e. marking by an iterator. it is counted by
+        // the initial 1 as part of the padding but for this reason
+        // mustn't be allowed to stop the count.
+
+        let padding_len = 1 + slice.iter()
+            .rev()
+            .skip(1)
+            .position(|b| *b != 0u8)
+            .unwrap();
+
+        let s_len = slice.len() - padding_len;
+        (std::str::from_utf8_unchecked(&slice[0 .. s_len]), tail_cell_offset)
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum PStrSegmentCmpResult {
+    Mismatch { c1: char, c2: char },
+    FirstMatch { pstr_loc1: usize, pstr_loc2: usize, l1_offset: usize },
+    SecondMatch { pstr_loc1: usize, pstr_loc2: usize, l2_offset: usize },
+    BothMatch { pstr_loc1: usize, pstr_loc2: usize, null_offset: usize },
+}
+
+impl PStrSegmentCmpResult {
+    pub(crate) fn continue_pstr_compare(
+        self,
+        pdl: &mut Vec<HeapCellValue>,
+    ) -> Option<std::cmp::Ordering> {
+        match self {
+            PStrSegmentCmpResult::FirstMatch { pstr_loc1, pstr_loc2, l1_offset } => {
+                let tail1 = Heap::neighboring_cell_offset(pstr_loc1 + l1_offset);
+                let rest_of_l2 = pstr_loc_as_cell!(pstr_loc2 + l1_offset);
+
+                pdl.push(heap_loc_as_cell!(tail1));
+                pdl.push(rest_of_l2);
+            }
+            PStrSegmentCmpResult::SecondMatch { pstr_loc1, pstr_loc2, l2_offset } => {
+                let tail2 = Heap::neighboring_cell_offset(pstr_loc2 + l2_offset);
+                let rest_of_l1 = pstr_loc_as_cell!(pstr_loc1 + l2_offset);
+
+                pdl.push(rest_of_l1);
+                pdl.push(heap_loc_as_cell!(tail2));
             }
-            Literal::Fixnum(n) => fixnum_as_cell!(n),
-            Literal::Integer(bigint_ptr) => {
-                typed_arena_ptr_as_cell!(bigint_ptr)
+            PStrSegmentCmpResult::BothMatch { pstr_loc1, pstr_loc2, null_offset } => {
+                // exhaustive match
+                let tail1 = Heap::neighboring_cell_offset(pstr_loc1 + null_offset);
+                let tail2 = Heap::neighboring_cell_offset(pstr_loc2 + null_offset);
+
+                pdl.push(heap_loc_as_cell!(tail1));
+                pdl.push(heap_loc_as_cell!(tail2));
             }
-            Literal::Rational(bigint_ptr) => {
-                typed_arena_ptr_as_cell!(bigint_ptr)
+            PStrSegmentCmpResult::Mismatch { c1, c2 } => {
+                return Some(c1.cmp(&c2));
             }
-            Literal::Float(f) => HeapCellValue::from(f.as_ptr()),
-            Literal::String(s) => {
-                if s == atom!("") {
-                    empty_list_as_cell!()
-                } else {
-                    string_as_cstr_cell!(s)
+        }
+
+        None
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct HeapView<'a> {
+    slice: *const u8,
+    cell_offset: usize,
+    slice_cell_len: usize,
+    pstr_slice: &'a BitSlice,
+}
+
+impl<'a> HeapView<'a> {
+    /*
+    pub fn get(&self, idx: usize) -> Option<HeapCellValue> {
+        if idx < self.slice_cell_len {
+            Some(*self.index(idx))
+        } else {
+            None
+        }
+    }
+    */
+
+    fn iter_follow(&mut self) -> Option<HeapCellValue> {
+        if self.slice_cell_len == 0 {
+            None
+        } else {
+            let cell;
+
+            if self.pstr_slice[0] {
+                cell = pstr_loc_as_cell!(heap_index!(self.cell_offset));
+                let next_cell_idx = self.pstr_slice[0 ..].first_zero().unwrap();
+
+                unsafe { self.slice = self.slice.add(heap_index!(next_cell_idx)); }
+                self.slice_cell_len -= next_cell_idx;
+                self.cell_offset += next_cell_idx;
+                self.pstr_slice = &self.pstr_slice[next_cell_idx ..];
+            } else {
+                unsafe {
+                    cell = ptr::read(self.slice as *mut HeapCellValue);
+                    self.slice = self.slice.add(heap_index!(1));
                 }
+
+                self.cell_offset += 1;
+                self.slice_cell_len -= 1;
+                self.pstr_slice = &self.pstr_slice[1 ..];
             }
+
+            Some(cell)
         }
     }
 }
 
-impl TryFrom<HeapCellValue> for Literal {
-    type Error = ();
+impl<'a> Iterator for HeapView<'a> {
+    type Item = HeapCellValue;
 
-    fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
-        read_heap_cell!(value,
-            (HeapCellValueTag::Atom, (name, arity)) => {
-                if arity == 0 {
-                    Ok(Literal::Atom(name))
+    #[inline]
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter_follow()
+    }
+}
+
+impl<'a> Index<usize> for HeapView<'a> {
+    type Output = HeapCellValue;
+
+    fn index(&self, idx: usize) -> &Self::Output {
+        debug_assert!(idx < self.slice_cell_len);
+        unsafe {
+            &*(self.slice.add(heap_index!(idx)) as *const HeapCellValue)
+        }
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct HeapViewMut<'a> {
+    slice: *mut u8,
+    cell_offset: usize,
+    slice_cell_len: usize,
+    pstr_slice: &'a BitSlice,
+}
+
+impl<'a> HeapViewMut<'a> {
+    fn iter_follow(&mut self) -> Option<&'a mut HeapCellValue> {
+        if self.slice_cell_len == 0 {
+            None
+        } else {
+            let cell;
+
+            loop {
+                if self.pstr_slice[0] {
+                    let next_cell_idx = self.pstr_slice[0 ..].first_zero().unwrap();
+
+                    unsafe { self.slice = self.slice.add(heap_index!(next_cell_idx)); }
+
+                    self.slice_cell_len -= next_cell_idx;
+                    self.cell_offset += next_cell_idx;
+                    self.pstr_slice = &self.pstr_slice[next_cell_idx ..];
                 } else {
-                    Err(())
+                    unsafe {
+                        cell = &mut *(self.slice as *mut HeapCellValue);
+                        self.slice = self.slice.add(heap_index!(1));
+                    }
+
+                    self.cell_offset += 1;
+                    self.slice_cell_len -= 1;
+                    self.pstr_slice = &self.pstr_slice[1 ..];
+
+                    break;
                 }
             }
-            (HeapCellValueTag::Char, c) => {
-                Ok(Literal::Char(c))
+
+            Some(cell)
+        }
+    }
+}
+
+
+
+impl<'a> Index<usize> for HeapViewMut<'a> {
+    type Output = HeapCellValue;
+
+    fn index(&self, idx: usize) -> &Self::Output {
+        debug_assert!(idx < self.slice_cell_len);
+        unsafe {
+            &*(self.slice.add(heap_index!(idx)) as *const HeapCellValue)
+        }
+    }
+}
+
+impl<'a> IndexMut<usize> for HeapViewMut<'a> {
+    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
+        debug_assert!(idx < self.slice_cell_len);
+        unsafe {
+            &mut *(self.slice.add(heap_index!(idx)) as *mut HeapCellValue)
+        }
+    }
+}
+
+impl<'a> Iterator for &'a mut HeapViewMut<'a> {
+    type Item = &'a mut HeapCellValue;
+
+    #[inline]
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter_follow()
+    }
+}
+
+#[derive(Debug)]
+pub struct PStrWriteInfo {
+    pstr_loc: usize,
+}
+
+#[derive(Debug)]
+pub(crate) struct ReservedHeapSection<'a> {
+    heap_ptr: *mut u8,
+    heap_cell_len: usize,
+    pstr_vec: &'a mut BitVec,
+}
+
+impl<'a> ReservedHeapSection<'a> {
+    #[inline]
+    pub(crate) fn cell_len(&self) -> usize {
+        self.heap_cell_len
+    }
+
+    pub(crate) fn push_cell(&mut self, cell: HeapCellValue) {
+        unsafe {
+            ptr::write(self.heap_ptr.add(heap_index!(self.heap_cell_len)) as *mut _, cell);
+        }
+        self.pstr_vec.push(false);
+        self.heap_cell_len += 1;
+    }
+
+    fn push_pstr_segment(
+        &mut self,
+        src: &str,
+    ) -> usize {
+        if src.is_empty() {
+            return 0;
+        }
+
+        let cells_written;
+        let str_byte_len = src.len();
+
+        const ALIGN_CELL: usize = Heap::heap_cell_alignment();
+
+        unsafe {
+            ptr::copy_nonoverlapping(
+                src.as_ptr(),
+                self.heap_ptr.add(heap_index!(self.heap_cell_len)),
+                str_byte_len,
+            );
+
+            let zero_region_idx = heap_index!(self.heap_cell_len) + str_byte_len;
+
+            let align_offset = self.heap_ptr
+                .add(zero_region_idx)
+                .align_offset(ALIGN_CELL);
+
+            let align_offset = if align_offset == 0 {
+                ALIGN_CELL
+            } else {
+                align_offset
+            };
+
+            ptr::write_bytes(
+                self.heap_ptr.add(zero_region_idx),
+                0u8,
+                align_offset,
+            );
+
+            cells_written = cell_index!(src.len() + align_offset);
+            self.heap_cell_len += cells_written;
+        }
+
+        cells_written
+    }
+
+    pub(crate) fn push_pstr(
+        &mut self,
+        mut src: &str,
+    ) -> Option<HeapCellValue> {
+        let orig_h = self.cell_len();
+
+        if src.is_empty() {
+            return if orig_h == self.heap_cell_len {
+                // src is empty and always was. nothing allocated
+                // in this case, so nothing to point to in heap.
+                None
+            } else {
+                self.push_cell(heap_loc_as_cell!(orig_h));
+                Some(heap_loc_as_cell!(orig_h))
+            };
+        }
+
+        loop {
+            let null_char_idx = src.find('\u{0}').unwrap_or_else(|| src.len());
+
+            let cell_len = self.cell_len();
+            let cells_written = self.push_pstr_segment(&src[0..null_char_idx]);
+            let tail_idx = self.cell_len();
+
+            self.pstr_vec.resize(cell_len + cells_written, true);
+
+            if cells_written == 0 {
+                return None;
+            } else if null_char_idx + 1 < src.len() {
+                self.push_cell(pstr_loc_as_cell!(heap_index!(tail_idx + 1)));
+                src = &src[null_char_idx + 1 ..];
+            } else {
+                return Some(pstr_loc_as_cell!(heap_index!(orig_h)));
+            }
+        }
+    }
+
+    pub(crate) fn functor_writer(
+        functor: Vec<FunctorElement>,
+    ) -> impl FnMut(&mut ReservedHeapSection) {
+        struct FunctorData<'a> {
+            functor: &'a Vec<FunctorElement>,
+            cell_offset: usize,
+            cursor: usize,
+        }
+
+        move |section| {
+            let mut functor_stack = vec![FunctorData {
+                functor: &functor,
+                cell_offset: section.heap_cell_len,
+                cursor: 0,
+            }];
+
+            while let Some(FunctorData { functor, cell_offset, mut cursor }) = functor_stack.pop() {
+                while cursor < functor.len() {
+                    match &functor[cursor] {
+                        &FunctorElement::AbsoluteCell(cell) => {
+                            section.push_cell(cell);
+                        }
+                        &FunctorElement::Cell(cell) => {
+                            section.push_cell(cell + cell_offset);
+                        }
+                        &FunctorElement::String(_cell_len, ref string) => {
+                            if section.push_pstr(&string).is_some() {
+                                section.push_cell(empty_list_as_cell!());
+                            }
+                        }
+                        FunctorElement::InnerFunctor(_inner_size, succ_functor) => {
+                            if cursor + 1 < functor.len() {
+                                functor_stack.push(FunctorData {
+                                    functor: &functor,
+                                    cell_offset,
+                                    cursor: cursor + 1,
+                                });
+                            }
+
+                            functor_stack.push(FunctorData {
+                                functor: succ_functor,
+                                cell_offset: section.heap_cell_len,
+                                cursor: 0,
+                            });
+
+                            break;
+                        }
+                    }
+
+                    cursor += 1;
+                }
             }
-            (HeapCellValueTag::Fixnum, n) => {
-                Ok(Literal::Fixnum(n))
+        }
+    }
+}
+
+impl<'a> Index<usize> for ReservedHeapSection<'a> {
+    type Output = HeapCellValue;
+
+    #[inline]
+    fn index(&self, idx: usize) -> &Self::Output {
+        debug_assert!(idx < self.heap_cell_len);
+        unsafe {
+            &*(self.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue)
+        }
+    }
+}
+
+#[must_use]
+#[derive(Debug)]
+pub struct HeapWriter<'a> {
+    section: ReservedHeapSection<'a>,
+    heap_byte_len: &'a mut usize,
+}
+
+impl<'a> HeapWriter<'a> {
+    #[allow(dead_code)]
+    pub(crate) fn write_with_error_handling<E>(
+        &mut self,
+        writer: impl FnOnce(&mut ReservedHeapSection) -> Result<(), E>,
+    ) -> Result<usize, E> {
+        let old_section_cell_len = self.section.heap_cell_len;
+        writer(&mut self.section)?;
+        *self.heap_byte_len = heap_index!(self.section.heap_cell_len);
+
+        // return the number of bytes written
+        Ok(heap_index!(self.section.heap_cell_len - old_section_cell_len))
+    }
+
+    pub(crate) fn write_with(
+        &mut self,
+        writer: impl FnOnce(&mut ReservedHeapSection),
+    ) -> usize {
+        let old_section_cell_len = self.section.heap_cell_len;
+        writer(&mut self.section);
+        *self.heap_byte_len = heap_index!(self.section.heap_cell_len);
+
+        // return the number of bytes written
+        heap_index!(self.section.heap_cell_len - old_section_cell_len)
+    }
+
+    #[inline]
+    pub(crate) fn truncate(&mut self, cell_offset: usize) {
+        self.section.heap_cell_len = cell_offset;
+        self.section.pstr_vec.truncate(cell_offset);
+        *self.heap_byte_len = heap_index!(cell_offset);
+    }
+
+    #[inline]
+    pub(crate) fn is_empty(&self) -> bool {
+        self.section.heap_cell_len == 0
+    }
+
+    #[inline]
+    pub(crate) fn cell_len(&self) -> usize {
+        self.section.heap_cell_len
+    }
+}
+
+impl<'a> Index<usize> for HeapWriter<'a> {
+    type Output = HeapCellValue;
+
+    #[inline]
+    fn index(&self, idx: usize) -> &Self::Output {
+        debug_assert!(heap_index!(idx) < *self.heap_byte_len);
+        unsafe {
+            &*(self.section.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue)
+        }
+    }
+}
+
+impl<'a> IndexMut<usize> for HeapWriter<'a> {
+    #[inline]
+    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
+        debug_assert!(heap_index!(idx) < *self.heap_byte_len);
+        unsafe {
+            &mut *(self.section.heap_ptr.add(heap_index!(idx)) as *mut HeapCellValue)
+        }
+    }
+}
+
+impl<'a> SizedHeap for HeapWriter<'a> {
+    fn cell_len(&self) -> usize {
+        self.section.cell_len()
+    }
+
+    fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) {
+        let (s, tail_cell_offset) = scan_slice_to_str(
+            unsafe { self.section.heap_ptr.add(slice_loc) },
+            &self.section.pstr_vec.as_bitslice()[cell_index!(slice_loc) ..],
+        );
+
+        (s, cell_index!(slice_loc) + tail_cell_offset)
+    }
+
+    fn pstr_at(&self, cell_offset: usize) -> bool {
+        self.section.pstr_vec[cell_offset]
+    }
+}
+
+impl<'a> SizedHeapMut for HeapWriter<'a> {}
+
+impl Heap {
+    pub(crate) fn new() -> Self {
+        Self {
+            inner: InnerHeap {
+                ptr: ptr::null_mut(),
+                byte_len: 0,
+                byte_cap: 0,
+            },
+            pstr_vec: bitvec![],
+            resource_err_loc: 0,
+        }
+    }
+
+    #[inline(always)]
+    unsafe fn grow(&mut self) -> bool {
+        let result = self.inner.grow();
+
+        if result {
+            self.pstr_vec.reserve(cell_index!(self.inner.byte_cap));
+        }
+
+        result
+    }
+
+    #[inline]
+    fn resource_error_offset(&self) -> usize {
+        self.resource_err_loc
+    }
+
+    pub(crate) fn with_cell_capacity(cap: usize) -> Result<Self, usize> {
+        let ptr = unsafe {
+            let layout = alloc::Layout::array::<HeapCellValue>(cap).unwrap();
+            alloc::alloc(layout)
+        };
+
+        if ptr.is_null() {
+            panic!("could not allocate {} bytes for heap!", heap_index!(cap))
+        } else {
+            Ok(Self {
+                inner: InnerHeap {
+                    ptr,
+                    byte_len: 0,
+                    byte_cap: heap_index!(cap),
+                },
+                pstr_vec: bitvec![],
+                resource_err_loc: 0,
+            })
+        }
+    }
+
+    #[must_use]
+    pub fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize> {
+        let section;
+        let len = heap_index!(num_cells);
+
+        loop {
+            unsafe {
+                if self.free_space() >= len {
+                    section = ReservedHeapSection {
+                        heap_ptr: self.inner.ptr,
+                        heap_cell_len: cell_index!(self.inner.byte_len),
+                        pstr_vec: &mut self.pstr_vec,
+                    };
+                    break;
+                } else if !self.grow() {
+                    return Err(self.resource_error_offset());
+                }
             }
-            (HeapCellValueTag::F64, f) => {
-                Ok(Literal::Float(f.as_offset()))
+        }
+
+        Ok(HeapWriter {
+            section,
+            heap_byte_len: &mut self.inner.byte_len,
+        })
+    }
+
+    pub(crate) fn last_cell_mut(&mut self) -> Option<&mut HeapCellValue> {
+        if self.inner.byte_len == 0 {
+            None
+        } else {
+            unsafe {
+                Some(&mut *(self.inner.ptr.add(self.inner.byte_len - heap_index!(1))
+                            as *mut HeapCellValue))
             }
-            (HeapCellValueTag::Cons, cons_ptr) => {
-                match_untyped_arena_ptr!(cons_ptr,
-                     (ArenaHeaderTag::Integer, n) => {
-                         Ok(Literal::Integer(n))
-                     }
-                     (ArenaHeaderTag::Rational, n) => {
-                         Ok(Literal::Rational(n))
-                     }
-                     (ArenaHeaderTag::IndexPtr, ip) => {
-                         Ok(Literal::CodeIndex(CodeIndex::from(ip)))
-                     }
-                     _ => {
-                         Err(())
-                     }
-                )
+        }
+    }
+
+    pub(crate) fn last_cell(&mut self) -> Option<HeapCellValue> {
+        if self.inner.byte_len == 0 {
+            None
+        } else {
+            unsafe {
+                Some(ptr::read(self.inner.ptr.add(self.inner.byte_len - heap_index!(1))
+                               as *const HeapCellValue))
             }
-            (HeapCellValueTag::CStr, cstr_atom) => {
-                Ok(Literal::String(cstr_atom))
+        }
+    }
+
+    #[inline]
+    pub(crate) fn is_empty(&self) -> bool {
+        self.inner.byte_len == 0
+    }
+
+    pub(crate) fn index_of(&mut self, cell: HeapCellValue) -> Result<usize, usize> {
+        Ok(if cell.is_var() {
+            cell.get_value() as usize
+        } else {
+            let focus = self.cell_len();
+            self.push_cell(cell)?;
+            focus
+        })
+    }
+
+    pub(crate) fn clear(&mut self) {
+        unsafe {
+            let layout = alloc::Layout::array::<u8>(self.inner.byte_cap).unwrap();
+            alloc::dealloc(self.inner.ptr, layout);
+        }
+
+        self.inner.ptr = ptr::null_mut();
+        self.inner.byte_len = 0;
+        self.inner.byte_cap = 0;
+
+        self.pstr_vec.clear();
+    }
+
+    pub(crate) fn append(&mut self, heap_slice: HeapView) -> Result<(), usize> {
+        unsafe {
+            loop {
+                if self.free_space() >= heap_index!(heap_slice.slice_cell_len) {
+                    ptr::copy_nonoverlapping(
+                        heap_slice.slice,
+                        self.inner.ptr.add(self.inner.byte_len),
+                        heap_index!(heap_slice.slice_cell_len),
+                    );
+
+                    self.inner.byte_len += heap_index!(heap_slice.slice_cell_len);
+                    self.pstr_vec.extend(heap_slice.pstr_slice.iter());
+
+                    break;
+                } else if !self.grow() {
+                    return Err(self.resource_error_offset());
+                }
             }
-            _ => {
-                Err(())
+        }
+
+        Ok(())
+    }
+
+    pub(crate) fn store_resource_error(&mut self) {
+        RESOURCE_ERROR_OFFSET_INIT.call_once(move || {
+            let stub = functor!(atom!("resource_error"), [atom_as_cell((atom!("memory")))]);
+            self.resource_err_loc = cell_index!(self.inner.byte_len);
+
+            let mut writer = Heap::functor_writer(stub);
+            writer(self).unwrap();
+        });
+    }
+
+    pub(crate) fn compare_pstr_segments(
+        &self,
+        pstr_loc1: usize,
+        pstr_loc2: usize,
+    ) -> PStrSegmentCmpResult {
+        unsafe {
+            let slice1 = std::slice::from_raw_parts(
+                self.inner.ptr.add(pstr_loc1),
+                self.inner.byte_len - pstr_loc1,
+            );
+
+            let slice2 = std::slice::from_raw_parts(
+                self.inner.ptr.add(pstr_loc2),
+                self.inner.byte_len - pstr_loc2,
+            );
+
+            let str1 = std::str::from_utf8_unchecked(&slice1);
+            let str2 = std::str::from_utf8_unchecked(&slice2);
+
+            debug_assert!(!str1.is_empty());
+            debug_assert!(!str2.is_empty());
+
+            for ((idx, c1), c2) in str1.char_indices().zip(str2.chars()) {
+                if c1 == '\u{0}' && c2 == '\u{0}' {
+                    return PStrSegmentCmpResult::BothMatch { pstr_loc1, pstr_loc2, null_offset: idx };
+                } else if c1 == '\u{0}' {
+                    return PStrSegmentCmpResult::FirstMatch { pstr_loc1, pstr_loc2, l1_offset: idx };
+                } else if c2 == '\u{0}' {
+                    return PStrSegmentCmpResult::SecondMatch { pstr_loc1, pstr_loc2, l2_offset: idx };
+                } else if c1 != c2 {
+                    return PStrSegmentCmpResult::Mismatch { c1, c2 };
+                }
+            }
+
+            unreachable!() // PStrSegmentCmpResult::Match(std::cmp::min(str1.len(), str2.len()))
+        }
+    }
+
+    #[inline]
+    pub(crate) fn slice_to_str(&self, slice_loc: usize, slice_len: usize) -> &str {
+        unsafe {
+            let slice = std::slice::from_raw_parts(self.inner.ptr.add(slice_loc), slice_len);
+            std::str::from_utf8_unchecked(&slice)
+        }
+    }
+
+    #[inline]
+    pub(crate) fn byte_len(&self) -> usize {
+        self.inner.byte_len
+    }
+
+    #[inline]
+    pub(crate) fn cell_len(&self) -> usize {
+        cell_index!(self.inner.byte_len)
+    }
+
+    // free space in bytes.
+    #[inline]
+    fn free_space(&self) -> usize {
+        self.inner.byte_cap - self.inner.byte_len
+    }
+
+    pub(crate) fn char_iter<'a>(&'a self, pstr_loc: usize) -> PStrSegmentIter<'a> {
+        PStrSegmentIter::from(self, pstr_loc)
+    }
+
+    // either succeed & return nothing or fail & return an offset into
+    // the heap to a pre-allocated resource error
+    pub(crate) fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), usize> {
+        unsafe {
+            if self.inner.byte_len == self.inner.byte_cap {
+                if !self.grow() {
+                    return Err(self.resource_error_offset());
+                }
+            }
+
+            let cell_ptr = (self.inner.ptr as *mut HeapCellValue).add(self.cell_len());
+            cell_ptr.write(cell);
+            self.pstr_vec.push(false);
+            self.inner.byte_len += heap_index!(1);
+        }
+
+        Ok(())
+    }
+
+    /*
+    pub(crate) fn pop_cell(&mut self) -> Option<HeapCellValue> {
+        unsafe {
+            if self.inner.byte_len > 0 {
+                let cell_ptr = (self.inner.ptr as *const HeapCellValue)
+                    .add(self.cell_len())
+                    .sub(1);
+                let cell = ptr::read(cell_ptr);
+
+                self.inner.byte_len -= heap_index!(1);
+                self.pstr_vec.pop();
+
+                Some(cell)
+            } else {
+                None
+            }
+        }
+    }
+    */
+
+    fn slice_range<R: RangeBounds<usize>>(&self, range: R) -> Range<usize> {
+        let start = match range.start_bound() {
+            Bound::Included(lower_bound) => *lower_bound,
+            Bound::Excluded(lower_bound) => *lower_bound + 1,
+            Bound::Unbounded => 0,
+        };
+
+        let end = match range.end_bound() {
+            Bound::Included(upper_bound) => *upper_bound + 1,
+            Bound::Excluded(0) => 0,
+            Bound::Excluded(upper_bound) => *upper_bound,
+            Bound::Unbounded => self.cell_len(),
+        };
+
+        Range { start, end }
+    }
+
+    pub(crate) fn splice<R: RangeBounds<usize>>(
+        &self,
+        range: R,
+    ) -> HeapView {
+        let range = self.slice_range(range);
+
+        HeapView {
+            slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) },
+            cell_offset: range.start,
+            slice_cell_len: range.end - range.start,
+            pstr_slice: &self.pstr_vec.as_bitslice()[range],
+        }
+    }
+
+    pub(crate) fn splice_mut<R: RangeBounds<usize>>(
+        &self,
+        range: R,
+    ) -> HeapViewMut {
+        let range = self.slice_range(range);
+
+        HeapViewMut {
+            slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) },
+            cell_offset: range.start,
+            slice_cell_len: range.end - range.start,
+            pstr_slice: &self.pstr_vec.as_bitslice()[range],
+        }
+    }
+
+    pub fn allocate_pstr(&mut self, src: &str) -> Result<Option<PStrWriteInfo>, usize> {
+        let size_in_heap = Self::compute_pstr_size(src);
+        let pstr_loc = heap_index!(self.cell_len());
+
+        let mut writer = self.reserve(size_in_heap)?;
+        writer.write_with(|section| {
+            section.push_pstr(src);
+        });
+
+        Ok(if size_in_heap > 0 {
+            Some(PStrWriteInfo { pstr_loc })
+        } else {
+            None
+        })
+    }
+
+    const fn heap_cell_alignment() -> usize {
+        // yes, size_of, not align_of. the alignment of HeapCellValue
+        // is 1 byte. In the heap, though, its alignment must be its
+        // size.
+        mem::size_of::<HeapCellValue>()
+    }
+
+    // takes a byte offset into the Heap ptr.
+    #[inline(always)]
+    pub(crate) const fn neighboring_cell_offset(offset: usize) -> usize {
+        const ALIGN_CELL: usize = Heap::heap_cell_alignment();
+        cell_index!((offset & !(ALIGN_CELL - 1)) + ALIGN_CELL)
+    }
+
+    #[inline]
+    pub(crate) fn iter(&self) -> HeapView {
+        HeapView {
+            slice: self.inner.ptr,
+            cell_offset: 0,
+            slice_cell_len: cell_index!(self.inner.byte_len),
+            pstr_slice: &self.pstr_vec.as_bitslice(),
+        }
+    }
+
+    #[inline]
+    pub(crate) fn pstr_vec(&self) -> &BitSlice<usize> {
+        self.pstr_vec.as_bitslice()
+    }
+
+    #[inline]
+    pub(crate) fn char_at(&self, byte_idx: usize) -> char {
+        let s = unsafe {
+            let char_ptr = self.inner.ptr.add(byte_idx);
+            let slice = std::slice::from_raw_parts(char_ptr, mem::size_of::<char>());
+            std::str::from_utf8_unchecked(&slice)
+        };
+
+        s.chars().next().unwrap()
+    }
+
+    pub(crate) fn last_str_char_and_tail(&self, loc: usize) -> (char, HeapCellValue) {
+        unsafe {
+            let char_ptr = self.inner.ptr.add(loc);
+            let slice = std::slice::from_raw_parts(char_ptr, self.inner.byte_len - loc);
+
+            let s = std::str::from_utf8_unchecked(&slice);
+            let mut chars_iter = s.chars();
+            let c = chars_iter.next().unwrap();
+            let succ_len = loc + c.len_utf8();
+
+            if chars_iter.next() == Some('\u{0}') {
+                (c, heap_loc_as_cell!(Self::neighboring_cell_offset(succ_len)))
+            } else {
+                (c, pstr_loc_as_cell!(succ_len))
+            }
+        }
+    }
+
+    // copies only the string, not its tail. returns the cell index of
+    // the tail location
+    pub(crate) fn copy_pstr_within(&mut self, pstr_loc: usize) -> Result<usize, usize> {
+        let (s, tail_loc) = self.scan_slice_to_str(pstr_loc);
+        let s_len = s.len();
+
+        const ALIGN_CELL: usize = Heap::heap_cell_alignment();
+
+        let align_offset = unsafe {
+            self.inner.ptr
+                .add(self.inner.byte_len + s_len)
+                .align_offset(ALIGN_CELL)
+        };
+
+        let align_offset = if align_offset == 0 {
+            ALIGN_CELL
+        } else {
+            align_offset
+        };
+
+        let copy_size = s_len + align_offset;
+
+        unsafe {
+            loop {
+                if self.free_space() >= copy_size {
+                    let slice = std::slice::from_raw_parts_mut(
+                        self.inner.ptr,
+                        self.inner.byte_len + s_len,
+                    );
+
+                    slice.copy_within(
+                        pstr_loc .. pstr_loc + s_len,
+                        self.inner.byte_len,
+                    );
+
+                    ptr::write_bytes(
+                        self.inner.ptr.add(self.inner.byte_len + s_len),
+                        0u8,
+                        align_offset,
+                    );
+
+                    self.inner.byte_len += copy_size;
+                    self.pstr_vec.resize(self.cell_len(), true);
+
+                    break;
+                } else if !self.grow() {
+                    return Err(self.resource_error_offset());
+                }
+            }
+        }
+
+        Ok(tail_loc)
+    }
+
+    // src is a cell-indexed range.
+    pub(crate) fn copy_slice_to_end<R: RangeBounds<usize>>(&mut self, src: R) -> Result<(), usize> {
+        let range = self.slice_range(src);
+        let len = range.end - range.start;
+
+        unsafe {
+            loop {
+                if self.free_space() >= len {
+                    ptr::copy_nonoverlapping(
+                        self.inner.ptr.add(heap_index!(range.start)),
+                        self.inner.ptr.add(self.inner.byte_len),
+                        heap_index!(len),
+                    );
+
+                    self.pstr_vec.resize(self.cell_len() + len, false);
+                    self.inner.byte_len += heap_index!(len);
+
+                    break;
+                } else if !self.grow() {
+                    return Err(self.resource_error_offset());
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    pub(crate) const fn compute_pstr_size(src: &str) -> usize {
+        const ALIGN_CELL: usize = Heap::heap_cell_alignment();
+
+        let mut byte_size = 0;
+        let mut null_idx = 0;
+
+        loop {
+            let src_bytes = src.as_bytes();
+
+            while null_idx < src_bytes.len() {
+                if src_bytes[null_idx] == 0u8 {
+                    break;
+                }
+
+                null_idx += 1;
+            }
+
+            byte_size += (null_idx & !(ALIGN_CELL - 1)) + ALIGN_CELL;
+            byte_size += mem::size_of::<HeapCellValue>();
+
+            if null_idx + 1 >= src.len() {
+                break;
+            } else {
+                null_idx += 1;
+            }
+        }
+
+        byte_size
+    }
+
+    pub(crate) const fn compute_functor_byte_size(functor: &[FunctorElement]) -> usize {
+        let mut byte_size = 0;
+        let mut idx = 0;
+
+        while idx < functor.len() {
+            match &functor[idx] {
+                &FunctorElement::InnerFunctor(inner_cell_size, ref _inner_functor) => {
+                    byte_size += inner_cell_size as usize * mem::size_of::<HeapCellValue>();
+                }
+                FunctorElement::AbsoluteCell(_cell) | FunctorElement::Cell(_cell) => {
+                    byte_size += mem::size_of::<HeapCellValue>();
+                }
+                &FunctorElement::String(cell_len, _) => {
+                    byte_size += cell_len as usize * mem::size_of::<HeapCellValue>();
+                }
             }
-        )
+
+            idx += 1;
+        }
+
+        byte_size
+    }
+
+    pub(crate) fn functor_writer(
+        functor: Vec<FunctorElement>,
+    ) -> impl FnMut(&mut Heap) -> Result<HeapCellValue, usize> {
+        let size = Heap::compute_functor_byte_size(&functor);
+        let mut functor_writer = ReservedHeapSection::functor_writer(functor);
+
+        move |heap| {
+            let mut writer = heap.reserve(size)?;
+            let heap_byte_len = *writer.heap_byte_len;
+            let bytes_written = writer.write_with(&mut functor_writer);
+
+            Ok(if cell_index!(bytes_written) > 1 {
+                str_loc_as_cell!(cell_index!(heap_byte_len))
+            } else {
+                heap_loc_as_cell!(cell_index!(heap_byte_len))
+            })
+        }
+    }
+
+    #[inline]
+    pub(crate) fn truncate(&mut self, cell_offset: usize) {
+        self.inner.byte_len = heap_index!(cell_offset);
+        self.pstr_vec.truncate(cell_offset);
+    }
+}
+
+
+
+pub(crate) struct PStrSegmentIter<'a> {
+    string_buf: &'a str,
+}
+
+impl<'a> PStrSegmentIter<'a> {
+    fn from(heap: &'a Heap, pstr_loc: usize) -> Self {
+        debug_assert!(pstr_loc <= heap.inner.byte_len);
+
+        let string_buf = unsafe {
+            let char_ptr = heap.inner.ptr.add(pstr_loc);
+            let slice = std::slice::from_raw_parts(char_ptr, heap.inner.byte_len - pstr_loc);
+            std::str::from_utf8_unchecked(&slice)
+        };
+
+        PStrSegmentIter { string_buf }
     }
 }
 
+impl<'a> Iterator for PStrSegmentIter<'a> {
+    type Item = char;
+
+    #[inline]
+    fn next(&mut self) -> Option<Self::Item> {
+        self.string_buf.chars().next().and_then(|c| {
+            if c == '\u{0}' {
+                None
+            } else {
+                self.string_buf = &self.string_buf[c.len_utf8() ..];
+                Some(c)
+            }
+        })
+    }
+}
+
+impl MachineState {
+    pub(crate) fn allocate_pstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
+        match self.heap.allocate_pstr(src)? {
+            None => Ok(empty_list_as_cell!()),
+            Some(PStrWriteInfo { pstr_loc, .. }) => Ok(pstr_loc_as_cell!(pstr_loc)),
+        }
+    }
+
+    // note that allocate_cstr does emit a tail cell to the string
+    // (completing it with the empty list), allocate_pstr does not, in
+    // any incarnation.
+    pub(crate) fn allocate_cstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
+        match self.heap.allocate_pstr(src)? {
+            None => Ok(empty_list_as_cell!()),
+            Some(PStrWriteInfo { pstr_loc, .. }) => {
+                self.heap.push_cell(empty_list_as_cell!())?;
+                Ok(pstr_loc_as_cell!(pstr_loc))
+            }
+        }
+    }
+}
+
+pub trait SizedHeap: Index<usize, Output = HeapCellValue> {
+    // return the size of the instance in cells
+    fn cell_len(&self) -> usize;
+
+    // return a pointer to the heap string and the cell index of its tail
+    fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize);
+
+    // return true iff a partial string is stored at cell_offset.
+    fn pstr_at(&self, cell_offset: usize) -> bool;
+}
+
+pub trait SizedHeapMut: IndexMut<usize, Output = HeapCellValue> + SizedHeap {
+}
+
+impl Index<usize> for Heap {
+    type Output = HeapCellValue;
+
+    fn index(&self, idx: usize) -> &Self::Output {
+        unsafe { &*(self.inner.ptr as *const HeapCellValue).add(idx) }
+    }
+}
+
+impl IndexMut<usize> for Heap {
+    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
+        unsafe { &mut *(self.inner.ptr as *mut HeapCellValue).add(idx) }
+    }
+}
+
+impl SizedHeap for Heap {
+    fn cell_len(&self) -> usize {
+        self.cell_len()
+    }
+
+    fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) {
+        let (s, tail_cell_offset) = scan_slice_to_str(
+            unsafe { self.inner.ptr.add(slice_loc) },
+            &self.pstr_vec.as_bitslice()[cell_index!(slice_loc) ..],
+        );
+
+        (s, cell_index!(slice_loc) + tail_cell_offset)
+    }
+
+    fn pstr_at(&self, cell_offset: usize) -> bool {
+        self.pstr_vec[cell_offset]
+    }
+}
+
+impl SizedHeapMut for Heap {}
+
+impl<'a> SizedHeap for HeapView<'a> {
+    fn cell_len(&self) -> usize {
+        self.slice_cell_len
+    }
+
+    fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) {
+        let (s, tail_cell_offset) = scan_slice_to_str(
+            unsafe { self.slice.add(slice_loc) },
+            &self.pstr_slice[cell_index!(slice_loc) ..],
+        );
+
+        (s, cell_index!(slice_loc) + tail_cell_offset)
+    }
+
+    fn pstr_at(&self, cell_offset: usize) -> bool {
+        self.pstr_slice[cell_offset]
+    }
+}
+
+impl<'a> SizedHeap for HeapViewMut<'a> {
+    fn cell_len(&self) -> usize {
+        self.slice_cell_len
+    }
+
+    fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) {
+        let (s, tail_cell_offset) = scan_slice_to_str(
+            unsafe { self.slice.add(slice_loc) },
+            &self.pstr_slice[cell_index!(slice_loc) ..],
+        );
+
+        (s, cell_index!(slice_loc) + tail_cell_offset)
+    }
+
+    fn pstr_at(&self, cell_offset: usize) -> bool {
+        self.pstr_slice[cell_offset]
+    }
+}
+
+impl<'a> SizedHeapMut for HeapViewMut<'a> {}
+
 // sometimes we need to dereference variables that are found only in
 // the heap without access to the full WAM (e.g., while detecting
 // cycles in terms), and which therefore may only point other cells in
 // the heap (thanks to the design of the WAM).
-pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue {
+pub fn heap_bound_deref(heap: &impl SizedHeap, mut value: HeapCellValue) -> HeapCellValue {
     loop {
         let new_value = read_heap_cell!(value,
             (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
@@ -111,7 +1277,7 @@ pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> Hea
     }
 }
 
-pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue {
+pub fn heap_bound_store(heap: &impl SizedHeap, value: HeapCellValue) -> HeapCellValue {
     read_heap_cell!(value,
         (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
             heap[h]
@@ -123,123 +1289,34 @@ pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCel
 }
 
 #[allow(dead_code)]
-pub fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
+pub fn print_heap_terms<'a, I: Iterator<Item = HeapCellValue>>(heap: I, h: usize) {
     for (index, term) in heap.enumerate() {
         println!("{} : {:?}", h + index, term);
     }
 }
 
-#[inline]
-pub(crate) fn put_complete_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue {
-    match allocate_pstr(heap, s, atom_tbl) {
-        Some(h) => {
-            heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.
-
-            if heap.len() == h + 1 {
-                let pstr_atom = cell_as_atom!(heap[h]);
-                heap[h] = atom_as_cstr_cell!(pstr_atom);
-                heap_loc_as_cell!(h)
-            } else {
-                heap.push(empty_list_as_cell!());
-                pstr_loc_as_cell!(h)
-            }
-        }
-        None => {
-            let h = heap.len();
-            heap.push(empty_list_as_cell!());
-            heap_loc_as_cell!(h)
-        }
-    }
-}
-
-#[inline]
-pub(crate) fn put_partial_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue {
-    match allocate_pstr(heap, s, atom_tbl) {
-        Some(h) => {
-            pstr_loc_as_cell!(h)
-        }
-        None => {
-            empty_list_as_cell!()
-        }
-    }
-}
-
-#[inline]
-pub(crate) fn allocate_pstr(heap: &mut Heap, mut src: &str, atom_tbl: &AtomTable) -> Option<usize> {
-    let orig_h = heap.len();
-
-    loop {
-        if src.is_empty() {
-            return if orig_h == heap.len() {
-                None
-            } else {
-                let tail_h = heap.len() - 1;
-                heap[tail_h] = heap_loc_as_cell!(tail_h);
-
-                Some(orig_h)
-            };
-        }
-
-        let h = heap.len();
-
-        let (pstr, rest_src) = match PartialString::new(src, atom_tbl) {
-            Some(tuple) => tuple,
-            None => {
-                if src.len() > '\u{0}'.len_utf8() {
-                    src = &src['\u{0}'.len_utf8()..];
-                    continue;
-                } else if orig_h == h {
-                    return None;
-                } else {
-                    heap[h - 1] = heap_loc_as_cell!(h - 1);
-                    return Some(orig_h);
-                }
-            }
-        };
-
-        heap.push(string_as_pstr_cell!(pstr));
-
-        if !rest_src.is_empty() {
-            heap.push(pstr_loc_as_cell!(h + 2));
-            src = rest_src;
-        } else {
-            heap.push(heap_loc_as_cell!(h + 1));
-            return Some(orig_h);
-        }
-    }
-}
-
-pub fn filtered_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
+pub fn sized_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
     heap: &mut Heap,
+    size: usize,
     values: impl Iterator<Item = SrcT>,
-    filter_fn: impl Fn(&Heap, HeapCellValue) -> bool,
-) -> usize {
-    let head_addr = heap.len();
-    let mut h = head_addr;
+) -> Result<HeapCellValue, usize> {
+    if size > 0 {
+        let h = heap.cell_len();
+        let mut writer = heap.reserve(1 + 2 * size)?;
 
-    for value in values {
-        let value = value.into();
+        writer.write_with(|section| {
+            for (idx, value) in values.enumerate() {
+                section.push_cell(list_loc_as_cell!(h + 1 + 2 * idx));
+                section.push_cell(value.into());
+            }
 
-        if filter_fn(heap, value) {
-            heap.push(list_loc_as_cell!(h + 1));
-            heap.push(value);
+            section.push_cell(empty_list_as_cell!());
+        });
 
-            h += 2;
-        }
+        Ok(heap_loc_as_cell!(h))
+    } else {
+        Ok(empty_list_as_cell!())
     }
-
-    heap.push(empty_list_as_cell!());
-
-    head_addr
-}
-
-#[inline(always)]
-pub fn iter_to_heap_list<Iter, SrcT>(heap: &mut Heap, values: Iter) -> usize
-where
-    Iter: Iterator<Item = SrcT>,
-    SrcT: Into<HeapCellValue>,
-{
-    filtered_iter_to_heap_list(heap, values, |_, _| true)
 }
 
 pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usize> {
index a144c1ca034d201df30da36bd02331c367757209..b6b4d253596d0aa9d89a792b18f41033a382859e 100644 (file)
@@ -1,10 +1,11 @@
 use std::collections::BTreeMap;
 
-use crate::atom_table;
-use crate::heap_print::{HCPrinter, HCValueOutputter, PrinterOutputter};
+use crate::atom_table::AtomTable;
 use crate::machine::mock_wam::CompositeOpDir;
-use crate::machine::{copy_and_align_iter, BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS};
-use crate::parser::parser::{Parser, Tokens};
+use crate::machine::{BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS};
+use crate::parser::ast::{TermWriteResult, Var};
+use crate::parser::lexer::*;
+use crate::parser::parser::Tokens;
 use indexmap::IndexMap;
 
 use super::{
@@ -16,7 +17,7 @@ pub struct QueryState<'a> {
     machine: &'a mut Machine,
     term: TermWriteResult,
     stub_b: usize,
-    var_names: IndexMap<HeapCellValue, VarPtr>,
+    var_names: IndexMap<HeapCellValue, Var>,
     called: bool,
 }
 
@@ -78,7 +79,7 @@ impl Iterator for QueryState<'_> {
         }
 
         if machine.machine_st.p == LIB_QUERY_SUCCESS {
-            if term_write_result.var_dict.is_empty() {
+            if term_write_result.inverse_var_locs.is_empty() {
                 self.machine.machine_st.backtrack();
                 return Some(Ok(QueryResolutionLine::True));
             }
@@ -87,47 +88,41 @@ impl Iterator for QueryState<'_> {
         }
 
         let mut bindings: BTreeMap<String, Value> = BTreeMap::new();
+        let inverse_var_locs = &term_write_result.inverse_var_locs;
 
-        let var_dict = &term_write_result.var_dict;
-
-        for (var_key, term_to_be_printed) in var_dict.iter() {
-            let mut var_name = var_key.to_string();
+        for (var_loc, var_name) in inverse_var_locs.iter() {
             if var_name.starts_with('_') {
-                let should_print = var_names.values().any(|x| match x.borrow().clone() {
-                    Var::Named(v) => v == var_name,
-                    _ => false,
+                let should_print = var_names.values().any(|v| {
+                    v == var_name
                 });
                 if !should_print {
                     continue;
                 }
             }
 
-            let mut term =
-                Value::from_heapcell(machine, *term_to_be_printed, &mut var_names.clone());
+            let var_loc = *var_loc;
+            let term = Value::from_heapcell(
+                machine,
+                heap_loc_as_cell!(var_loc),
+                &mut var_names.clone(),
+            );
 
             if let Value::Var(ref term_str) = term {
-                if *term_str == var_name {
+                if *term_str == **var_name {
                     continue;
                 }
 
-                // Var dict is in the order things appear in the query. If var_name appears
-                // after term in the query, switch their places.
-                let var_name_idx = var_dict
-                    .get_index_of(&VarKey::VarPtr(Var::Named(var_name.clone()).into()))
-                    .unwrap();
-                let term_idx =
-                    var_dict.get_index_of(&VarKey::VarPtr(Var::Named(term_str.clone()).into()));
-                if let Some(idx) = term_idx {
-                    if idx < var_name_idx {
-                        let new_term = Value::Var(var_name);
-                        let new_var_name = term_str.into();
-                        term = new_term;
-                        var_name = new_var_name;
-                    }
+                let var_cell = machine.machine_st.store(
+                    machine.machine_st.deref(machine.machine_st.heap[var_loc]),
+                );
+
+                if (var_cell.get_value() as usize) < var_loc {
+                    bindings.insert(term_str.clone(), Value::Var(var_name.to_string()));
+                    continue;
                 }
             }
 
-            bindings.insert(var_name, term);
+            bindings.insert(var_name.to_string(), term);
         }
 
         // NOTE: there are outstanding choicepoints, backtrack
@@ -153,7 +148,7 @@ impl Machine {
     pub fn consult_module_string(&mut self, module_name: &str, program: String) {
         let stream = Stream::from_owned_string(program, &mut self.machine_st.arena);
         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!(AtomTable::build_with(
             &self.machine_st.atom_tbl,
             module_name
         ));
@@ -181,7 +176,7 @@ impl Machine {
         or_frame.prelude.attr_var_queue_len = 0;
 
         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;
     }
 
@@ -190,27 +185,21 @@ impl Machine {
     }
 
     pub fn run_query_iter(&mut self, query: String) -> QueryState {
-        let mut parser = Parser::new(
+        let mut lexer_parser = LexerParser::new(
             Stream::from_owned_string(query, &mut self.machine_st.arena),
             &mut self.machine_st,
         );
+
+        // Write parsed term to heap
         let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
-        let term = parser
+        let term = lexer_parser
             .read_term(&op_dir, Tokens::Default)
             .expect("Failed to parse query");
 
         self.allocate_stub_choice_point();
 
-        // Write parsed term to heap
-        let heap_loc = self.machine_st.heap.len();
-        self.machine_st.heap.extend(copy_and_align_iter(
-            term.heap.iter().cloned(),
-            0,
-            heap_loc as i64,
-        ));
-
         // Write term to heap
-        self.machine_st.registers[1] = self.machine_st.heap[heap_loc + term.focus];
+        self.machine_st.registers[1] = self.machine_st.heap[term.focus];
 
         self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
         let call_index_p = self
@@ -225,8 +214,8 @@ impl Machine {
             .inverse_var_locs
             .iter()
             .map(|(var_loc, var)| {
-                let cell = term.heap[*var_loc];
-                (cell + heap_loc, var.clone())
+                let cell = self.machine_st.heap[*var_loc];
+                (cell, var.clone())
             })
             .collect();
 
@@ -235,7 +224,7 @@ impl Machine {
         let stub_b = self.machine_st.b;
         QueryState {
             machine: self,
-            term: term_write_result,
+            term,
             stub_b,
             var_names,
             called: false,
index f62e01f664525bda06f6f5a7e542b86eb1fcedd7..9ac569725d57bbe41146d3e6e20009e30bcbf558 100644 (file)
@@ -2,7 +2,6 @@ use crate::forms::*;
 use crate::machine::loader::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
-use crate::machine::preprocessor::*;
 use crate::machine::term_stream::*;
 use crate::machine::*;
 use crate::parser::ast::*;
@@ -434,19 +433,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         self.retract_local_clauses_impl(clause_clause_compilation_target, key, clause_locs);
     }
 
-    pub(super) fn try_term_to_tl(
-        &mut self,
-        term: FocusedHeap,
-        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]
     pub(super) fn remove_module_op_exports(&mut self) {
         for (mut op_decl, record) in self.payload.module_op_exports.drain(0..) {
index 611c30bdd4fd931510bee8731d7d865d31db1ed4..82483ce04669b534a3fd58345eab7f70fe536fd8 100644 (file)
@@ -20,6 +20,25 @@ use std::convert::TryFrom;
 use std::fmt;
 use std::ops::{Deref, DerefMut};
 
+impl TermWriteResult {
+    pub(super) fn from(heap: &mut Heap, value: HeapCellValue) -> Result<Self, usize> {
+        let focus = heap.index_of(value)?;
+        let mut stack = Stack::uninitialized();
+
+        heap[0] = value;
+
+        let inverse_var_locs = inverse_var_locs_from_iter(
+            stackful_preorder_iter::<NonListElider>(
+                heap,
+                &mut stack,
+                0,
+            ),
+        );
+
+        Ok(Self { focus, inverse_var_locs })
+    }
+}
+
 /*
  * The loader compiles Prolog terms read from a TermStream instance,
  * which may be incremental or monolithic. The monolithic term stream
@@ -176,18 +195,18 @@ impl CompilationTarget {
 }
 
 pub struct PredicateQueue {
-    pub(super) predicates: Vec<FocusedHeap>,
-    pub(super) compilation_target: CompilationTarget,
+    pub predicates: Vec<TermWriteResult>,
+    pub compilation_target: CompilationTarget,
 }
 
 impl PredicateQueue {
     #[inline]
-    pub(super) fn push(&mut self, clause: FocusedHeap) {
-        self.predicates.push(clause);
+    pub(super) fn push(&mut self, term_write_result: TermWriteResult) {
+        self.predicates.push(term_write_result);
     }
 
     #[inline]
-    pub(crate) fn first(&self) -> Option<&FocusedHeap> {
+    pub(crate) fn first(&self) -> Option<&TermWriteResult> {
         self.predicates.first()
     }
 
@@ -381,7 +400,6 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
         let repo_len = loader.wam_prelude.code.len();
 
         loader.payload.retraction_info.reset(repo_len);
-
         loader.remove_module_op_exports();
 
         Ok(loader.payload.compilation_target)
@@ -399,7 +417,7 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
 
     #[inline(always)]
     fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState {
-        loader.term_stream.parser.lexer.machine_st
+        loader.term_stream.lexer_parser.machine_st
     }
 
     #[inline(always)]
@@ -491,23 +509,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         }
     }
 
-    pub(crate) fn copy_term_from_heap(&mut self, cell: HeapCellValue) -> FocusedHeap {
-        use crate::iterators::fact_iterator;
-
-        let mut term = FocusedHeap::empty();
-        let mut stack = Stack::uninitialized();
-        let machine_st = LS::machine_st(&mut self.payload);
-
-        term.copy_term_from_machine_heap(machine_st, cell);
-        term.inverse_var_locs = inverse_var_locs_from_iter(
-            fact_iterator::<false>(
-                &mut term.heap,
-                &mut stack,
-                0,
-            ),
-        );
-
-        term
+    #[inline]
+    pub(super) fn machine_heap(&mut self) -> &mut Heap {
+        &mut LS::machine_st(&mut self.payload).heap
     }
 
     pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
@@ -525,14 +529,26 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target);
 
             let mut term = load_state.term_stream.next(&composite_op_dir)?;
+            let predicate_focus_opt = load_state.predicates.first().map(|term_write_result| {
+                term_write_result.focus
+            });
 
-            if !term.is_consistent(&load_state.predicates) {
-                self.compile_and_submit()?;
+            let machine_st = LS::machine_st(&mut self.payload);
+            let term_key_opt = clause_predicate_key(&machine_st.heap, term.focus);
+
+            if let Some(predicate_focus) = predicate_focus_opt {
+                let predicate_key_opt = clause_predicate_key(&machine_st.heap, predicate_focus);
+
+                debug_assert!(predicate_key_opt.is_some());
+
+                if term_key_opt != predicate_key_opt {
+                    self.compile_and_submit()?;
+                }
             }
 
-            if Some(atom!(":-")) == term.name(term.focus) && term.arity(term.focus) == 1 {
-                let new_focus = term.nth_arg(term.focus, 1).unwrap();
-                let term = term.as_ref_mut(new_focus);
+            if Some((atom!(":-"), 1)) == term_key_opt {
+                let machine_st = LS::machine_st(&mut self.payload);
+                term.focus = term_nth_arg(&machine_st.heap, term.focus, 1).unwrap();
                 return Ok(Some(setup_declaration(self, term)?));
             }
 
@@ -1055,48 +1071,55 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         let machine_st = LS::machine_st(&mut self.payload);
         let cell = machine_st[r];
 
-        let export_list = FocusedHeapRefMut::from_cell(&mut machine_st.heap, cell);
+        let focus = machine_st.heap.cell_len();
+        machine_st.heap.push_cell(cell)
+            .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+
+        let export_list = FocusedHeapRefMut { heap: &mut machine_st.heap, focus };
         let export_list = setup_module_export_list(export_list)?;
 
         Ok(export_list.into_iter().collect())
     }
 
-    fn clause_clause(&mut self, cell: HeapCellValue) -> Result<FocusedHeap, CompilationError> {
+    fn clause_clause(&mut self, cell: HeapCellValue) -> Result<TermWriteResult, CompilationError> {
         let machine_st = LS::machine_st(&mut self.payload);
-        let mut term = FocusedHeap::empty();
+        let focus = machine_st.heap.cell_len();
 
         read_heap_cell!(cell,
             (HeapCellValueTag::Str, s) => {
                 let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
                     .get_name_and_arity();
 
-                term.copy_term_from_machine_heap(machine_st, cell);
-                let focus = term.heap.len();
+                let mut writer = machine_st.heap.reserve(4)
+                    .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
 
-                term.heap.push(str_loc_as_cell!(focus+1));
-                term.heap.push(atom_as_cell!(atom!("clause"), 2));
+                writer.write_with(|section| {
+                    section.push_cell(str_loc_as_cell!(focus+1));
+                    section.push_cell(atom_as_cell!(atom!("clause"), 2));
 
-                match (name, arity) {
-                    (atom!(":-"), 2) => {
-                        term.heap.push(heap_loc_as_cell!(2));
-                        term.heap.push(heap_loc_as_cell!(3));
-                    }
-                    _ => {
-                        term.heap.push(heap_loc_as_cell!(0));
-                        term.heap.push(atom_as_cell!(atom!("true")));
+                    match (name, arity) {
+                        (atom!(":-"), 2) => {
+                            section.push_cell(heap_loc_as_cell!(s+1));
+                            section.push_cell(heap_loc_as_cell!(s+2));
+                        }
+                        _ => {
+                            section.push_cell(str_loc_as_cell!(s));
+                            section.push_cell(atom_as_cell!(atom!("true")));
+                        }
                     }
-                }
-
-                term.focus = focus;
+                });
             }
             (HeapCellValueTag::Atom, (name, arity)) => {
                 if arity == 0 {
-                    term.heap.push(str_loc_as_cell!(1));
-                    term.heap.push(atom_as_cell!(atom!("clause"), 2));
-                    term.heap.push(atom_as_cell!(name));
-                    term.heap.push(atom_as_cell!(atom!("true")));
-
-                    term.focus = 0;
+                    let mut writer = machine_st.heap.reserve(4)
+                        .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+
+                    writer.write_with(|section| {
+                        section.push_cell(str_loc_as_cell!(focus+1));
+                        section.push_cell(atom_as_cell!(atom!("clause"), 2));
+                        section.push_cell(atom_as_cell!(name));
+                        section.push_cell(atom_as_cell!(atom!("true")));
+                    });
                 } else {
                     return Err(CompilationError::InadmissibleFact);
                 }
@@ -1106,11 +1129,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             }
         );
 
-        let value = term.heap[term.focus];
-        term.inverse_var_locs = inverse_var_locs_from_iter(
-            eager_stackful_preorder_iter(&mut term.heap, value),
-        );
-        Ok(term)
+        Ok(TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus))
+           .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?)
     }
 
     fn add_extensible_predicate_declaration(
@@ -1330,18 +1350,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 
     fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> {
         let machine_st = LS::machine_st(&mut self.payload);
-        let term = FocusedHeapRefMut::from_cell(&mut machine_st.heap, value);
-
-        let name_opt = ClauseInfo::name(&term);
+        let key_opt = clause_predicate_key_from_heap(&machine_st.heap, value);
 
-        if let Some(predicate_name) = name_opt {
-            let arity = ClauseInfo::arity(&term);
+        if let Some((predicate_name, predicate_arity)) = key_opt {
             let predicates_compilation_target = self.payload.predicates.compilation_target;
 
             let is_dynamic = self
                 .wam_prelude
                 .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)
                 .unwrap_or(false);
 
@@ -1413,21 +1433,6 @@ impl<'a> MachinePreludeView<'a> {
     }
 }
 
-/*
-impl MachineState {
-    pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> FocusedHeap {
-        let mut term = FocusedHeap::empty();
-        term.copy_term_from_machine_heap(self, term_addr);
-
-        let value = term.heap[0];
-        let iter = eager_stackful_preorder_iter(&mut term.heap, value);
-
-        term.var_locs = var_locs_from_iter(iter);
-        term
-    }
-}
-*/
-
 impl Machine {
     pub(crate) fn use_module(&mut self) -> CallResult {
         let subevacuable_addr = self
@@ -1589,11 +1594,14 @@ impl Machine {
 
     pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult {
         let value = self.machine_st.registers[1];
+        let term = resource_error_call_result!(
+            self.machine_st,
+            TermWriteResult::from(&mut self.machine_st.heap, value)
+        );
+
         let mut loader = self.loader_from_heap_evacuable(temp_v!(2));
 
         let add_clause = || {
-            let term = loader.copy_term_from_heap(value);
-
             loader.incremental_compile_clause(
                 (atom!("term_expansion"), 2),
                 term,
@@ -1614,31 +1622,40 @@ impl Machine {
             .machine_st
             .store(self.machine_st.deref(self.machine_st.registers[1])));
 
-        let value = self.machine_st.registers[2];
-        let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
-
         let compilation_target = match target_module_name {
             atom!("user") => CompilationTarget::User,
             _ => CompilationTarget::Module(target_module_name),
         };
 
-        let add_clause = || {
-            let term = loader.copy_term_from_heap(value);
+        let value = self.machine_st.registers[2];
+        let term  = resource_error_call_result!(
+            self.machine_st,
+            TermWriteResult::from(&mut self.machine_st.heap, value)
+        );
 
-            let indexing_arg = match term.name(term.focus) {
-                Some(atom!(":-")) => term.nth_arg(term.focus, 1).and_then(|h| term.nth_arg(h, 1)),
-                Some(_) => term.nth_arg(term.focus, 1),
+        let add_clause = || {
+            let indexing_arg_opt = match term_predicate_key(&self.machine_st.heap, term.focus) {
+                Some((atom!(":-"), _)) => {
+                    term_nth_arg(&self.machine_st.heap, term.focus, 1).and_then(|h| {
+                        term_nth_arg(&self.machine_st.heap, h, 1)
+                    })
+                }
+                Some(_) => term_nth_arg(&self.machine_st.heap, term.focus, 1),
                 None => None,
             };
 
-            if let Some(indexing_term_loc) = indexing_arg {
-                if let Some(indexing_name) = term.name(indexing_term_loc) {
-                    loader
-                        .wam_prelude
-                        .indices
-                        .goal_expansion_indices
-                        .insert((indexing_name, term.arity(indexing_term_loc)));
-                }
+            let key_opt = indexing_arg_opt.and_then(|indexing_term_loc| {
+                term_predicate_key(&self.machine_st.heap, indexing_term_loc)
+            });
+
+            let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
+
+            if let Some((name, arity)) = key_opt {
+                loader
+                    .wam_prelude
+                    .indices
+                    .goal_expansion_indices
+                    .insert((name, arity));
             }
 
             loader.incremental_compile_clause(
@@ -1944,19 +1961,16 @@ impl Machine {
 
         let stub_gen = || functor_stub(key.0, key.1);
         let assert_clause = self.machine_st.registers[2];
-        let (name, arity) = {
-            let term = FocusedHeapRefMut::from_cell(&mut self.machine_st.heap, assert_clause);
-            (ClauseInfo::name(&term), ClauseInfo::arity(&term))
-        };
+        let key_opt = clause_predicate_key_from_heap(&self.machine_st.heap, assert_clause);
 
-        let mut compile_assert = |assert_clause, name, arity| {
+        let mut compile_assert = |assert_clause, key_opt| {
             let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
                 Loader::new(self, LiveTermStream::new(ListingSource::User));
 
             loader.payload.compilation_target = compilation_target;
 
-            let name = if let Some(name) = name {
-                name
+            let (name, arity) = if let Some(key) = key_opt {
+                key
             } else {
                 return Err(SessionError::from(CompilationError::InvalidRuleHead));
             };
@@ -1994,11 +2008,16 @@ impl Machine {
 
             // if a new predicate was just created, make it dynamic.
             loader.add_dynamic_predicate(compilation_target, name, arity)?;
-            let asserted_clause = loader.copy_term_from_heap(assert_clause);
+
+            let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload);
+            // let asserted_clause = loader.copy_term_from_heap(assert_clause);
+
+            let term = TermWriteResult::from(&mut machine_st.heap, assert_clause)
+                .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
 
             loader.incremental_compile_clause(
                 (name, arity),
-                asserted_clause,
+                term,
                 compilation_target,
                 false,
                 append_or_prepend,
@@ -2019,7 +2038,7 @@ impl Machine {
             LiveLoadAndMachineState::evacuate(loader)
         };
 
-        match compile_assert(assert_clause, name, arity) {
+        match compile_assert(assert_clause, key_opt) {
             Ok(_) => Ok(()),
             Err(SessionError::CompilationError(
                 CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact,
@@ -2221,11 +2240,21 @@ impl Machine {
         };
 
         let mut loader = self.loader_from_heap_evacuable(temp_v!(4));
+        let predicate_focus_opt = loader.payload.predicates.first().map(|term_write_result| {
+            term_write_result.focus
+        });
+
+        let is_consistent = if let Some(predicate_focus) = predicate_focus_opt {
+            let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload);
+            clause_predicate_key(&machine_st.heap, predicate_focus) == Some(key)
+        } else {
+            true
+        };
 
         LiveLoadAndMachineState::machine_st(&mut loader.payload).fail =
             (!loader.payload.predicates.is_empty()
-                && loader.payload.predicates.compilation_target != compilation_target)
-                || !key.is_consistent(&loader.payload.predicates);
+             && loader.payload.predicates.compilation_target != compilation_target)
+                || !is_consistent;
 
         let result = LiveLoadAndMachineState::evacuate(loader);
         self.restore_load_state_payload(result)
@@ -2293,29 +2322,36 @@ impl Machine {
             .get_meta_predicate_spec(predicate_name, arity, &compilation_target)
         {
             Some(meta_specs) => {
-                let term_loc = self.machine_st.heap.len();
+                let term_loc = self.machine_st.heap.cell_len();
 
-                self.machine_st
-                    .heap
-                    .push(atom_as_cell!(predicate_name, arity));
-                self.machine_st
-                    .heap
-                    .extend(meta_specs.iter().map(|meta_spec| match meta_spec {
-                        MetaSpec::Minus => atom_as_cell!(atom!("+")),
-                        MetaSpec::Plus => atom_as_cell!(atom!("-")),
-                        MetaSpec::Either => atom_as_cell!(atom!("?")),
-                        MetaSpec::Colon => atom_as_cell!(atom!(":")),
-                        MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
-                            fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
-                        }
-                    }));
+                let mut writer = match self.machine_st.heap.reserve(3 + meta_specs.len()) {
+                    Ok(writer) => writer,
+                    Err(err_loc) => {
+                        self.machine_st.throw_resource_error(err_loc);
+                        return;
+                    }
+                };
 
-                let heap_loc = self.machine_st.heap.len();
+                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::Plus => atom_as_cell!(atom!("-")),
+                            MetaSpec::Either => atom_as_cell!(atom!("?")),
+                            MetaSpec::Colon => atom_as_cell!(atom!(":")),
+                            MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
+                                fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
+                            }
+                        });
+                    }
 
-                self.machine_st
-                    .heap
-                    .push(atom_as_cell!(atom!("meta_predicate"), 1));
-                self.machine_st.heap.push(str_loc_as_cell!(term_loc));
+                    section.push_cell(atom_as_cell!(atom!("meta_predicate"), 1));
+                    section.push_cell(str_loc_as_cell!(term_loc));
+                });
+
+                let heap_loc = self.machine_st.heap.cell_len() - 2;
 
                 unify!(
                     self.machine_st,
@@ -2430,9 +2466,12 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
 
         self.add_clause_clause_if_dynamic(value)?;
 
-        let term = self.copy_term_from_heap(value);
-        self.payload.term_stream.term_queue.push_back(term);
+        let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload);
 
+        let term = TermWriteResult::from(&mut machine_st.heap, value)
+            .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+
+        self.payload.term_stream.term_queue.push_back(term);
         self.load()
     }
 }
index ea8db552c352c5e212655ee25a406e1ef4458ec6..5017cb78bb72e71f66ec0950fd352f6290aa3699 100644 (file)
@@ -5,6 +5,7 @@ use crate::parser::ast::*;
 #[cfg(feature = "ffi")]
 use crate::ffi::FFIError;
 use crate::forms::*;
+use crate::functor_macro::*;
 use crate::machine::heap::*;
 use crate::machine::loader::CompilationTarget;
 use crate::machine::machine_state::*;
@@ -12,20 +13,13 @@ use crate::machine::streams::*;
 use crate::machine::system_calls::BrentAlgState;
 use crate::types::*;
 
-pub type MachineStub = Vec<HeapCellValue>;
+pub type MachineStub = Vec<FunctorElement>;
 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)]
 pub(crate) struct MachineError {
     stub: MachineStub,
     location: Option<ParserErrorSrc>,
-    from: ErrorProvenance,
 }
 
 // from 7.12.2 b) of 13211-1:1995
@@ -91,45 +85,26 @@ impl TypeError for HeapCellValue {
     fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
         let stub = functor!(
             atom!("type_error"),
-            [atom(valid_type.as_atom()), cell(self)]
+            [atom_as_cell((valid_type.as_atom())), cell(self)]
         );
 
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 }
 
 impl TypeError for MachineStub {
-    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,
-        }
-    }
-}
-
-impl TypeError for FunctorStub {
-    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!(
             atom!("type_error"),
-            [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
-            [self]
+            [atom_as_cell((valid_type.as_atom())), functor(self)]
         );
 
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Constructed,
         }
     }
 }
@@ -139,15 +114,14 @@ impl TypeError for Number {
         let stub = functor!(
             atom!("type_error"),
             [
-                atom(valid_type.as_atom()),
-                number(&mut machine_st.arena, self)
+                atom_as_cell((valid_type.as_atom())),
+                number(self, (&mut machine_st.arena))
             ]
         );
 
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 }
@@ -171,16 +145,15 @@ impl PermissionError for Atom {
         let stub = functor!(
             atom!("permission_error"),
             [
-                atom(perm.as_atom()),
-                atom(index_atom),
-                cell(atom_as_cell!(self))
+                atom_as_cell((perm.as_atom())),
+                atom_as_cell(index_atom),
+                atom_as_cell(self)
             ]
         );
 
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 }
@@ -214,13 +187,12 @@ impl PermissionError for HeapCellValue {
 
         let stub = functor!(
             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 {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 }
@@ -228,24 +200,22 @@ impl PermissionError for HeapCellValue {
 impl PermissionError for MachineStub {
     fn permission_error(
         self,
-        machine_st: &mut MachineState,
+        _machine_st: &mut MachineState,
         index_atom: Atom,
         perm: Permission,
     ) -> MachineError {
         let stub = functor!(
             atom!("permission_error"),
             [
-                atom(perm.as_atom()),
-                atom(index_atom),
-                str(machine_st.heap.len(), 0)
-            ],
-            [self]
+                atom_as_cell((perm.as_atom())),
+                atom_as_cell(index_atom),
+                functor(self)
+            ]
         );
 
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Constructed,
         }
     }
 }
@@ -256,60 +226,46 @@ pub(super) trait DomainError {
 
 impl DomainError for HeapCellValue {
     fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
-        let stub = functor!(atom!("domain_error"), [atom(error.as_atom()), cell(self)]);
+        let stub = functor!(atom!("domain_error"), [atom_as_cell((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 {
+impl DomainError for Number {
+    fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
         let stub = functor!(
             atom!("domain_error"),
-            [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
-            [self]
+            [atom_as_cell((error.as_atom())), number(self, (&mut machine_st.arena))]
         );
 
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Constructed,
         }
     }
 }
 
-impl DomainError for Number {
-    fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
+impl DomainError for MachineStub {
+    fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
         let stub = functor!(
             atom!("domain_error"),
-            [atom(error.as_atom()), number(&mut machine_st.arena, self)]
+            [atom_as_cell((error.as_atom())), functor(self)]
         );
 
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 }
 
-pub(super) type FunctorStub = [HeapCellValue; 3];
-
 #[inline(always)]
-pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub {
-    [
-        atom_as_cell!(atom!("/"), 2),
-        atom_as_cell!(name),
-        fixnum_as_cell!(Fixnum::build_with(arity as i64)),
-    ]
+pub(super) fn functor_stub(name: Atom, arity: usize) -> MachineStub {
+    functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)])
 }
 
 impl MachineState {
@@ -320,17 +276,15 @@ impl MachineState {
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 
     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 {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 
@@ -339,18 +293,17 @@ impl MachineState {
             ResourceError::FiniteMemory(size_requested) => {
                 functor!(
                     atom!("resource_error"),
-                    [atom(atom!("finite_memory")), cell(size_requested)]
+                    [atom_as_cell((atom!("finite_memory"))), cell(size_requested)]
                 )
             }
             ResourceError::OutOfFiles => {
-                functor!(atom!("resource_error"), [atom(atom!("file_descriptors"))])
+                functor!(atom!("resource_error"), [atom_as_cell((atom!("file_descriptors")))])
             }
         };
 
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 
@@ -367,13 +320,12 @@ impl MachineState {
             ExistenceError::Module(name) => {
                 let stub = functor!(
                     atom!("existence_error"),
-                    [atom(atom!("source_sink")), atom(name)]
+                    [atom_as_cell((atom!("source_sink"))), atom_as_cell(name)]
                 );
 
                 MachineError {
                     stub,
                     location: None,
-                    from: ErrorProvenance::Received,
                 }
             }
             ExistenceError::QualifiedProcedure {
@@ -381,36 +333,30 @@ impl MachineState {
                 name,
                 arity,
             } => {
-                let h = self.heap.len();
-
-                let ind_stub = functor!(atom!("/"), [atom(name), fixnum(arity)]);
-                let res_stub = functor!(atom!(":"), [atom(module_name), str(h + 3, 0)], [ind_stub]);
+                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 stub = functor!(
                     atom!("existence_error"),
-                    [atom(atom!("procedure")), str(h, 0)],
-                    [res_stub]
+                    [atom_as_cell((atom!("procedure"))), functor(res_stub)]
                 );
 
                 MachineError {
                     stub,
                     location: None,
-                    from: ErrorProvenance::Constructed,
                 }
             }
             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!(
                     atom!("existence_error"),
-                    [atom(atom!("procedure")), str(self.heap.len(), 0)],
-                    [culprit]
+                    [atom_as_cell((atom!("procedure"))), functor(culprit)]
                 );
 
                 MachineError {
                     stub,
                     location: None,
-                    from: ErrorProvenance::Constructed,
                 }
             }
             ExistenceError::ModuleSource(source) => {
@@ -418,43 +364,75 @@ impl MachineState {
 
                 let stub = functor!(
                     atom!("existence_error"),
-                    [atom(atom!("source_sink")), str(self.heap.len(), 0)],
-                    [source_stub]
+                    [atom_as_cell((atom!("source_sink"))), functor(source_stub)]
                 );
 
                 MachineError {
                     stub,
                     location: None,
-                    from: ErrorProvenance::Constructed,
                 }
             }
             ExistenceError::SourceSink(culprit) => {
                 let stub = functor!(
                     atom!("existence_error"),
-                    [atom(atom!("source_sink")), cell(culprit)]
+                    [atom_as_cell((atom!("source_sink"))), cell(culprit)]
                 );
 
                 MachineError {
                     stub,
                     location: None,
-                    from: ErrorProvenance::Received,
                 }
             }
             ExistenceError::Stream(culprit) => {
                 let stub = functor!(
                     atom!("existence_error"),
-                    [atom(atom!("stream")), cell(culprit)]
+                    [atom_as_cell((atom!("stream"))), cell(culprit)]
                 );
 
                 MachineError {
                     stub,
                     location: None,
-                    from: ErrorProvenance::Received,
                 }
             }
         }
     }
 
+    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)
+            }
+        }
+    }
+
     pub(super) fn permission_error<T: PermissionError>(
         &mut self,
         err: Permission,
@@ -471,7 +449,6 @@ impl MachineState {
 
     fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
         match err {
-            ArithmeticError::UninstantiatedVar => self.instantiation_error(),
             ArithmeticError::NonEvaluableFunctor(cell, arity) => {
                 let culprit = functor!(atom!("/"), [cell(cell), fixnum(arity)]);
 
@@ -495,7 +472,6 @@ impl MachineState {
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 
@@ -505,15 +481,11 @@ impl MachineState {
                 Permission::Modify,
                 atom!("static_procedure"),
                 functor_stub(key.0, key.1)
-                    .into_iter()
-                    .collect::<MachineStub>(),
             ),
             SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error(
                 Permission::Modify,
                 atom!("static_procedure"),
                 functor_stub(key.0, key.1)
-                    .into_iter()
-                    .collect::<MachineStub>(),
             ),
             SessionError::CannotOverwriteBuiltInModule(module) => {
                 self.permission_error(Permission::Modify, atom!("static_module"), module)
@@ -524,8 +496,7 @@ impl MachineState {
 
                 let stub = functor!(
                     atom!("module_does_not_contain_claimed_export"),
-                    [atom(module_name), str(self.heap.len() + 4, 0)],
-                    [functor_stub]
+                    [atom_as_cell(module_name), functor(functor_stub)]
                 );
 
                 self.permission_error(Permission::Access, atom!("private_procedure"), stub)
@@ -536,7 +507,7 @@ impl MachineState {
                 self.permission_error(
                     Permission::Modify,
                     atom!("module"),
-                    functor!(error_atom, [atom(module_name)]),
+                    functor!(error_atom, [atom_as_cell(module_name)]),
                 )
             }
             SessionError::NamelessEntry => {
@@ -555,15 +526,12 @@ impl MachineState {
             }
             SessionError::CompilationError(err) => self.syntax_error(err),
             SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
-                let functor_stub = functor_stub(key.0, key.1);
-
                 let stub = functor!(
                     atom!(":"),
                     [
-                        atom(compilation_target.module_name()),
-                        str(self.heap.len() + 4, 0)
-                    ],
-                    [functor_stub]
+                        atom_as_cell((compilation_target.module_name())),
+                        functor((key.0), [fixnum((key.1))])
+                    ]
                 );
 
                 self.permission_error(
@@ -587,30 +555,27 @@ impl MachineState {
         }
 
         let location = err.line_and_col_num();
-        let len = self.heap.len();
         let stub = err.as_functor();
 
-        let stub = functor!(atom!("syntax_error"), [str(len, 0)], [stub]);
+        let stub = functor!(atom!("syntax_error"), [functor(stub)]);
 
         MachineError {
             stub,
             location,
-            from: ErrorProvenance::Constructed,
         }
     }
 
-    pub(super) fn representation_error(&mut self, flag: RepFlag) -> MachineError {
-        let stub = functor!(atom!("representation_error"), [atom(flag.as_atom())]);
+    pub(super) fn representation_error(&self, flag: RepFlag) -> MachineError {
+        let stub = functor!(atom!("representation_error"), [atom_as_cell((flag.as_atom()))]);
 
         MachineError {
             stub,
             location: None,
-            from: ErrorProvenance::Received,
         }
     }
 
     #[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 {
             FFIError::ValueCast => atom!("value_cast"),
             FFIError::ValueDontFit => atom!("value_dont_fit"),
@@ -619,62 +584,44 @@ impl MachineState {
             FFIError::FunctionNotFound => atom!("function_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 {
             stub,
             location: None,
-            from: ErrorProvenance::Constructed,
         }
     }
 
-    pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub {
-        let h = self.heap.len();
-        let location = err.location;
-        let stub_addition_len = if err.len() == 1 {
-            0 // if err contains 1 cell, it can be inlined at stub[1].
-        } else {
-            err.len()
-        };
-
-        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));
+    pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub {
+        if let Some(ParserErrorSrc { line_num,  .. }) = err.location {
+            functor!(atom!("error"), [functor((err.stub)),
+                                      functor((atom!(":")), [functor(src),
+                                                             number(line_num, (&mut self.arena))])])
         } else {
-            stub[1] = err.stub[0];
-        }
-
-        if let Some(ParserErrorSrc { line_num, .. }) = location {
-            stub.push(atom_as_cell!(atom!(":"), 2));
-            stub.push(str_loc_as_cell!(h + 6 + stub_addition_len));
-            stub.push(integer_as_cell!(Number::arena_from(
-                line_num,
-                &mut self.arena
-            )));
+            functor!(atom!("error"), [functor((err.stub)),
+                                      functor(src)])
         }
+    }
 
-        stub.extend(src.iter());
-        stub
+    // throw an error pre-allocated in the heap
+    pub(super) fn throw_resource_error(&mut self, err_loc: usize) {
+        self.registers[1] = str_loc_as_cell!(err_loc);
+        self.set_ball();
+        self.unwind_stack();
     }
 
     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.stub.truncate(0);
 
-        self.heap.extend(err);
+        let mut writer = Heap::functor_writer(err);
 
-        self.registers[1] = if err_len == 1 {
-            heap_loc_as_cell!(h)
-        } else {
-            str_loc_as_cell!(h)
+        self.registers[1] = match writer(&mut self.heap) {
+            Ok(loc) => loc,
+            Err(resource_err_loc) => {
+                self.throw_resource_error(resource_err_loc);
+                return;
+            }
         };
 
         self.set_ball();
@@ -682,21 +629,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)]
 pub enum CompilationError {
     Arithmetic(ArithmeticError),
@@ -715,12 +647,12 @@ pub enum CompilationError {
 
 #[derive(Debug)]
 pub enum DirectiveError {
-    ExpectedDirective(Term),
+    ExpectedDirective(HeapCellValue),
     InvalidDirective(Atom, usize /* arity */),
-    InvalidOpDeclNameType(Term),
-    InvalidOpDeclSpecDomain(Term),
+    InvalidOpDeclNameType(HeapCellValue),
+    InvalidOpDeclSpecDomain(HeapCellValue),
     InvalidOpDeclSpecValue(Atom),
-    InvalidOpDeclPrecType(Term),
+    InvalidOpDeclPrecType(HeapCellValue),
     InvalidOpDeclPrecDomain(Fixnum),
     ShallNotCreate(Atom),
     ShallNotModify(Atom),
@@ -757,11 +689,9 @@ impl CompilationError {
                 functor!(atom!("exceeded_max_arity"))
             }
             CompilationError::InadmissibleFact => {
-                // TODO: type_error(callable, _).
                 functor!(atom!("inadmissible_fact"))
             }
             CompilationError::InadmissibleQueryTerm => {
-                // TODO: type_error(callable, _).
                 functor!(atom!("inadmissible_query_term"))
             }
             CompilationError::InvalidDirective(_) => {
@@ -776,8 +706,8 @@ impl CompilationError {
             CompilationError::InvalidModuleExport => {
                 functor!(atom!("invalid_module_export"))
             }
-            CompilationError::InvalidModuleResolution(ref module_name) => {
-                functor!(atom!("no_such_module"), [atom(module_name)])
+            &CompilationError::InvalidModuleResolution(module_name) => {
+                functor!(atom!("no_such_module"), [atom_as_cell(module_name)])
             }
             CompilationError::InvalidRuleHead => {
                 functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
@@ -896,14 +826,13 @@ impl EvalError {
 // used by '$skip_max_list'.
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum CycleSearchResult {
-    Cyclic(usize),
+    Cyclic { lambda: usize }, // number of steps
     EmptyList,
-    NotList(usize, HeapCellValue), // the list length until the second argument in the heap
-    PartialList(usize, Ref),       // the list length (up to max), and an offset into the heap.
-    ProperList(usize),             // the list length.
-    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).
-    UntouchedCStr(Atom, usize),
+    NotList { num_steps: usize, heap_loc: HeapCellValue },
+    PartialList { 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 {
@@ -915,11 +844,11 @@ impl MachineState {
         let sorted = self.store(self.deref(self.registers[2]));
 
         match BrentAlgState::detect_cycles(&self.heap, list) {
-            CycleSearchResult::PartialList(..) => {
+            CycleSearchResult::PartialList { .. } => {
                 let err = self.instantiation_error();
                 return Err(self.error_form(err, stub_gen()));
             }
-            CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
+            CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => {
                 let err = self.type_error(ValidType::List, list);
                 return Err(self.error_form(err, stub_gen()));
             }
@@ -927,7 +856,7 @@ impl MachineState {
         };
 
         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);
                 Err(self.error_form(err, stub_gen()))
             }
@@ -939,7 +868,7 @@ impl MachineState {
         let stub_gen = || functor_stub(atom!("keysort"), 2);
 
         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);
                 Err(self.error_form(err, stub_gen()))
             }
@@ -1001,11 +930,11 @@ impl MachineState {
         let sorted = self.store(self.deref(self[temp_v!(2)]));
 
         match BrentAlgState::detect_cycles(&self.heap, pairs) {
-            CycleSearchResult::PartialList(..) => {
+            CycleSearchResult::PartialList { .. } => {
                 let err = self.instantiation_error();
                 Err(self.error_form(err, stub_gen()))
             }
-            CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
+            CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => {
                 let err = self.type_error(ValidType::List, pairs);
                 Err(self.error_form(err, stub_gen()))
             }
index a08a8264eb1cc8660908904f9717c265d416f7c9..03eb46c20262769167a07aa7d84c5c96d59a3e36 100644 (file)
@@ -168,6 +168,13 @@ impl From<TypedArenaPtr<IndexPtr>> for CodeIndex {
     }
 }
 
+impl From<CodeIndex> for HeapCellValue {
+    #[inline(always)]
+    fn from(idx: CodeIndex) -> HeapCellValue {
+        untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))
+    }
+}
+
 impl CodeIndex {
     #[inline]
     pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self {
@@ -207,10 +214,12 @@ impl CodeIndex {
         std::mem::replace(self.0.deref_mut(), value)
     }
 
+    /*
     #[inline(always)]
     pub(crate) fn as_ptr(&self) -> *const IndexPtr {
         self.0.as_ptr()
     }
+    */
 }
 
 pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
index 1c18f16a71b6d8a1ca50518677de2b678d1a3aa7..a5ee474a40516548d90da3a5a35ee7312ddda82a 100644 (file)
@@ -1,6 +1,7 @@
 use crate::arena::*;
 use crate::atom_table::*;
 use crate::forms::*;
+use crate::functor_macro::*;
 use crate::heap_iter::*;
 use crate::heap_print::*;
 use crate::machine::attributed_variables::*;
@@ -12,7 +13,6 @@ use crate::machine::stack::*;
 use crate::machine::streams::*;
 use crate::machine::Machine;
 use crate::parser::ast::*;
-use crate::read::TermWriteResult;
 use crate::types::*;
 
 use crate::parser::dashu::Integer;
@@ -21,7 +21,7 @@ use indexmap::IndexMap;
 
 use std::convert::TryFrom;
 use std::fmt;
-use std::ops::{Index, IndexMut};
+use std::ops::{Index, IndexMut, Range};
 use std::rc::Rc;
 use std::sync::Arc;
 
@@ -36,8 +36,8 @@ pub(super) enum MachineMode {
 #[derive(Debug, Clone)]
 pub(super) enum HeapPtr {
     HeapCell(usize),
-    PStrChar(usize, usize),
-    PStrLocation(usize, usize),
+    PStr(usize), // Char(usize),
+    // PStrLocation(usize),
 }
 
 impl Default for HeapPtr {
@@ -184,8 +184,9 @@ 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],
@@ -200,30 +201,44 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
         }
     )
 }
+*/
 
 fn push_var_eq_functors(
     heap: &mut Heap,
+    size: usize,
     iter: impl Iterator<Item = (usize, Var)>,
     atom_tbl: &AtomTable,
-) -> Vec<HeapCellValue> {
-    let mut list_of_var_eqs = vec![];
+) -> Result<HeapCellValue, usize> {
+    let src_h = heap.cell_len();
 
-    for (var_loc, var) in iter { // (var, binding) in iter {
-        let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
-        let h = heap.len();
-        let binding = heap[var_loc];
+    if size > 0 {
+        let mut writer = heap.reserve(1 + 5 * size)?;
 
-        heap.push(atom_as_cell!(atom!("="), 2));
-        heap.push(atom_as_cell!(var_atom));
-        heap.push(binding);
+        writer.write_with(|section| {
+            for (var_loc, var) in iter { // (var, binding) in iter {
+                let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
+                let binding = heap_loc_as_cell!(var_loc);
 
-        list_of_var_eqs.push(str_loc_as_cell!(h));
-    }
+                section.push_cell(atom_as_cell!(atom!("="), 2));
+                section.push_cell(atom_as_cell!(var_atom));
+                section.push_cell(binding);
+            }
 
-    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));
+            }
 
+            section.push_cell(empty_list_as_cell!());
+        });
+
+        Ok(heap_loc_as_cell!(src_h + 3 * size))
+    } else {
+        Ok(empty_list_as_cell!())
+    }
+}
 
+/*
 pub(crate) fn copy_and_align_iter<Iter: Iterator<Item = HeapCellValue>>(
     iter: Iter,
     boundary: i64,
@@ -232,6 +247,7 @@ pub(crate) fn copy_and_align_iter<Iter: Iterator<Item = HeapCellValue>>(
     let diff = boundary - h;
     iter.map(move |heap_value| heap_value - diff)
 }
+*/
 
 #[derive(Debug)]
 pub struct Ball {
@@ -252,8 +268,17 @@ impl Ball {
         self.stub.clear();
     }
 
-    pub(super) fn copy_and_align(&self, h: usize) -> Heap {
-        copy_and_align_iter(self.stub.iter().cloned(), self.boundary as i64, h as i64).collect()
+    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;
+
+        dest.append(self.stub.splice(..))?;
+
+        for cell in &mut dest.splice_mut(h ..) {
+            *cell = *cell - diff;
+        }
+
+        Ok(h)
     }
 }
 
@@ -286,13 +311,13 @@ impl<'a> IndexMut<usize> for CopyTerm<'a> {
 
 impl<'a> CopierTarget for CopyTerm<'a> {
     #[inline(always)]
-    fn threshold(&self) -> usize {
-        self.state.heap.len()
+    fn store(&self, value: HeapCellValue) -> HeapCellValue {
+        self.state.store(value)
     }
 
     #[inline(always)]
-    fn push(&mut self, hcv: HeapCellValue) {
-        self.state.heap.push(hcv);
+    fn deref(&self, value: HeapCellValue) -> HeapCellValue {
+        self.state.deref(value)
     }
 
     #[inline(always)]
@@ -301,18 +326,49 @@ impl<'a> CopierTarget for CopyTerm<'a> {
     }
 
     #[inline(always)]
-    fn store(&self, value: HeapCellValue) -> HeapCellValue {
-        self.state.store(value)
+    fn stack(&mut self) -> &mut Stack {
+        &mut self.state.stack
     }
 
     #[inline(always)]
-    fn deref(&self, value: HeapCellValue) -> HeapCellValue {
-        self.state.deref(value)
+    fn threshold(&self) -> usize {
+        self.state.heap.cell_len()
     }
 
     #[inline(always)]
-    fn stack(&mut self) -> &mut Stack {
-        &mut self.state.stack
+    fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
+        self.state.heap.copy_pstr_within(pstr_loc)
+    }
+
+    #[inline(always)]
+    fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize {
+        self.state.heap.pstr_vec()[0 .. cell_index!(pstr_loc)]
+            .last_zero()
+            .map(|idx| idx + 1)
+            .unwrap_or(0)
+    }
+
+    #[inline(always)]
+    fn pstr_at(&self, loc: usize) -> bool {
+        self.state.heap.pstr_vec()[loc]
+    }
+
+    #[inline(always)]
+    fn next_non_pstr_cell_index(&self, loc: usize) -> usize {
+        // unwrap is safe here because a partial string is always
+        // followed by a tail cell, i.e. a non-pstr cell, supposing
+        // self.state.heap[loc] is a pstr cell
+        self.state.heap.pstr_vec()[loc ..].first_zero().unwrap()
+    }
+
+    #[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)
     }
 }
 
@@ -321,7 +377,6 @@ pub(crate) struct CopyBallTerm<'a> {
     attr_var_queue: &'a mut Vec<usize>,
     stack: &'a mut Stack,
     heap: &'a mut Heap,
-    heap_boundary: usize,
     stub: &'a mut Heap,
 }
 
@@ -332,13 +387,10 @@ impl<'a> CopyBallTerm<'a> {
         heap: &'a mut Heap,
         stub: &'a mut Heap,
     ) -> Self {
-        let hb = heap.len();
-
         CopyBallTerm {
             attr_var_queue,
             stack,
             heap,
-            heap_boundary: hb,
             stub,
         }
     }
@@ -348,10 +400,10 @@ impl<'a> Index<usize> for CopyBallTerm<'a> {
     type Output = HeapCellValue;
 
     fn index(&self, index: usize) -> &Self::Output {
-        if index < self.heap_boundary {
+        if index < self.heap.cell_len() {
             &self.heap[index]
         } else {
-            let index = index - self.heap_boundary;
+            let index = index - self.heap.cell_len();
             &self.stub[index]
         }
     }
@@ -359,10 +411,10 @@ impl<'a> Index<usize> for CopyBallTerm<'a> {
 
 impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
     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]
         } else {
-            let index = index - self.heap_boundary;
+            let index = index - self.heap.cell_len();
             &mut self.stub[index]
         }
     }
@@ -370,11 +422,7 @@ impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
 
 impl<'a> CopierTarget for CopyBallTerm<'a> {
     fn threshold(&self) -> usize {
-        self.heap_boundary + self.stub.len()
-    }
-
-    fn push(&mut self, value: HeapCellValue) {
-        self.stub.push(value);
+        self.heap.cell_len() + self.stub.cell_len()
     }
 
     #[inline(always)]
@@ -385,10 +433,10 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
     fn store(&self, value: HeapCellValue) -> HeapCellValue {
         read_heap_cell!(value,
             (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
-                if h < self.heap_boundary {
+                if h < self.heap.cell_len() {
                     self.heap[h]
                 } else {
-                    let index = h - self.heap_boundary;
+                    let index = h - self.heap.cell_len();
                     self.stub[index]
                 }
             }
@@ -417,6 +465,67 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
     fn stack(&mut self) -> &mut 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 (string, tail_loc) = self.heap.scan_slice_to_str(pstr_loc);
+        self.stub.allocate_pstr(string)?;
+        Ok(tail_loc)
+    }
+
+    #[inline]
+    fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize> {
+        self.stub.reserve(num_cells)
+    }
+
+    #[inline]
+    fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize {
+        if pstr_loc >= self.heap.byte_len() {
+            self.stub.pstr_vec()[0 .. cell_index!(pstr_loc - self.heap.byte_len())]
+                .last_zero()
+                .map(|idx| idx + 1)
+                .unwrap_or(0)
+        } else {
+            self.heap.pstr_vec()[0 .. cell_index!(pstr_loc)]
+                .last_zero()
+                .map(|idx| idx + 1)
+                .unwrap_or(0)
+        }
+    }
+
+    #[inline]
+    fn pstr_at(&self, loc: usize) -> bool {
+        if loc >= self.heap.cell_len() {
+            self.stub.pstr_vec()[loc - self.heap.cell_len()]
+        } else {
+            self.heap.pstr_vec()[loc]
+        }
+    }
+
+    #[inline]
+    fn next_non_pstr_cell_index(&self, loc: usize) -> usize {
+        let zero_from_loc = if loc >= self.heap.cell_len() {
+            self.stub.pstr_vec()[loc - self.heap.cell_len() ..].first_zero().unwrap()
+        } else {
+            self.heap.pstr_vec()[loc ..].first_zero().unwrap()
+        };
+
+        zero_from_loc + loc
+    }
+
+    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 {
@@ -467,10 +576,12 @@ impl MachineState {
             let addr = self.store(self.deref(addr));
 
             read_heap_cell!(addr,
+                /*
                 (HeapCellValueTag::Char, c) => {
                     chars.push(c);
                     continue;
                 }
+                */
                 (HeapCellValueTag::Atom, (name, arity)) => {
                     if arity == 0 {
                         if let Some(c) = name.as_char() {
@@ -543,35 +654,37 @@ impl MachineState {
     pub fn write_read_term_options(
         &mut self,
         mut var_list: Vec<(Var, HeapCellValue, usize)>,
-        singleton_var_list: Vec<HeapCellValue>,
+        singletons_heap_list: HeapCellValue,
     ) -> CallResult {
         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().map(|(var_name, var, _)| {
                 (var.get_value() as usize, var_name.clone())
             }),
+            num_vars,
             &self.atom_tbl,
         );
+        */
 
         let singleton_addr = self.registers[3];
-        let singletons_offset = heap_loc_as_cell!(iter_to_heap_list(
-            &mut self.heap,
-            singleton_var_list.into_iter()
-        ));
-
-        unify_fn!(*self, singletons_offset, singleton_addr);
+        unify_fn!(*self, singletons_heap_list, singleton_addr);
 
         if self.fail {
             return Ok(());
         }
 
         let vars_addr = self.registers[4];
-        let vars_offset = heap_loc_as_cell!(iter_to_heap_list(
-            &mut self.heap,
-            var_list.into_iter().map(|(_, cell, _)| cell)
-        ));
+        let vars_offset = resource_error_call_result!(
+            self,
+            sized_iter_to_heap_list(
+                &mut self.heap,
+                var_list.len(),
+                var_list.iter().map(|(_, cell, _)| *cell),
+            )
+        );
 
         unify_fn!(*self, vars_offset, vars_addr);
 
@@ -580,23 +693,41 @@ impl MachineState {
         }
 
         let var_names_addr = self.registers[5];
+        /*
         let var_names_offset = heap_loc_as_cell!(iter_to_heap_list(
             &mut self.heap,
             list_of_var_eqs.into_iter()
         ));
+        */
+
+        let var_names_offset = resource_error_call_result!(
+            self,
+            push_var_eq_functors(
+                &mut self.heap,
+                var_list.len(),
+                var_list.iter().map(|(var_name, var, _)| {
+                    (var.get_value() as usize, var_name.clone())
+                }),
+                &self.atom_tbl,
+            )
+        );
 
         Ok(unify_fn!(*self, var_names_offset, var_names_addr))
     }
 
     pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult {
-        let heap_loc = read_heap_cell!(self.heap[term.heap_loc],
-            (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
+        let heap_loc = self.heap[term.focus];
+
+        /*
+        read_heap_cell!(self.heap[term.heap_loc],
+            (HeapCellValueTag::PStr) => { // | HeapCellValueTag::PStrOffset) => {
                 pstr_loc_as_cell!(term.heap_loc)
             }
             _ => {
                 heap_loc_as_cell!(term.heap_loc)
             }
         );
+        */
 
         unify_fn!(*self, heap_loc, self.registers[2]);
 
@@ -612,7 +743,7 @@ impl MachineState {
 
         let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
 
-        for cell in eager_stackful_preorder_iter(&mut self.heap, heap_loc) {
+        for cell in stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, term.focus) {
             let cell = unmark_cell_bits!(cell);
 
             if let Some(var) = cell.as_var() {
@@ -624,29 +755,33 @@ impl MachineState {
             }
         }
 
-        let singleton_var_list = push_var_eq_functors(
-            &mut self.heap,
-            term.inverse_var_locs
-                .iter()
-                .filter_map(|(var_loc, var_name)| {
-                    // add h to offset the term variable into its heap location.
-                    let r = Ref::heap_cell(*var_loc);
-
-                    if singleton_var_set.get(&r).cloned().unwrap_or(false) {
-                        Some((*var_loc, var_name.clone()))
-                    } else {
-                        None
-                    }
-                }),
-            &self.atom_tbl,
+        let singleton_var_list = resource_error_call_result!(
+            self,
+            push_var_eq_functors(
+                &mut self.heap,
+                singleton_var_set
+                    .iter()
+                    .filter(|(var, is_singleton)| {
+                        **is_singleton && term.inverse_var_locs.contains_key(
+                            &(var.get_value() as usize)
+                        )
+                    })
+                    .count(),
+                term.inverse_var_locs
+                    .iter()
+                    .filter_map(|(var_loc, var_name)| {
+                        let r = Ref::heap_cell(*var_loc);
+
+                        if singleton_var_set.get(&r).cloned().unwrap_or(false) {
+                            Some((*var_loc, var_name.clone()))
+                        } else {
+                            None
+                        }
+                    }),
+                &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());
 
         for (var_loc, var_name) in term.inverse_var_locs {
@@ -744,7 +879,7 @@ impl MachineState {
                         CompilationError::ParserError(e) if e.is_unexpected_eof() => {
                             match eof_handler(self, stream)? {
                                 OnEOF::Return => {
-                                    return self.write_read_term_options(vec![], vec![])
+                                    return self.write_read_term_options(vec![], empty_list_as_cell!());
                                 }
                                 OnEOF::Continue => continue,
                             }
@@ -793,9 +928,11 @@ impl MachineState {
                                 }
 
                                 read_heap_cell!(atom,
+                                    /*
                                     (HeapCellValueTag::Char, c) => {
                                         var_names.insert(var, Rc::new(c.to_string()));
                                     }
+                                    */
                                     (HeapCellValueTag::Atom, (name, _arity)) => {
                                         debug_assert_eq!(_arity, 0);
                                         var_names.insert(var, Rc::new(name.as_str().to_owned()));
@@ -884,16 +1021,20 @@ impl MachineState {
                     }
                 );
 
-                let h = self.heap.len();
-                self.heap.push(term_to_be_printed);
+                let term_loc = self.heap.cell_len();
+
+                step_or_resource_error!(
+                    self,
+                    self.heap.push_cell(term_to_be_printed),
+                    { return Ok(None); }
+                );
 
                 let mut printer = HCPrinter::new(
                     &mut self.heap,
-                    Arc::clone(&self.atom_tbl),
                     &mut self.stack,
                     op_dir,
                     PrinterOutputter::new(),
-                    h,
+                    term_loc,
                 );
 
                 printer.ignore_ops = ignore_ops;
@@ -984,42 +1125,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)]
index e93356fd7635dbd49b7f952ae7abff9f721dc4a3..34fbe5cac80912d13029e1642ce84992880d015f 100644 (file)
@@ -22,6 +22,12 @@ use std::convert::TryFrom;
 
 impl MachineState {
     pub(crate) fn new() -> Self {
+        let mut heap = Heap::with_cell_capacity(256 * 256).unwrap();
+
+        // this is an interstitial cell reserved for use by the runtime.
+        heap.push_cell(empty_list_as_cell!()).unwrap();
+        heap.store_resource_error();
+
         MachineState {
             arena: Arena::new(),
             atom_tbl: AtomTable::new(),
@@ -38,7 +44,7 @@ impl MachineState {
             cp: 0,
             attr_var_init: AttrVarInitializer::new(0),
             fail: false,
-            heap: Heap::with_capacity(256 * 256),
+            heap,
             mode: MachineMode::Write,
             stack: Stack::new(),
             registers: [heap_loc_as_cell!(0); MAX_ARITY + 1], // self.registers[0] is never used.
@@ -261,9 +267,14 @@ impl MachineState {
         unifier.unify_atom(atom, value);
     }
 
-    pub fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) {
+    pub fn unify_list(&mut self, l1: usize, value: HeapCellValue) {
         let mut unifier = DefaultUnifier::from(self);
-        unifier.unify_complete_string(atom, value);
+        unifier.unify_list(l1, value);
+    }
+
+    pub fn unify_partial_string(&mut self, pstr_loc: usize, value: HeapCellValue) {
+        let mut unifier = DefaultUnifier::from(self);
+        unifier.unify_partial_string(pstr_loc, value);
     }
 
     pub fn unify_char(&mut self, c: char, value: HeapCellValue) {
@@ -316,18 +327,23 @@ impl MachineState {
         self.ball.reset();
 
         let addr = self.registers[1];
-        self.ball.boundary = self.heap.len();
-
-        copy_term(
-            CopyBallTerm::new(
-                &mut self.attr_var_init.attr_var_queue,
-                &mut self.stack,
-                &mut self.heap,
-                &mut self.ball.stub,
-            ),
-            addr,
-            AttrVarPolicy::DeepCopy,
+        let ball_boundary = self.heap.cell_len();
+
+        step_or_resource_error!(
+            self,
+            copy_term(
+                CopyBallTerm::new(
+                    &mut self.attr_var_init.attr_var_queue,
+                    &mut self.stack,
+                    &mut self.heap,
+                    &mut self.ball.stub,
+                ),
+                addr,
+                AttrVarPolicy::DeepCopy,
+            )
         );
+
+        self.ball.boundary = ball_boundary;
     }
 
     #[inline(always)]
@@ -336,84 +352,34 @@ impl MachineState {
         self.fail = true;
     }
 
+    // return the read value and the succeeding HeapPtr
     pub(crate) fn read_s(&mut self) -> HeapCellValue {
-        match &mut self.s {
-            &mut HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]),
-            &mut HeapPtr::PStrChar(h, n) if self.s_offset == 0 => {
-                read_heap_cell!(self.heap[h],
-                    (HeapCellValueTag::PStr, pstr_atom) => {
-                        let pstr = PartialString::from(pstr_atom);
-
-                        if let Some(c) = pstr.as_str_from(n).chars().next() {
-                            char_as_cell!(c)
-                        } else {
-                            self.deref(self.heap[h+1])
-                        }
-                    }
-                    (HeapCellValueTag::CStr, cstr_atom) => {
-                        let pstr = PartialString::from(cstr_atom);
-
-                        if let Some(c) = pstr.as_str_from(n).chars().next() {
-                            char_as_cell!(c)
-                        } else {
-                            empty_list_as_cell!()
-                        }
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                )
-            }
-            &mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrLocation(h, ref mut n) => {
-                read_heap_cell!(self.heap[h],
-                    (HeapCellValueTag::PStr, pstr_atom) => {
-                        let pstr = PartialString::from(pstr_atom);
-                        let n_offset: usize = pstr.as_str_from(*n)
-                            .chars()
-                            .take(self.s_offset)
-                            .map(|c| c.len_utf8())
-                            .sum();
-
-                        self.s_offset = 0;
-                        *n += n_offset;
-
-                        if *n < pstr_atom.len() {
-                            let h_len = self.heap.len();
-
-                            self.heap.push(pstr_offset_as_cell!(h));
-                            self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64)));
-
-                            pstr_loc_as_cell!(h_len)
-                        } else {
-                            self.deref(self.heap[h+1])
-                        }
-                    }
-                    (HeapCellValueTag::CStr, cstr_atom) => {
-                        let pstr = PartialString::from(cstr_atom);
-                        let n_offset: usize = pstr.as_str_from(*n)
-                            .chars()
-                            .take(self.s_offset)
-                            .map(|c| c.len_utf8())
-                            .sum();
-
-                        self.s_offset = 0;
-                        *n += n_offset;
-
-                        if *n < cstr_atom.len() {
-                            let h_len = self.heap.len();
-
-                            self.heap.push(pstr_offset_as_cell!(h));
-                            self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64)));
-
-                            pstr_loc_as_cell!(h_len)
-                        } else {
-                            empty_list_as_cell!()
-                        }
-                    }
-                    _ => {
-                        unreachable!()
+        match self.s {
+            HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]),
+            HeapPtr::PStr(h) => {
+                let mut char_iter = self.heap.char_iter(h);
+
+                if self.s_offset == 0 { // read the car of the list
+                    let c = char_iter.next().unwrap();
+                    char_as_cell!(c)
+                } else { // read the (self.s_offset)^{th} cdr of the list
+                    let byte_offset: usize = char_iter
+                        .take(self.s_offset)
+                        .map(|c| c.len_utf8())
+                        .sum();
+                    let new_h = h + byte_offset;
+
+                    self.s_offset = 0;
+
+                    if self.heap.char_iter(new_h).next().is_some() {
+                        self.s = HeapPtr::PStr(new_h);
+                        pstr_loc_as_cell!(new_h)
+                    } else {
+                        let h = Heap::neighboring_cell_offset(new_h);
+                        self.s = HeapPtr::HeapCell(h);
+                        self.deref(heap_loc_as_cell!(h))
                     }
-                )
+                }
             }
         }
     }
@@ -482,6 +448,7 @@ impl MachineState {
                                         return Some(n1.cmp(&n2));
                                     }
                                 }
+                                /*
                                 (HeapCellValueTag::Char, c2) => {
                                     if let Some(c1) = n1.as_char() {
                                         if c1 != c2 {
@@ -496,6 +463,7 @@ impl MachineState {
                                         );
                                     }
                                 }
+                                */
                                 (HeapCellValueTag::Str, s) => {
                                     let n2 = cell_as_atom_cell!(self.heap[s])
                                         .get_name();
@@ -510,6 +478,7 @@ impl MachineState {
                                 }
                             )
                         }
+                        /*
                         (HeapCellValueTag::Char, c1) => {
                             read_heap_cell!(v2,
                                 (HeapCellValueTag::Atom, (n2, _a2)) => {
@@ -554,6 +523,7 @@ impl MachineState {
                                 }
                             )
                         }
+                        */
                         (HeapCellValueTag::Str, s) => {
                             let n1 = cell_as_atom_cell!(self.heap[s])
                                 .get_name();
@@ -565,6 +535,7 @@ impl MachineState {
                                         return Some(n1.cmp(&n2));
                                     }
                                 }
+                                /*
                                 (HeapCellValueTag::Char, c2) => {
                                     if let Some(c1) = n1.as_char() {
                                         if c1 != c2 {
@@ -579,6 +550,7 @@ impl MachineState {
                                         );
                                     }
                                 }
+                                */
                                 (HeapCellValueTag::Str, s) => {
                                     let n2 = cell_as_atom_cell!(self.heap[s])
                                         .get_name();
@@ -599,121 +571,22 @@ impl MachineState {
                     )
                 }
                 Some(TermOrderCategory::Compound) => {
-                    fn stalled_pstr_iter_comparator(
-                        iteratee: PStrIteratee,
-                        iter2: HeapPStrIter,
-                        pdl: &mut Vec<HeapCellValue>,
-                    ) -> Option<Ordering> {
-                        let compound = Some(TermOrderCategory::Compound);
-
-                        if iter2.focus.order_category(iter2.heap) != compound {
-                            Some(compound.cmp(&iter2.focus.order_category(iter2.heap)))
-                        } else {
-                            let c1 = match iteratee {
-                                PStrIteratee::Char(_, c) => c,
-                                PStrIteratee::PStrSegment(focus, pstr_atom, n) => {
-                                    let pstr = PartialString::from(pstr_atom);
-
-                                    match pstr.as_str_from(n).chars().next() {
-                                        Some(c) => c,
-                                        None => {
-                                            pdl.push(iter2.focus);
-                                            // iter2 is continuable, so it
-                                            // has a tail in the heap at
-                                            // focus+1.
-                                            pdl.push(iter2.heap[focus + 1]);
-
-                                            return None;
-                                        }
-                                    }
-                                }
-                            };
-
-                            read_heap_cell!(iter2.focus,
-                                (HeapCellValueTag::Lis, l) => {
-                                    pdl.push(iter2.heap[l]);
-                                    pdl.push(char_as_cell!(c1));
-
-                                    None
-                                }
-                                (HeapCellValueTag::Str, s) => {
-                                    let (name, arity) = cell_as_atom_cell!(iter2.heap[s])
-                                        .get_name_and_arity();
-
-                                    if name == atom!(".") && arity == 2 {
-                                        pdl.push(iter2.heap[s+1]);
-                                        pdl.push(char_as_cell!(c1));
-
-                                        None
-                                    } else {
-                                        Some((2, atom!(".")).cmp(&(arity, name)))
-                                    }
-                                }
-                                _ => {
-                                    unreachable!()
-                                }
-                            )
-                        }
-                    }
-
-                    fn pstr_comparator(
-                        heap: &[HeapCellValue],
-                        pdl: &mut Vec<HeapCellValue>,
-                        s1: usize,
-                        s2: usize,
-                    ) -> Option<Ordering> {
-                        let mut iter1 = HeapPStrIter::new(heap, s1);
-                        let mut iter2 = HeapPStrIter::new(heap, s2);
-
-                        match compare_pstr_prefixes(&mut iter1, &mut iter2) {
-                            PStrCmpResult::Ordered(ordering) => Some(ordering),
-                            PStrCmpResult::FirstIterContinuable(iteratee) => {
-                                stalled_pstr_iter_comparator(iteratee, iter2, pdl)
-                            }
-                            PStrCmpResult::SecondIterContinuable(iteratee) => {
-                                let result = stalled_pstr_iter_comparator(iteratee, iter1, pdl);
-
-                                if let Some(ordering) = result {
-                                    Some(ordering.reverse())
-                                } else {
-                                    let pdl_len = pdl.len();
-                                    pdl.swap(pdl_len - 2, pdl_len - 1);
-                                    result
-                                }
-                            }
-                            PStrCmpResult::Unordered => {
-                                pdl.push(iter2.focus);
-                                pdl.push(iter1.focus);
-
-                                None
-                            }
-                        }
-                    }
-
                     read_heap_cell!(v1,
                         (HeapCellValueTag::Lis, l1) => {
                             read_heap_cell!(v2,
-                                (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
-                                    let h = self.heap.len();
-
-                                    self.heap.push(v1);
-                                    self.heap.push(v2);
-
-                                    if let Some(ordering) = pstr_comparator(
-                                        &self.heap, &mut self.pdl, h, h+1
-                                    ) {
-                                        if ordering != Ordering::Equal {
-                                            self.heap.pop();
-                                            self.heap.pop();
-
-                                            self.pdl.clear();
-
-                                            return Some(ordering);
-                                        }
-                                    }
-
-                                    self.heap.pop();
-                                    self.heap.pop();
+                                (HeapCellValueTag::PStrLoc, l2) => {
+                                    // like the action of
+                                    // partial_string_to_pdl here but
+                                    // the ordering of PDL pushes is
+                                    // (crucially for comparison
+                                    // correctness) different.
+                                    let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
+
+                                    self.pdl.push(succ_cell);
+                                    self.pdl.push(heap_loc_as_cell!(l1 + 1));
+
+                                    self.pdl.push(char_as_cell!(c));
+                                    self.pdl.push(heap_loc_as_cell!(l1));
                                 }
                                 (HeapCellValueTag::Lis, l2) => {
                                     if tabu_list.contains(&(l1, l2)) {
@@ -757,27 +630,44 @@ impl MachineState {
                                 }
                             )
                         }
-                        (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
-                            let h = self.heap.len();
-
-                            self.heap.push(v1);
-                            self.heap.push(v2);
+                        (HeapCellValueTag::PStrLoc, l1) => {
+                            read_heap_cell!(v2,
+                                (HeapCellValueTag::PStrLoc, l2) => {
+                                    let cmp_result = self.heap.compare_pstr_segments(l1, l2);
 
-                            if let Some(ordering) = pstr_comparator(
-                                &self.heap, &mut self.pdl, h, h+1,
-                            ) {
-                                if ordering != Ordering::Equal {
-                                    self.heap.pop();
-                                    self.heap.pop();
+                                    if let Some(ordering) = cmp_result.continue_pstr_compare(&mut self.pdl) {
+                                        return Some(ordering);
+                                    }
+                                }
+                                (HeapCellValueTag::Lis, l2) => {
+                                    let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
 
-                                    self.pdl.clear();
+                                    self.pdl.push(succ_cell);
+                                    self.pdl.push(heap_loc_as_cell!(l2 + 1));
 
-                                    return Some(ordering);
+                                    self.pdl.push(char_as_cell!(c));
+                                    self.pdl.push(heap_loc_as_cell!(l2));
                                 }
-                            }
+                                (HeapCellValueTag::Str, s) => {
+                                    let (name, arity) = cell_as_atom_cell!(self.heap[s])
+                                        .get_name_and_arity();
+
+                                    if name == atom!(".") && arity == 2 {
+                                        let (c, succ_cell) = self.heap.last_str_char_and_tail(l1);
+
+                                        self.pdl.push(heap_loc_as_cell!(s+2));
+                                        self.pdl.push(succ_cell);
 
-                            self.heap.pop();
-                            self.heap.pop();
+                                        self.pdl.push(heap_loc_as_cell!(s+1));
+                                        self.pdl.push(char_as_cell!(c));
+                                    } else {
+                                        self.fail = true;
+                                    }
+                                }
+                                _ => {
+                                    unreachable!()
+                                }
+                            );
                         }
                         (HeapCellValueTag::Str, s1) => {
                             read_heap_cell!(v2,
@@ -831,27 +721,21 @@ impl MachineState {
                                         }
                                     }
                                 }
-                                (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
-                                    let h = self.heap.len();
-
-                                    self.heap.push(v1);
-                                    self.heap.push(v2);
+                                (HeapCellValueTag::PStrLoc, l2) => {
+                                    let (name, arity) = cell_as_atom_cell!(self.heap[s1])
+                                        .get_name_and_arity();
 
-                                    if let Some(ordering) = pstr_comparator(
-                                        &self.heap, &mut self.pdl, h, h+1,
-                                    ) {
-                                        if ordering != Ordering::Equal {
-                                            self.heap.pop();
-                                            self.heap.pop();
+                                    if name == atom!(".") && arity == 2 {
+                                        let (c, succ_cell) = self.heap.last_str_char_and_tail(l2);
 
-                                            self.pdl.clear();
+                                        self.pdl.push(succ_cell);
+                                        self.pdl.push(heap_loc_as_cell!(s1+2));
 
-                                            return Some(ordering);
-                                        }
+                                        self.pdl.push(char_as_cell!(c));
+                                        self.pdl.push(heap_loc_as_cell!(s1+1));
+                                    } else {
+                                        self.fail = true;
                                     }
-
-                                    self.heap.pop();
-                                    self.heap.pop();
                                 }
                                 _ => {
                                     unreachable!()
@@ -875,185 +759,37 @@ impl MachineState {
         Some(Ordering::Equal)
     }
 
-    pub fn match_partial_string(&mut self, value: HeapCellValue, string: Atom, has_tail: bool) {
-        let h = self.heap.len();
-        self.heap.push(value);
-
-        let prefix_len;
-        let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h);
-
-        let s = string.as_str();
-
-        match heap_pstr_iter.compare_pstr_to_string(&s) {
-            Some(PStrPrefixCmpResult {
-                focus,
-                offset,
-                prefix_len,
-            }) if prefix_len == s.len() => {
-                let focus_addr = self.heap[focus];
-
-                read_heap_cell!(focus_addr,
-                    (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => {
-                        if has_tail {
-                            self.s = HeapPtr::PStrLocation(focus, offset);
-                            self.s_offset = 0;
-                            self.mode = MachineMode::Read;
-                        } else if offset == pstr_atom.len() {
-                            let focus = heap_pstr_iter.focus;
-                            unify!(self, focus, empty_list_as_cell!());
-                        } else {
-                            self.fail = true;
-                        }
-                    }
-                    (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, h) => {
-                        let (focus, _) = pstr_loc_and_offset(&self.heap, h);
-                        let pstr_atom = cell_as_atom!(self.heap[focus]);
-
-                        if has_tail {
-                            self.s = HeapPtr::PStrLocation(focus, offset);
-                            self.s_offset = 0;
-                            self.mode = MachineMode::Read;
-                        } else if offset == pstr_atom.len() {
-                            let focus = heap_pstr_iter.focus;
-                            unify!(self, focus, empty_list_as_cell!());
-                        } else {
-                            self.fail = true;
-                        }
-                    }
-                    _ => {
-                        let focus = heap_pstr_iter.focus();
-
-                        if has_tail {
-                            self.s = HeapPtr::HeapCell(focus);
-                            self.s_offset = 0;
-                            self.mode = MachineMode::Read;
-                        } else {
-                            let focus = heap_pstr_iter.focus;
-                            unify!(self, focus, empty_list_as_cell!());
-                        }
-                    }
-                );
+    /* TODO: new, inlined match_partial_string. now inlined into GetPartialString,
+     * the only place it is called from. Therefore, it has been inlined.
 
-                return;
+    pub fn match_partial_string(
+        &mut self,
+        value: HeapCellValue,
+        string: &str,
+    ) -> Result<(), usize> {
+        debug_assert!(value.is_ref());
+
+        self.heap[0] = value;
+        let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, 0);
+
+        match heap_pstr_iter.compare_pstr_to_string(string) {
+            Some(PStrCmpResult::CompleteMatch { bytes_matched, pstr_loc }) => {
+                self.s_offset = bytes_matched;
+                self.s = HeapPtr::PStr(pstr_loc);
+                self.mode = MachineMode::Read;
             }
-            Some(PStrPrefixCmpResult {
-                prefix_len: inner_prefix_len,
-                ..
-            }) => {
-                prefix_len = inner_prefix_len;
+            Some(PStrCmpResult::PartialMatch { string, var_loc }) => {
+                let cell = self.heap.allocate_pstr(string)?;
+                unify!(self, cell, heap_loc_as_loc!(var_loc));
             }
             None => {
-                read_heap_cell!(value,
-                    (HeapCellValueTag::Str, s) => {
-                        let cell = heap_loc_as_cell!(s + 1);
-                        let is_list = self.heap[s] == atom_as_cell!(atom!("."), 2);
-
-                        if !(is_list && self.store(self.deref(cell)).is_var()) {
-                            self.fail = true;
-                            return;
-                        }
-                    }
-                    (HeapCellValueTag::Lis, l) => {
-                        let cell = heap_loc_as_cell!(l);
-
-                        if !self.store(self.deref(cell)).is_var() {
-                            self.fail = true;
-                            return;
-                        }
-                    }
-                    (HeapCellValueTag::AttrVar |
-                     HeapCellValueTag::StackVar |
-                     HeapCellValueTag::Var) => {
-                    }
-                    _ => {
-                        self.fail = true;
-                        return;
-                    }
-                );
-
-                prefix_len = 0;
+                self.fail = true;
             }
         }
 
-        let focus = heap_pstr_iter.focus();
-        let tail_addr = self.heap[focus];
-        let target_cell = self.push_str_to_heap(&string.as_str()[prefix_len..], has_tail);
-
-        unify!(self, tail_addr, target_cell);
-    }
-
-    #[inline(always)]
-    pub(super) fn push_str_to_heap(&mut self, pstr: &str, has_tail: bool) -> HeapCellValue {
-        let h = self.heap.len();
-
-        if has_tail {
-            self.s = HeapPtr::HeapCell(h + 1);
-            self.s_offset = 0;
-            self.mode = MachineMode::Read;
-
-            put_partial_string(&mut self.heap, pstr, &self.atom_tbl)
-        } else {
-            put_complete_string(&mut self.heap, pstr, &self.atom_tbl)
-        }
-    }
-
-    pub(super) fn write_literal_to_var(&mut self, deref_v: HeapCellValue, lit: HeapCellValue) {
-        let store_v = self.store(deref_v);
-
-        read_heap_cell!(lit,
-            (HeapCellValueTag::Atom, (atom, arity)) => {
-                if arity == 0 {
-                    self.unify_atom(atom, store_v);
-                } else {
-                    self.fail = true;
-                }
-            }
-            (HeapCellValueTag::Char, c) => {
-                self.unify_char(c, store_v);
-            }
-            (HeapCellValueTag::Fixnum, n) => {
-                self.unify_fixnum(n, store_v);
-            }
-            (HeapCellValueTag::F64, f64_ptr) => {
-                self.unify_f64(f64_ptr, store_v);
-            }
-            (HeapCellValueTag::Cons, ptr) => {
-                match_untyped_arena_ptr!(ptr,
-                     (ArenaHeaderTag::Integer, n) => {
-                         self.unify_big_int(n, store_v);
-                     }
-                     (ArenaHeaderTag::Rational, r) => {
-                         self.unify_rational(r, store_v);
-                     }
-                     _ => {
-                         self.fail = true;
-                     }
-                )
-            }
-            (HeapCellValueTag::CStr, cstr_atom) => {
-                read_heap_cell!(store_v,
-                    (HeapCellValueTag::PStrLoc |
-                     HeapCellValueTag::Lis |
-                     HeapCellValueTag::Str) => {
-                        self.match_partial_string(store_v, cstr_atom, false);
-                    }
-                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
-                        let r = store_v.as_var().unwrap();
-                        self.bind(r, lit);
-                    }
-                    (HeapCellValueTag::CStr, cstr2_atom) => {
-                        self.fail = cstr_atom != cstr2_atom;
-                    }
-                    _ => {
-                        self.fail = true;
-                    }
-                );
-            }
-            _ => {
-                unreachable!()
-            }
-        )
+        Ok(())
     }
+    */
 
     pub(crate) fn setup_call_n_init_goal_info(
         &mut self,
@@ -1084,9 +820,11 @@ impl MachineState {
 
                 (name, 0, 0)
             }
+            /*
             (HeapCellValueTag::Char, c) => {
                 (AtomTable::build_with(&self.atom_tbl, &c.to_string()), 0, 0)
             }
+            */
             (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
                 let stub = functor_stub(atom!("call"), arity + 1);
                 let err = self.instantiation_error();
@@ -1118,24 +856,14 @@ impl MachineState {
     }
 
     #[inline]
-    pub fn is_cyclic_term(&mut self, value: HeapCellValue) -> bool {
-        let value = self.store(self.deref(value));
-
-        if value.is_stack_var() || value.is_constant() {
+    pub fn is_cyclic_term(&mut self, term_loc: usize) -> bool {
+        if self.heap[term_loc].is_stack_var() {
             return false;
         }
 
-        let h = self.heap.len();
-        self.heap.push(value);
-
-        let cycle_found = {
-            let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, h);
-            for _ in iter.by_ref() {}
-            iter.cycle_found()
-        };
-
-        self.heap.pop();
-        cycle_found
+        let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, term_loc);
+        for _ in iter.by_ref() {}
+        iter.cycle_found()
     }
 
     // arg(+N, +Term, ?Arg)
@@ -1202,19 +930,27 @@ impl MachineState {
                     (HeapCellValueTag::PStrLoc, pstr_loc) => {
                         if n == 1 || n == 2 {
                             let a3 = self.registers[3];
-                            let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc);
+                            // let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc);
+                            let mut char_iter = self.heap.char_iter(pstr_loc);
 
-                            let pstr = cell_as_string!(self.heap[h]);
-                            let offset = offset.get_num() as usize;
+                            // let pstr = cell_as_string!(self.heap[h]);
+                            // let offset = offset.get_num() as usize;
 
-                            if let Some(c) = pstr.as_str_from(offset).chars().next() {
+                            if let Some(c) = char_iter.next() { // pstr.as_str_from(offset).chars().next() {
                                 if n == 1 {
                                     self.unify_char(c, a3);
                                 } else {
-                                    let offset = (offset + c.len_utf8()) as i64;
-                                    let h_len = self.heap.len();
-                                    let pstr_atom: Atom = pstr.into();
+                                    // let offset = (offset + c.len_utf8()) as i64;
+                                    // let h_len = self.heap.len();
+                                    // let pstr_atom: Atom = pstr.into();
+                                    if char_iter.next().is_some() {
+                                        unify_fn!(*self, pstr_loc_as_cell!(pstr_loc + c.len_utf8()), a3);
+                                    } else {
+                                        let tail_idx = Heap::neighboring_cell_offset(pstr_loc);
+                                        unify_fn!(*self, self.heap[tail_idx]);
+                                    }
 
+                                    /*
                                     if pstr_atom.len() > offset as usize {
                                         self.heap.push(pstr_offset_as_cell!(h));
                                         self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset)));
@@ -1233,6 +969,7 @@ impl MachineState {
                                             }
                                         }
                                     }
+                                    */
                                 }
                             } else {
                                 unreachable!()
@@ -1241,6 +978,7 @@ impl MachineState {
                             self.fail = true;
                         }
                     }
+                    /*
                     (HeapCellValueTag::CStr, cstr_atom) => {
                         let cstr = PartialString::from(cstr_atom);
 
@@ -1267,6 +1005,7 @@ impl MachineState {
                             unreachable!()
                         }
                     }
+                    */
                     _ => {
                         // 8.5.2.3 d)
                         let err = self.type_error(ValidType::Compound, term);
@@ -1297,7 +1036,7 @@ impl MachineState {
 
     fn try_functor_unify_components(&mut self, name: HeapCellValue, arity: usize) {
         let a2 = self.deref(self.registers[2]);
-        self.write_literal_to_var(a2, name);
+        unify!(self, a2, name);
 
         if !self.fail {
             let a3 = self.store(self.deref(self.registers[3]));
@@ -1305,20 +1044,25 @@ impl MachineState {
         }
     }
 
-    fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) {
-        let h = self.heap.len();
+    fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) -> Result<(), usize> {
+        let h = self.heap.cell_len();
+        let mut writer = self.heap.reserve(arity + 1)?;
 
         let f_a = if name == atom!(".") && arity == 2 {
-            self.heap.push(heap_loc_as_cell!(h));
-            self.heap.push(heap_loc_as_cell!(h + 1));
+            writer.write_with(|section| {
+                section.push_cell(heap_loc_as_cell!(h));
+                section.push_cell(heap_loc_as_cell!(h + 1));
+            });
 
             list_loc_as_cell!(h)
         } else {
-            self.heap.push(atom_as_cell!(name, arity));
+            writer.write_with(|section| {
+                section.push_cell(atom_as_cell!(name, arity));
 
-            for i in 0..arity {
-                self.heap.push(heap_loc_as_cell!(h + i + 1));
-            }
+                for i in 0..arity {
+                    section.push_cell(heap_loc_as_cell!(h + i + 1));
+                }
+            });
 
             if arity == 0 {
                 heap_loc_as_cell!(h)
@@ -1328,6 +1072,7 @@ impl MachineState {
         };
 
         (self.bind_fn)(self, r, f_a);
+        Ok(())
     }
 
     pub fn try_functor(&mut self) -> CallResult {
@@ -1335,7 +1080,7 @@ impl MachineState {
         let a1 = self.store(self.deref(self.registers[1]));
 
         read_heap_cell!(a1,
-            (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum |
+            (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // | HeapCellValueTag::Char
              HeapCellValueTag::F64) => {
                 self.try_functor_unify_components(a1, 0);
             }
@@ -1347,7 +1092,7 @@ impl MachineState {
                 let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity();
                 self.try_functor_compound_case(name, arity);
             }
-            (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
+            (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { // | HeapCellValueTag::CStr) => {
                 self.try_functor_compound_case(atom!("."), 2);
             }
             (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
@@ -1399,16 +1144,19 @@ impl MachineState {
                 };
 
                 read_heap_cell!(store_name,
-                    (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum |
+                    (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // HeapCellValueTag::Char | 
                      HeapCellValueTag::F64) if arity == 0 => {
                         self.bind(a1.as_var().unwrap(), deref_name);
                     }
                     (HeapCellValueTag::Atom, (name, atom_arity)) => {
                         debug_assert_eq!(atom_arity, 0);
-                        self.try_functor_fabricate_struct(
-                            name,
-                            arity as usize,
-                            a1.as_var().unwrap(),
+                        resource_error_call_result!(
+                            self,
+                            self.try_functor_fabricate_struct(
+                                name,
+                                arity as usize,
+                                a1.as_var().unwrap(),
+                            )
                         );
                     }
                     (HeapCellValueTag::Str, s) => {
@@ -1416,25 +1164,33 @@ impl MachineState {
                             .get_name_and_arity();
 
                         if atom_arity == 0 {
-                            self.try_functor_fabricate_struct(
-                                name,
-                                arity as usize,
-                                a1.as_var().unwrap(),
+                            resource_error_call_result!(
+                                self,
+                                self.try_functor_fabricate_struct(
+                                    name,
+                                    arity as usize,
+                                    a1.as_var().unwrap(),
+                                )
                             );
                         } else {
                             let err = self.type_error(ValidType::Atomic, store_name);
                             return Err(self.error_form(err, stub_gen()));
                         }
                     }
+                    /*
                     (HeapCellValueTag::Char, c) => {
                         let c = AtomTable::build_with(&self.atom_tbl, &c.to_string());
 
-                        self.try_functor_fabricate_struct(
-                            c,
-                            arity as usize,
-                            a1.as_var().unwrap(),
+                        resource_error_call_result!(
+                            self,
+                            self.try_functor_fabricate_struct(
+                                c,
+                                arity as usize,
+                                a1.as_var().unwrap(),
+                            )
                         );
                     }
+                    */
                     (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum |
                      HeapCellValueTag::F64) if arity != 0 => {
                         let err = self.type_error(ValidType::Atom, store_name);
@@ -1457,7 +1213,7 @@ impl MachineState {
     pub fn try_from_list(
         &mut self,
         value: HeapCellValue,
-        stub_gen: impl Fn() -> FunctorStub,
+        stub_gen: impl Fn() -> MachineStub,
     ) -> Result<Vec<HeapCellValue>, MachineStub> {
         let value = self.store(self.deref(value));
 
@@ -1465,8 +1221,8 @@ impl MachineState {
             (HeapCellValueTag::Lis, l) => {
                 self.try_from_inner_list(vec![], l, stub_gen, value)
             }
-            (HeapCellValueTag::PStrLoc, h) => {
-                self.try_from_partial_string(vec![], h, stub_gen, value)
+            (HeapCellValueTag::PStrLoc, pstr_loc) => {
+                self.try_from_partial_string(vec![], pstr_loc, stub_gen, value)
             }
             (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => {
                 let err = self.instantiation_error();
@@ -1491,10 +1247,12 @@ impl MachineState {
                     Err(self.error_form(err, stub_gen()))
                 }
             }
+            /*
             (HeapCellValueTag::CStr, cstr_atom) => {
                 let cstr = cstr_atom.as_str();
                 Ok(cstr.chars().map(|c| char_as_cell!(c)).collect())
             }
+            */
             _ => {
                 let err = self.type_error(ValidType::List, value);
                 Err(self.error_form(err, stub_gen()))
@@ -1506,7 +1264,7 @@ impl MachineState {
         &mut self,
         mut result: Vec<HeapCellValue>,
         mut l: usize,
-        stub_gen: impl Fn() -> FunctorStub,
+        stub_gen: impl Fn() -> MachineStub,
         a1: HeapCellValue,
     ) -> Result<Vec<HeapCellValue>, MachineStub> {
         result.push(self.heap[l]);
@@ -1520,8 +1278,8 @@ impl MachineState {
                     result.push(self.heap[hcp]);
                     l = hcp + 1;
                 }
-                (HeapCellValueTag::PStrLoc, l) => {
-                    return self.try_from_partial_string(result, l, stub_gen, a1);
+                (HeapCellValueTag::PStrLoc, pstr_loc) => {
+                    return self.try_from_partial_string(result, pstr_loc, stub_gen, a1);
                 }
                 (HeapCellValueTag::Str, s) => {
                     let (name, arity) = cell_as_atom_cell!(self.heap[s])
@@ -1560,52 +1318,34 @@ impl MachineState {
     fn try_from_partial_string(
         &mut self,
         mut chars: Vec<HeapCellValue>,
-        h: usize,
-        stub_gen: impl Fn() -> FunctorStub,
+        pstr_loc: usize,
+        stub_gen: impl Fn() -> MachineStub,
         a1: HeapCellValue,
     ) -> Result<Vec<HeapCellValue>, MachineStub> {
-        let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h);
+        self.heap[0] = pstr_loc_as_cell!(pstr_loc);
+        let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, 0);
 
-        for iteratee in heap_pstr_iter.by_ref() {
+        while let Some(iteratee) = heap_pstr_iter.next() {
             match iteratee {
-                PStrIteratee::Char(_, c) => chars.push(char_as_cell!(c)),
-                PStrIteratee::PStrSegment(_, pstr_atom, n) => {
-                    let pstr = PartialString::from(pstr_atom);
-                    chars.extend(pstr.as_str_from(n).chars().map(|c| char_as_cell!(c)));
+                PStrIteratee::Char { value: c, .. } => chars.push(char_as_cell!(c)),
+                PStrIteratee::PStrSlice {
+                    slice_loc,
+                    slice_len,
+                } => {
+                    let pstr = heap_pstr_iter.heap.slice_to_str(slice_loc, slice_len);
+                    chars.extend(pstr.chars().map(|c| char_as_cell!(c)));
                 }
             }
         }
 
-        match self.heap[h].get_tag() {
-            HeapCellValueTag::PStr => {
-                if heap_pstr_iter.at_string_terminator() {
-                    Ok(chars)
-                } else {
-                    read_heap_cell!(self.heap[heap_pstr_iter.focus()],
-                        (HeapCellValueTag::Lis, l) => {
-                            self.try_from_inner_list(chars, l, stub_gen, a1)
-                        }
-                        (HeapCellValueTag::Atom, (name, arity)) => {
-                            if name == atom!(".") && arity == 2 {
-                                let l = heap_pstr_iter.focus() + 1;
-                                self.try_from_inner_list(chars, l, stub_gen, a1)
-                            } else {
-                                let err = self.type_error(ValidType::List, a1);
-                                Err(self.error_form(err, stub_gen()))
-                            }
-                        }
-                        _ => {
-                            let err = self.type_error(ValidType::List, a1);
-                            Err(self.error_form(err, stub_gen()))
-                        }
-                    )
-                }
-            }
-            HeapCellValueTag::CStr => Ok(chars),
-            _ => {
-                unreachable!()
-            }
+        let end_cell = heap_pstr_iter.heap[heap_pstr_iter.focus()];
+
+        if heap_pstr_iter.is_cyclic() || end_cell == empty_list_as_cell!() {
+            let err = self.type_error(ValidType::List, a1);
+            return Err(self.error_form(err, stub_gen()));
         }
+
+        Ok(chars)
     }
 
     // returns true on failure.
@@ -1624,7 +1364,7 @@ impl MachineState {
     pub fn integers_to_bytevec(
         &mut self,
         value: HeapCellValue,
-        stub_gen: impl Fn() -> FunctorStub,
+        stub_gen: impl Fn() -> MachineStub,
     ) -> Vec<u8> {
         let mut bytes: Vec<u8> = Vec::new();
 
index e169525de3dfce75ece3a12858d0b96d38df2f6d..fb84400a1587a46541abd726e7380733f63c6feb 100644 (file)
@@ -4,16 +4,12 @@ pub use crate::machine::machine_state::*;
 pub use crate::machine::streams::*;
 pub use crate::machine::*;
 pub use crate::parser::ast::*;
-use crate::read::*;
-pub use crate::types::*;
-
-use std::sync::Arc;
 
 #[cfg(test)]
 use crate::machine::copier::CopierTarget;
 
 #[cfg(test)]
-use std::ops::{Deref, DerefMut, Index, IndexMut};
+use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
 
 // a mini-WAM for test purposes.
 
@@ -31,7 +27,6 @@ impl MockWAM {
         Self {
             machine_st: MachineState::new(),
             op_dir,
-            //flags: MachineFlags::default(),
         }
     }
 
@@ -56,7 +51,7 @@ impl MockWAM {
     ) -> Result<String, CompilationError> {
         let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
 
-        print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
+        print_heap_terms(self.machine_st.heap.splice(..), term_write_result.focus);
 
         let var_names = term_write_result
             .inverse_var_locs
@@ -68,11 +63,10 @@ impl MockWAM {
 
         let mut printer = HCPrinter::new(
             &mut self.machine_st.heap,
-            Arc::clone(&self.machine_st.atom_tbl),
             &mut self.machine_st.stack,
             &self.op_dir,
             PrinterOutputter::new(),
-            term_write_result.heap_loc,
+            term_write_result.focus,
         );
 
         printer.var_names = var_names;
@@ -154,10 +148,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) {
         self.wam
             .machine_st
@@ -171,43 +161,123 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
     }
 
     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 pstr_head_cell_index(&self, pstr_loc: usize) -> usize {
+        self.wam.machine_st.heap.pstr_vec()[0 .. cell_index!(pstr_loc)]
+            .last_zero()
+            .map(|idx| idx + 1)
+            .unwrap_or(0)
+    }
+
+    #[inline(always)]
+    fn pstr_at(&self, loc: usize) -> bool {
+        self.wam.machine_st.heap.pstr_vec()[loc]
+    }
+
+    #[inline(always)]
+    fn next_non_pstr_cell_index(&self, loc: usize) -> usize {
+        // unwrap is safe here because a partial string is always
+        // followed by a tail cell, i.e. a non-pstr cell, supposing
+        // self.machine_st.heap[loc] is a pstr cell
+        self.wam.machine_st.heap.pstr_vec()[loc ..].first_zero()
+            .map(|idx| idx + loc)
+            .unwrap()
+    }
+
+    #[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)]
-pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
-    for (idx, cell) in heap.iter().enumerate() {
+pub fn all_cells_marked_and_unforwarded(iter: impl SizedHeap) {
+    let mut idx = 0;
+    let cell_len = iter.cell_len();
+
+    while idx < cell_len {
+        let curr_idx = idx;
+        let cell = if iter.pstr_at(idx) {
+            let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx));
+            idx = last_cell_loc;
+            iter[last_cell_loc - 1]
+        } else {
+            idx += 1;
+            iter[curr_idx]
+        };
+
         assert!(
             cell.get_mark_bit(),
             "cell {:?} at index {} is not marked",
             cell,
-            idx
+            curr_idx
         );
         assert!(
             !cell.get_forwarding_bit(),
             "cell {:?} at index {} is forwarded",
             cell,
-            idx
+            curr_idx
         );
     }
 }
 
 #[cfg(test)]
-pub fn all_cells_unmarked(heap: &Heap) {
-    for (idx, cell) in heap.iter().enumerate() {
+pub fn unmark_all_cells(mut iter: impl SizedHeapMut) {
+    let mut idx = 0;
+    let cell_len = iter.cell_len();
+
+    while idx < cell_len {
+        if iter.pstr_at(idx) {
+            iter[idx].set_mark_bit(false);
+
+            let last_cell_loc = {
+                let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx));
+                last_cell_loc
+            };
+
+            iter[last_cell_loc].set_mark_bit(false);
+            idx = last_cell_loc;
+        } else {
+            iter[idx].set_mark_bit(false);
+            idx += 1;
+        }
+    }
+}
+
+#[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;
+        let cell = if iter.pstr_at(idx) {
+            let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx));
+            idx = last_cell_loc;
+            iter[last_cell_loc - 1]
+        } else {
+            idx += 1;
+            iter[curr_idx]
+        };
+
         assert!(
             !cell.get_mark_bit(),
             "cell {:?} at index {} is still marked",
             cell,
-            idx
-        );
-
-        assert!(
-            !cell.get_forwarding_bit(),
-            "cell {:?} at index {} is still forwarded",
-            cell,
-            idx
+            curr_idx
         );
     }
 }
@@ -258,6 +328,8 @@ impl Machine {
 mod tests {
     use super::*;
 
+    use crate::functor_macro::FunctorElement;
+
     #[test]
     fn unify_tests() {
         let mut wam = MachineState::new();
@@ -278,13 +350,13 @@ mod tests {
             unify!(
                 wam,
                 str_loc_as_cell!(0),
-                str_loc_as_cell!(term_write_result_2.heap_loc)
+                str_loc_as_cell!(term_write_result_2.focus)
             );
 
             assert!(wam.fail);
         }
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.fail = false;
         wam.heap.clear();
@@ -298,14 +370,14 @@ mod tests {
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.heap_loc),
-                heap_loc_as_cell!(term_write_result_2.heap_loc)
+                heap_loc_as_cell!(term_write_result_1.focus),
+                heap_loc_as_cell!(term_write_result_2.focus)
             );
 
             assert!(!wam.fail);
         }
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.fail = false;
         wam.heap.clear();
@@ -319,14 +391,14 @@ mod tests {
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.heap_loc),
-                heap_loc_as_cell!(term_write_result_2.heap_loc)
+                heap_loc_as_cell!(term_write_result_1.focus),
+                heap_loc_as_cell!(term_write_result_2.focus)
             );
 
             assert!(!wam.fail);
         }
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.fail = false;
         wam.heap.clear();
@@ -340,14 +412,14 @@ mod tests {
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.heap_loc),
-                heap_loc_as_cell!(term_write_result_2.heap_loc)
+                heap_loc_as_cell!(term_write_result_1.focus),
+                heap_loc_as_cell!(term_write_result_2.focus)
             );
 
             assert!(!wam.fail);
         }
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.fail = false;
         wam.heap.clear();
@@ -361,14 +433,14 @@ mod tests {
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.heap_loc),
-                heap_loc_as_cell!(term_write_result_2.heap_loc)
+                heap_loc_as_cell!(term_write_result_1.focus),
+                heap_loc_as_cell!(term_write_result_2.focus)
             );
 
             assert!(!wam.fail);
         }
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.fail = false;
         wam.heap.clear();
@@ -380,95 +452,119 @@ mod tests {
             let term_write_result_2 =
                 parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
 
-            all_cells_unmarked(&wam.heap);
+            all_cells_unmarked(wam.heap.splice(..));
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.heap_loc),
-                heap_loc_as_cell!(term_write_result_2.heap_loc)
+                heap_loc_as_cell!(term_write_result_1.focus),
+                heap_loc_as_cell!(term_write_result_2.focus)
             );
 
             assert!(!wam.fail);
         }
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.heap.clear();
 
-        wam.heap.push(pstr_as_cell!(atom!("this is a string")));
-        wam.heap.push(heap_loc_as_cell!(1));
+        let mut writer = wam.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_pstr("this is a string"); // 0
+
+            let h = section.cell_len();
+            assert_eq!(h, 3);
 
-        wam.heap.push(pstr_as_cell!(atom!("this is a string")));
-        wam.heap.push(pstr_loc_as_cell!(4));
+            section.push_cell(heap_loc_as_cell!(h)); // 3
+            section.push_pstr("this is a string"); // 4
 
-        wam.heap.push(pstr_offset_as_cell!(0));
-        wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6)));
+            let h = section.cell_len();
+            assert_eq!(h + 1, 8);
 
-        unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2));
+            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_eq!(wam.heap[1], pstr_loc_as_cell!(4));
+        assert_eq!(wam.heap[3], pstr_loc_as_cell!(heap_index!(8)));
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.heap.clear();
 
-        wam.heap.push(list_loc_as_cell!(1));
-        wam.heap.push(atom_as_cell!(atom!("a")));
-        wam.heap.push(list_loc_as_cell!(3));
-        wam.heap.push(atom_as_cell!(atom!("b")));
-        wam.heap.push(heap_loc_as_cell!(0));
+        let mut writer = wam.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(atom!("a")));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(atom_as_cell!(atom!("b")));
+            section.push_cell(heap_loc_as_cell!(0));
 
-        wam.heap.push(list_loc_as_cell!(6));
-        wam.heap.push(atom_as_cell!(atom!("a")));
-        wam.heap.push(list_loc_as_cell!(8));
-        wam.heap.push(atom_as_cell!(atom!("b")));
-        wam.heap.push(heap_loc_as_cell!(5));
+            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));
 
         assert!(!wam.fail);
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.heap.clear();
 
-        wam.heap.push(list_loc_as_cell!(1));
-        wam.heap.push(atom_as_cell!(atom!("a")));
-        wam.heap.push(list_loc_as_cell!(3));
-        wam.heap.push(atom_as_cell!(atom!("b")));
-        wam.heap.push(heap_loc_as_cell!(0));
+        let mut writer = wam.heap.reserve(96).unwrap();
 
-        wam.heap.push(list_loc_as_cell!(6));
-        wam.heap.push(atom_as_cell!(atom!("a")));
-        wam.heap.push(list_loc_as_cell!(8));
-        wam.heap.push(atom_as_cell!(atom!("c")));
-        wam.heap.push(heap_loc_as_cell!(5));
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(atom!("a")));
+            section.push_cell(list_loc_as_cell!(3));
+            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));
 
         assert!(wam.fail);
 
         wam.fail = false;
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
+
         wam.heap.clear();
 
-        wam.heap.push(list_loc_as_cell!(1));
-        wam.heap.push(atom_as_cell!(atom!("a")));
-        wam.heap.push(list_loc_as_cell!(3));
-        wam.heap.push(atom_as_cell!(atom!("b")));
-        wam.heap.push(heap_loc_as_cell!(5));
+        let mut writer = wam.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(atom_as_cell!(atom!("a")));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(atom_as_cell!(atom!("b")));
+            section.push_cell(heap_loc_as_cell!(5));
 
-        wam.heap.push(list_loc_as_cell!(6));
-        wam.heap.push(atom_as_cell!(atom!("a")));
-        wam.heap.push(list_loc_as_cell!(8));
-        wam.heap.push(atom_as_cell!(atom!("b")));
-        wam.heap.push(heap_loc_as_cell!(0));
+            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));
         assert!(!wam.fail);
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
     }
 
     #[test]
@@ -487,12 +583,12 @@ mod tests {
             let term_write_result_2 =
                 parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
 
-            all_cells_unmarked(&wam.heap);
+            all_cells_unmarked(wam.heap.splice(..));
 
             unify_with_occurs_check!(
                 wam,
                 heap_loc_as_cell!(0),
-                heap_loc_as_cell!(term_write_result_2.heap_loc)
+                heap_loc_as_cell!(term_write_result_2.focus)
             );
 
             assert!(wam.fail);
@@ -505,8 +601,15 @@ mod tests {
 
         let mut wam = MachineState::new();
 
-        wam.heap.push(heap_loc_as_cell!(0));
-        wam.heap.push(heap_loc_as_cell!(1));
+        // clear the heap of resource error data etc
+        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!(
             compare_term_test!(wam, wam.heap[0], wam.heap[1]),
@@ -528,11 +631,13 @@ mod tests {
             Some(Ordering::Equal)
         );
 
+        let cstr_cell = wam.allocate_cstr("string").unwrap();
+
         assert_eq!(
             compare_term_test!(
                 wam,
                 atom_as_cell!(atom!("atom")),
-                atom_as_cstr_cell!(atom!("string"))
+                cstr_cell
             ),
             Some(Ordering::Less)
         );
@@ -566,8 +671,12 @@ mod tests {
 
         wam.heap.clear();
 
-        wam.heap.push(atom_as_cell!(atom!("f"), 1));
-        wam.heap.push(heap_loc_as_cell!(1));
+        let mut writer = wam.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(atom_as_cell!(atom!("f"), 1));
+            section.push_cell(heap_loc_as_cell!(1));
+        });
 
         assert_eq!(
             compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(0)),
@@ -581,21 +690,25 @@ mod tests {
 
         wam.heap.clear();
 
-        // [1,2,3]
-        wam.heap.push(list_loc_as_cell!(1));
-        wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
-        wam.heap.push(list_loc_as_cell!(3));
-        wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
-        wam.heap.push(list_loc_as_cell!(5));
-        wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
-        wam.heap.push(empty_list_as_cell!());
-
-        // [1,2]
-        wam.heap.push(list_loc_as_cell!(8));
-        wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
-        wam.heap.push(list_loc_as_cell!(10));
-        wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
-        wam.heap.push(empty_list_as_cell!());
+        let mut writer = wam.heap.reserve(96).unwrap();
+
+        writer.write_with(|section| {
+            // [1,2,3]
+            section.push_cell(list_loc_as_cell!(1));
+            section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
+            section.push_cell(list_loc_as_cell!(3));
+            section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
+            section.push_cell(list_loc_as_cell!(5));
+            section.push_cell(fixnum_as_cell!(Fixnum::build_with(3)));
+            section.push_cell(empty_list_as_cell!());
+
+            // [1,2]
+            section.push_cell(list_loc_as_cell!(8));
+            section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
+            section.push_cell(list_loc_as_cell!(10));
+            section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
+            section.push_cell(empty_list_as_cell!());
+        });
 
         assert_eq!(
             compare_term_test!(wam, heap_loc_as_cell!(7), heap_loc_as_cell!(7)),
@@ -621,11 +734,13 @@ mod tests {
             Some(Ordering::Greater)
         );
 
+        let cstr_cell = wam.allocate_cstr("string").unwrap();
+
         assert_eq!(
             compare_term_test!(
                 wam,
                 empty_list_as_cell!(),
-                atom_as_cstr_cell!(atom!("string"))
+                cstr_cell
             ),
             Some(Ordering::Less)
         );
@@ -657,55 +772,66 @@ mod tests {
     fn is_cyclic_term_tests() {
         let mut wam = MachineState::new();
 
-        assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f"))));
-        assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555))));
+        let mut writer = wam.heap.reserve(96).unwrap();
 
-        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.splice(..));
         wam.heap.clear();
 
-        wam.heap
-            .extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))]));
+        let mut functor_writer = Heap::functor_writer(
+            functor!(
+                atom!("f"),
+                [atom_as_cell((atom!("a"))),
+                 atom_as_cell((atom!("b")))]
+            ),
+        );
+
+        functor_writer(&mut wam.heap).unwrap();
 
-        assert!(!wam.is_cyclic_term(str_loc_as_cell!(0)));
+        let h = wam.heap.cell_len();
+        wam.heap.push_cell(str_loc_as_cell!(0)).unwrap();
 
-        all_cells_unmarked(&wam.heap);
+        assert!(!wam.is_cyclic_term(h));
 
-        assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1)));
+        all_cells_unmarked(wam.heap.splice(..));
 
-        all_cells_unmarked(&wam.heap);
+        assert!(!wam.is_cyclic_term(1));
 
-        assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2)));
+        all_cells_unmarked(wam.heap.splice(..));
 
-        all_cells_unmarked(&wam.heap);
+        assert!(!wam.is_cyclic_term(2));
+
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.heap[2] = str_loc_as_cell!(0);
 
         print_heap_terms(wam.heap.iter(), 0);
 
-        assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
+        assert!(wam.is_cyclic_term(2));
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.heap[2] = atom_as_cell!(atom!("b"));
         wam.heap[1] = str_loc_as_cell!(0);
 
-        assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
-
-        all_cells_unmarked(&wam.heap);
-
-        assert!(wam.is_cyclic_term(heap_loc_as_cell!(1)));
+        assert!(wam.is_cyclic_term(1));
 
-        all_cells_unmarked(&wam.heap);
+        all_cells_unmarked(wam.heap.splice(..));
 
         wam.heap.clear();
 
-        wam.heap.push(pstr_as_cell!(atom!("a string")));
-        wam.heap.push(empty_list_as_cell!());
+        let h = wam.heap.cell_len();
+        wam.allocate_cstr("a string").unwrap();
 
-        assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0)));
+        assert!(!wam.is_cyclic_term(h));
     }
 }
index f35288926df64b64fe4edf3813a38360b28ce9f1..c75c62343d193d473f3a3be0cc761fe9feef0cc9 100644 (file)
@@ -251,7 +251,7 @@ pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
 
 impl Machine {
     #[inline]
-    fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
+    pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
         (
             MachinePreludeView {
                 indices: &mut self.indices,
@@ -271,7 +271,7 @@ impl Machine {
             .unwrap()
     }
 
-    pub(crate) fn run_module_predicate(
+    pub fn run_module_predicate(
         &mut self,
         module_name: Atom,
         key: PredicateKey,
@@ -619,7 +619,10 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn run_verify_attr_interrupt(&mut self, arity: usize) {
         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 {
@@ -639,12 +642,11 @@ impl Machine {
                                 s,
                             )) => {
                                 cell = self.deref_register(arg);
-                                self.machine_st
-                                    .select_switch_on_term_index(cell, v, c, l, s)
+                                self.machine_st.select_switch_on_term_index(cell, v, c, l, s)
                             }
                             IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
-                                let lit = self.machine_st.constant_to_literal(cell);
-                                hm.get(&lit).cloned().unwrap_or(IndexingCodePtr::Fail)
+                                // let lit = self.machine_st.constant_to_literal(cell);
+                                hm.get(&cell).cloned().unwrap_or(IndexingCodePtr::Fail)
                             }
                             IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
                                 self.machine_st.select_switch_on_structure_index(cell, hm)
@@ -670,6 +672,7 @@ impl Machine {
 
                     if cell.is_var() {
                         offset += 1;
+                    /*
                     } else if lit.get_tag() == HeapCellValueTag::CStr {
                         read_heap_cell!(cell,
                             (HeapCellValueTag::CStr) => {
@@ -696,8 +699,10 @@ impl Machine {
                                 return false;
                             }
                         );
+                    */
                     } else {
-                        self.machine_st.write_literal_to_var(cell, lit);
+                        unify!(self.machine_st, cell, lit);
+                        // self.machine_st.write_literal_to_var(cell, lit);
 
                         if self.machine_st.fail {
                             self.machine_st.fail = false;
@@ -711,7 +716,7 @@ impl Machine {
                     let cell = self.deref_register(t);
 
                     read_heap_cell!(cell,
-                        (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
+                        (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {// | HeapCellValueTag::CStr) => {
                             offset += 1;
                         }
                         (HeapCellValueTag::Str, s) => {
@@ -752,13 +757,14 @@ impl Machine {
                 }
                 &Instruction::GetPartialString(
                     Level::Shallow,
-                    string,
+                    ref _string,
                     RegType::Temp(t),
-                    has_tail,
+                    // has_tail,
                 ) => {
                     let cell = self.deref_register(t);
 
                     read_heap_cell!(cell,
+                        /*
                         (HeapCellValueTag::CStr, cstr) => {
                             if !has_tail && string != cstr {
                                 return false;
@@ -766,11 +772,13 @@ impl Machine {
 
                             offset += 1;
                         }
+                        */
                         (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();
+                            let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
+                                .get_name_and_arity();
 
                             if name == atom!(".") && arity == 2 {
                                 offset += 1;
@@ -893,7 +901,7 @@ impl Machine {
             or_frame.prelude.boip = 0;
             or_frame.prelude.biip = 0;
             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.attr_var_queue_len =
                 self.machine_st.attr_var_init.attr_var_queue.len();
@@ -904,7 +912,7 @@ impl Machine {
                 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;
@@ -925,7 +933,7 @@ impl Machine {
             or_frame.prelude.boip = self.machine_st.oip;
             or_frame.prelude.biip = self.machine_st.iip + iip_offset; // 1
             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.attr_var_queue_len =
                 self.machine_st.attr_var_init.attr_var_queue.len();
@@ -936,7 +944,7 @@ impl Machine {
                 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.iip = 0;
index b76239edd6c44d70a22b3c166e84497fbac24895..7c80dc954a83168388a4377fb1cf32d3ce37c83f 100644 (file)
@@ -1,11 +1,11 @@
 use crate::atom_table::*;
 use crate::heap_iter::{stackful_post_order_iter, NonListElider};
 use crate::machine::{F64Offset, F64Ptr, Fixnum, HeapCellValueTag};
-use crate::parser::ast::{Var, VarPtr};
+use crate::parser::ast::Var;
 use dashu::*;
 use indexmap::IndexMap;
 use ordered_float::OrderedFloat;
-use std::cmp::Ordering;
+use std::borrow::Borrow;
 use std::collections::BTreeMap;
 use std::collections::HashMap;
 use std::fmt::Display;
@@ -24,7 +24,7 @@ pub enum QueryResolution {
     Matches(Vec<QueryMatch>),
 }
 
-fn write_prolog_value_as_json<W: Write>(
+pub fn write_prolog_value_as_json<W: Write>(
     writer: &mut W,
     value: &Value,
 ) -> Result<(), std::fmt::Error> {
@@ -163,29 +163,22 @@ impl Value {
     pub(crate) fn from_heapcell(
         machine: &mut Machine,
         heap_cell: HeapCellValue,
-        var_names: &mut IndexMap<HeapCellValue, VarPtr>,
+        var_names: &mut IndexMap<HeapCellValue, Var>,
     ) -> Self {
         // Adapted from MachineState::read_term_from_heap
         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.stack,
-            heap_cell,
+            0,
         );
 
         let mut anon_count: usize = 0;
-        let var_ptr_cmp = |a, b| match a {
-            Var::Named(name_a) => match b {
-                Var::Named(name_b) => name_a.cmp(&name_b),
-                _ => Ordering::Less,
-            },
-            _ => match b {
-                Var::Named(_) => Ordering::Greater,
-                _ => Ordering::Equal,
-            },
-        };
-
-        for addr in iter {
+
+        while let Some(addr) = iter.next() {
             let addr = unmark_cell_bits!(addr);
 
             read_heap_cell!(addr,
@@ -202,6 +195,7 @@ impl Value {
                             _ => Value::List(vec![head]),
                         },
                         Value::List(elems) if elems.is_empty() => match head {
+                            // a.chars().collect::<Vec<_>>().len() == 1
                             Value::Atom(ref a) if a.chars().collect::<Vec<_>>().len() == 1 => {
                                 // Handle lists of char as strings
                                 Value::String(a.to_string())
@@ -234,29 +228,28 @@ impl Value {
                     term_stack.push(list);
                 }
                 (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
-                    let var = var_names.get(&addr).map(|x| x.borrow().clone());
+                    let var = var_names.get(&addr).cloned();
                     match var {
-                        Some(Var::Named(name)) => term_stack.push(Value::Var(name)),
+                        Some(name) => term_stack.push(Value::Var(name.to_string())),
                         _ => {
                             let anon_name = loop {
                                 // Generate a name for the anonymous variable
                                 let anon_name = count_to_letter_code(anon_count);
 
                                 // Find if this name is already being used
-                                var_names.sort_by(|_, a, _, b| {
-                                    var_ptr_cmp(a.borrow().clone(), b.borrow().clone())
-                                });
+                                var_names.sort_by(|_, a, _, b| a.cmp(b));
+
                                 let binary_result = var_names.binary_search_by(|_,a| {
-                                    let var_ptr = Var::Named(anon_name.clone());
-                                    var_ptr_cmp(a.borrow().clone(), var_ptr.clone())
+                                    let a: &String = a.borrow();
+                                    a.cmp(&anon_name)
                                 });
 
                                 match binary_result {
                                     Ok(_) => anon_count += 1, // Name already used
                                     Err(_) => {
                                         // Name not used, assign it to this variable
-                                        let var_ptr = VarPtr::from(Var::Named(anon_name.clone()));
-                                        var_names.insert(addr, var_ptr);
+                                        let var = anon_name.clone();
+                                        var_names.insert(addr, Var::from(var));
                                         break anon_name;
                                     },
                                 }
@@ -268,9 +261,6 @@ impl Value {
                 (HeapCellValueTag::F64, f) => {
                     term_stack.push(Value::Float(*f));
                 }
-                (HeapCellValueTag::Char, c) => {
-                    term_stack.push(Value::Atom(c.into()));
-                }
                 (HeapCellValueTag::Fixnum, n) => {
                     term_stack.push(Value::Integer(n.into()));
                 }
@@ -281,9 +271,6 @@ impl Value {
                         _ => {}
                     }
                 }
-                (HeapCellValueTag::CStr, s) => {
-                    term_stack.push(Value::String(s.as_str().to_string()));
-                }
                 (HeapCellValueTag::Atom, (name, arity)) => {
                     //let h = iter.focus().value() as usize;
                     //let mut arity = arity;
@@ -325,8 +312,9 @@ impl Value {
                         term_stack.push(Value::Structure(name.as_str().to_string(), subterms));
                     }
                 }
-                (HeapCellValueTag::PStr, atom) => {
+                (HeapCellValueTag::PStrLoc, pstr_loc) => {
                     let tail = term_stack.pop().unwrap();
+                    let char_iter = iter.base_iter.heap.char_iter(pstr_loc);
 
                     match tail {
                         Value::Atom(atom) => {
@@ -334,21 +322,18 @@ impl Value {
                                 term_stack.push(Value::String(atom.as_str().to_string()));
                             }
                         },
+                        Value::List(l) if l.is_empty() => {
+                            term_stack.push(Value::String(char_iter.collect()));
+                        }
                         Value::List(l) => {
-                            let mut list: Vec<Value> = atom
-                                .as_str()
-                                .to_string()
-                                .chars()
+                            let mut list: Vec<Value> = char_iter
                                 .map(|x| Value::Atom(x.to_string()))
                                 .collect();
                             list.extend(l.into_iter());
                             term_stack.push(Value::List(list));
                         },
                         _ => {
-                            let mut list: Vec<Value> = atom
-                                .as_str()
-                                .to_string()
-                                .chars()
+                            let mut list: Vec<Value> = char_iter
                                 .map(|x| Value::Atom(x.to_string()))
                                 .collect();
 
@@ -374,19 +359,6 @@ impl Value {
                         }
                     }
                 }
-                // 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),
-                    ));
-                }
-                */
                 _ => {
                 }
             );
index 6a6ba96d8d4fc489d1fef9ed5e8576aa013a1ae4..6176e73a027c8b92a9048fcaa9d04798d4dc3338 100644 (file)
@@ -1,78 +1,27 @@
 use crate::atom_table::*;
-use crate::parser::ast::*;
 
 use crate::machine::heap::*;
 use crate::machine::machine_errors::CycleSearchResult;
 use crate::machine::system_calls::BrentAlgState;
 use crate::types::*;
 
-use std::cmp::Ordering;
 use std::ops::Deref;
 use std::str;
 
-#[derive(Copy, Clone, Debug)]
-pub struct PartialString(Atom);
-
-fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
-    let mut terminator_idx = 0;
-
-    for c in iter {
-        if c == '\u{0}' && terminator_idx != 0 {
-            return terminator_idx;
-        }
-
-        terminator_idx += c.len_utf8();
-    }
-
-    terminator_idx
-}
-
-impl From<Atom> for PartialString {
-    #[inline]
-    fn from(buf: Atom) -> PartialString {
-        PartialString(buf)
-    }
-}
-
-impl From<PartialString> for Atom {
-    #[inline]
-    fn from(val: PartialString) -> Self {
-        val.0
-    }
-}
-
-impl PartialString {
-    #[inline]
-    pub(super) fn new<'a>(src: &'a str, atom_tbl: &AtomTable) -> Option<(Self, &'a str)> {
-        let terminator_idx = scan_for_terminator(src.chars());
-        let pstr = PartialString(AtomTable::build_with(atom_tbl, &src[..terminator_idx]));
-        Some(if terminator_idx < src.as_bytes().len() {
-            (pstr, &src[terminator_idx + 1..])
-        } else {
-            (pstr, "")
-        })
-    }
-
-    #[inline(always)]
-    pub(crate) fn as_str_from(&self, n: usize) -> AtomString {
-        self.0.as_str().map(|str| &str[n..])
-    }
-}
-
 #[derive(Clone, Copy)]
 pub struct HeapPStrIter<'a> {
-    pub heap: &'a [HeapCellValue],
-    pub focus: HeapCellValue,
+    pub heap: &'a Heap,
+    // pub focus: HeapCellValue,
     orig_focus: usize,
     brent_st: BrentAlgState,
     stepper: fn(&mut HeapPStrIter<'a>) -> Option<PStrIteratee>,
 }
 
 #[derive(Debug, Clone, Copy)]
-pub struct PStrPrefixCmpResult {
-    pub focus: usize,
-    pub offset: usize,
-    pub prefix_len: usize,
+pub enum PStrCmpResult<'a> {
+    ListMatch { list_loc: usize },
+    CompletePStrMatch { chars_matched: usize, pstr_loc: usize },
+    PartialPStrMatch { string: &'a str, var_loc: usize },
 }
 
 struct PStrIterStep {
@@ -80,15 +29,20 @@ struct PStrIterStep {
     next_hare: usize,
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PStrIteratee {
+    Char { heap_loc: usize, value: char },
+    PStrSlice { slice_loc: usize, slice_len: usize },
+}
+
 impl<'a> HeapPStrIter<'a> {
-    pub fn new(heap: &'a [HeapCellValue], h: usize) -> Self {
-        let value = heap[h];
+    pub fn new(heap: &'a Heap, orig_focus: usize) -> Self {
+        debug_assert!(heap[orig_focus].is_ref());
 
         Self {
             heap,
-            focus: value,
-            orig_focus: h,
-            brent_st: BrentAlgState::new(h),
+            orig_focus,
+            brent_st: BrentAlgState::new(orig_focus),
             stepper: HeapPStrIter::pre_cycle_discovery_stepper,
         }
     }
@@ -98,97 +52,83 @@ impl<'a> HeapPStrIter<'a> {
         self.brent_st.hare
     }
 
-    #[inline(always)]
-    pub fn at_string_terminator(&self) -> bool {
-        self.focus.is_string_terminator(self.heap)
-    }
+    pub fn compare_pstr_to_string<'b>(self, mut s: &'b str) -> Option<PStrCmpResult<'b>> {
+        let mut curr_hare = self.brent_st.hare;
 
-    #[inline(always)]
-    pub fn chars(mut self) -> PStrCharsIter<'a> {
-        let item = self.next();
-        PStrCharsIter { iter: self, item }
-    }
+        while !s.is_empty() {
+            read_heap_cell!(self.heap[curr_hare],
+                (HeapCellValueTag::PStrLoc, h) => {
+                    let t = self.heap.slice_to_str(h, self.heap.byte_len() - h);
 
-    pub fn compare_pstr_to_string(&mut self, s: &str) -> Option<PStrPrefixCmpResult> {
-        let mut result = PStrPrefixCmpResult {
-            focus: self.brent_st.hare,
-            offset: 0,
-            prefix_len: 0,
-        };
+                    let mut bytes_matched = 0;
+                    let mut chars_matched = 0;
 
-        let mut final_result = None;
+                    for (sc, tc) in s.chars().zip(t.chars()) {
+                        if sc != tc {
+                            if tc != '\u{0}' {
+                                return None;
+                            } else {
+                                break;
+                            }
+                        }
 
-        while let Some(PStrIterStep {
-            iteratee,
-            next_hare,
-        }) = self.step(self.brent_st.hare)
-        {
-            self.brent_st.hare = next_hare;
-            self.focus = self.heap[iteratee.focus()];
+                        bytes_matched += sc.len_utf8();
+                        chars_matched += 1;
+                    }
 
-            result.focus = iteratee.focus();
-            result.offset = iteratee.offset();
+                    s = &s[bytes_matched ..];
 
-            match iteratee {
-                PStrIteratee::Char(_, c1) => {
-                    if let Some(c2) = s[result.prefix_len..].chars().next() {
-                        if c1 != c2 {
-                            return None;
-                        } else {
-                            result.prefix_len += c1.len_utf8();
-                            result.offset += c1.len_utf8();
-                        }
+                    if s.is_empty() {
+                        return Some(PStrCmpResult::CompletePStrMatch { chars_matched, pstr_loc: h });
                     } else {
-                        final_result = Some(result);
-                        break;
+                        let next_hare = Heap::neighboring_cell_offset(h + bytes_matched);
+                        curr_hare = next_hare;
                     }
                 }
-                PStrIteratee::PStrSegment(_, pstr_atom, n) => {
-                    let pstr = PartialString::from(pstr_atom);
-                    let t = pstr.as_str_from(n);
-                    let s = &s[result.prefix_len..];
-
-                    if s.len() >= t.len() {
-                        if s.starts_with(&*t) {
-                            result.prefix_len += t.len();
-                            result.offset += t.len();
-                        } else {
-                            return None;
-                        }
-                    } else if t.starts_with(s) {
-                        result.prefix_len += s.len();
-                        result.offset += s.len();
-
-                        final_result = Some(result);
-                        break;
-                    } else {
-                        return None;
+                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+                    if h == curr_hare {
+                        return Some(PStrCmpResult::PartialPStrMatch { string: s, var_loc: h });
                     }
+
+                    curr_hare = h;
+                    continue;
                 }
-            }
+                _ => {
+                    match self.step(curr_hare).ok() {
+                        Some(PStrIterStep { iteratee, next_hare }) => {
+                            let value = if let PStrIteratee::Char { value, .. } = iteratee {
+                                value
+                            } else {
+                                unreachable!()
+                            };
 
-            if s.len() == result.prefix_len {
-                final_result = Some(result);
-                break;
-            }
-        }
+                            let c = s.chars().next().unwrap();
 
-        if let Some(result) = &final_result {
-            if self.at_string_terminator() {
-                self.focus = empty_list_as_cell!();
-                self.brent_st.hare = result.focus;
-            } else {
-                read_heap_cell!(self.heap[result.focus],
-                    (HeapCellValueTag::Lis | HeapCellValueTag::Str | HeapCellValueTag::PStr) => {
-                        self.focus = self.heap[self.brent_st.hare];
-                    }
-                    _ => {
+                            if c == value {
+                                s = &s[c.len_utf8() ..];
+
+                                if s.is_empty() {
+                                    return Some(
+                                        PStrCmpResult::ListMatch {
+                                            list_loc: next_hare,
+                                        }
+                                    );
+                                }
+
+                                curr_hare = next_hare;
+                            } else {
+                                return None;
+                            }
+                        }
+                        None => {
+                            return None;
+                        }
                     }
-                );
-            }
+                }
+            );
         }
 
-        Some(result)
+        None
     }
 
     fn walk_hare_to_cycle_end(&mut self) {
@@ -209,21 +149,23 @@ impl<'a> HeapPStrIter<'a> {
             self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare;
         }
 
-        self.focus = self.heap[orig_hare];
+        // self.focus = self.heap[orig_hare];
         self.brent_st.hare = orig_hare;
     }
 
     pub fn to_string_mut(&mut self) -> String {
         let mut buf = String::with_capacity(32);
 
-        for iteratee in self.by_ref() {
+        while let Some(iteratee) = self.next() {
             match iteratee {
-                PStrIteratee::Char(_, c) => {
+                PStrIteratee::Char { value: c, .. } => {
                     buf.push(c);
                 }
-                PStrIteratee::PStrSegment(_, pstr_atom, n) => {
-                    let pstr = PartialString::from(pstr_atom);
-                    buf += &*pstr.as_str_from(n);
+                PStrIteratee::PStrSlice {
+                    slice_loc,
+                    slice_len,
+                } => {
+                    buf += self.heap.slice_to_str(slice_loc, slice_len);
                 }
             }
         }
@@ -231,97 +173,18 @@ impl<'a> HeapPStrIter<'a> {
         buf
     }
 
-    #[inline]
-    pub fn is_continuable(&self) -> bool {
-        let mut focus = self.focus;
-
-        loop {
-            read_heap_cell!(focus,
-                (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
-                    return true;
-                }
-                (HeapCellValueTag::Atom, (name, arity)) => { // TODO: use Str here?
-                    return name == atom!(".") && arity == 2;
-                }
-                (HeapCellValueTag::Lis, h) => {
-                    let value = self.heap[h];
-                    let value = heap_bound_store(
-                        self.heap,
-                        heap_bound_deref(self.heap, value),
-                    );
-
-                    return read_heap_cell!(value,
-                        (HeapCellValueTag::Atom, (name, arity)) => {
-                            arity == 0 && name.as_char().is_some()
-                        }
-                        (HeapCellValueTag::Char) => {
-                            true
-                        }
-                        _ => {
-                            false
-                        }
-                    );
-                }
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                    if focus == self.heap[h] {
-                        return false;
-                    }
-
-                    focus = self.heap[h];
-                }
-                _ => {
-                    return false;
-                }
-            );
-        }
-    }
-
-    #[inline(always)]
-    pub fn cycle_detected(&self) -> bool {
-        self.stepper as usize == HeapPStrIter::post_cycle_discovery_stepper as usize
-    }
-
-    fn step(&self, mut curr_hare: usize) -> Option<PStrIterStep> {
+    // return the next step in the iteration or the updated curr_hare
+    // for the sake of pointing to the pstr tail
+    fn step(&self, mut curr_hare: usize) -> Result<PStrIterStep, usize> {
         loop {
             read_heap_cell!(self.heap[curr_hare],
-                (HeapCellValueTag::CStr, cstr_atom) => {
-                    return if self.focus == empty_list_as_cell!() {
-                        None
-                    } else {
-                        Some(PStrIterStep {
-                            iteratee: PStrIteratee::PStrSegment(curr_hare, cstr_atom, 0),
-                            next_hare: curr_hare,
-                        })
-                    }
-                }
                 (HeapCellValueTag::PStrLoc, h) => {
-                    curr_hare = h;
-                }
-                (HeapCellValueTag::PStr, pstr_atom) => {
-                    return Some(PStrIterStep {
-                        iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, 0),
-                        next_hare: curr_hare+1,
-                    });
-                }
-                (HeapCellValueTag::PStrOffset, pstr_offset) => {
-                    if self.focus == empty_list_as_cell!() {
-                        return None;
-                    }
-
-                    let pstr_atom = cell_as_atom!(self.heap[pstr_offset]);
-                    let n = cell_as_fixnum!(self.heap[curr_hare+1]).get_num() as usize;
+                    let (s, tail_loc) = self.heap.scan_slice_to_str(h);
 
-                    return if self.heap[pstr_offset].get_tag() == HeapCellValueTag::CStr {
-                        Some(PStrIterStep {
-                            iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n),
-                            next_hare: pstr_offset,
-                        })
-                    } else {
-                        Some(PStrIterStep {
-                            iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n),
-                            next_hare: pstr_offset+1,
-                        })
-                    };
+                    return Ok(PStrIterStep {
+                        iteratee: PStrIteratee::PStrSlice { slice_loc: h, slice_len: s.len() },
+                        next_hare: tail_loc,
+                    });
                 }
                 (HeapCellValueTag::Lis, h) => {
                     let value = heap_bound_store(
@@ -330,9 +193,9 @@ impl<'a> HeapPStrIter<'a> {
                     );
 
                     return value.as_char().map(|c| PStrIterStep {
-                        iteratee: PStrIteratee::Char(curr_hare, c),
+                        iteratee: PStrIteratee::Char { heap_loc: curr_hare, value: c },
                         next_hare: h+1,
-                    });
+                    }).ok_or(curr_hare)
                 }
                 (HeapCellValueTag::Str, s) => {
                     let (name, arity) = cell_as_atom_cell!(self.heap[s])
@@ -345,26 +208,26 @@ impl<'a> HeapPStrIter<'a> {
                         );
 
                         value.as_char().map(|c| PStrIterStep {
-                            iteratee: PStrIteratee::Char(curr_hare, c),
+                            iteratee: PStrIteratee::Char { heap_loc: curr_hare, value: c },
                             next_hare: s+2,
-                        })
+                        }).ok_or(curr_hare)
                     } else {
-                        None
+                        Err(curr_hare)
                     };
                 }
                 (HeapCellValueTag::Atom, (_name, arity)) => {
                     debug_assert!(arity == 0);
-                    return None;
+                    return Err(curr_hare);
                 }
                 (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
                     if h == curr_hare {
-                        return None;
+                        return Err(curr_hare);
                     }
 
                     curr_hare = h;
                 }
                 _ => {
-                    return None;
+                    return Err(curr_hare);
                 }
             );
         }
@@ -375,30 +238,22 @@ impl<'a> HeapPStrIter<'a> {
             iteratee,
             next_hare,
         } = match self.step(self.brent_st.hare) {
-            Some(results) => results,
-            None => {
+            Ok(results) => results,
+            Err(next_hare) => {
+                self.brent_st.hare = next_hare;
                 return None;
             }
         };
 
-        self.focus = self.heap[iteratee.focus()];
-
-        if self.at_string_terminator() {
-            self.focus = empty_list_as_cell!();
-            self.brent_st.hare = iteratee.focus();
-
-            return Some(iteratee);
-        }
-
         match self.brent_st.step(next_hare) {
             Some(cycle_result) => {
-                debug_assert!(matches!(cycle_result, CycleSearchResult::Cyclic(..)));
+                debug_assert!(matches!(cycle_result, CycleSearchResult::Cyclic { .. }));
 
                 self.walk_hare_to_cycle_end();
                 self.stepper = HeapPStrIter::post_cycle_discovery_stepper;
             }
             None => {
-                self.focus = self.heap[next_hare];
+                // self.focus = self.heap[next_hare];
             }
         }
 
@@ -414,40 +269,21 @@ impl<'a> HeapPStrIter<'a> {
             iteratee,
             next_hare,
         } = match self.step(self.brent_st.hare) {
-            Some(results) => results,
-            None => {
+            Ok(results) => results,
+            Err(next_hare) => {
+                self.brent_st.hare = next_hare;
                 return None;
             }
         };
 
-        self.focus = self.heap[next_hare];
+        // self.focus = self.heap[next_hare];
         self.brent_st.hare = next_hare;
 
         Some(iteratee)
     }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum PStrIteratee {
-    Char(usize, char),
-    PStrSegment(usize, Atom, usize),
-}
-
-impl PStrIteratee {
-    #[inline]
-    fn offset(&self) -> usize {
-        match self {
-            PStrIteratee::Char(_, _) => 0,
-            PStrIteratee::PStrSegment(_, _, n) => *n,
-        }
-    }
 
-    #[inline]
-    fn focus(&self) -> usize {
-        match self {
-            PStrIteratee::Char(focus, _) => *focus,
-            PStrIteratee::PStrSegment(focus, _, _) => *focus,
-        }
+    pub(crate) fn is_cyclic(&self) -> bool {
+        self.stepper as usize == Self::post_cycle_discovery_stepper as usize
     }
 }
 
@@ -465,24 +301,6 @@ pub struct PStrCharsIter<'a> {
     pub item: Option<PStrIteratee>,
 }
 
-impl<'a> PStrCharsIter<'a> {
-    pub fn peek(&self) -> Option<char> {
-        if let Some(iteratee) = self.item {
-            match iteratee {
-                PStrIteratee::Char(_, c) => {
-                    return Some(c);
-                }
-                PStrIteratee::PStrSegment(_, pstr_atom, n) => {
-                    let pstr = PartialString::from(pstr_atom);
-                    return pstr.as_str_from(n).chars().next();
-                }
-            }
-        }
-
-        None
-    }
-}
-
 impl<'a> Deref for PStrCharsIter<'a> {
     type Target = HeapPStrIter<'a>;
 
@@ -497,18 +315,19 @@ impl<'a> Iterator for PStrCharsIter<'a> {
     fn next(&mut self) -> Option<Self::Item> {
         while let Some(item) = self.item {
             match item {
-                PStrIteratee::Char(_, c) => {
+                PStrIteratee::Char { value, .. } => {
                     self.item = self.iter.next();
-                    return Some(c);
+                    return Some(value);
                 }
-                PStrIteratee::PStrSegment(f1, pstr_atom, n) => {
-                    let pstr = PartialString::from(pstr_atom);
+                PStrIteratee::PStrSlice { slice_loc, slice_len } => {
+                    let s = self.iter.heap.slice_to_str(slice_loc, slice_len);
 
-                    match pstr.as_str_from(n).chars().next() {
+                    match s.chars().next() {
                         Some(c) => {
-                            self.item =
-                                Some(PStrIteratee::PStrSegment(f1, pstr_atom, n + c.len_utf8()));
-
+                            self.item = Some(PStrIteratee::PStrSlice {
+                                slice_loc: slice_loc + c.len_utf8(),
+                                slice_len: slice_len - c.len_utf8(),
+                            });
                             return Some(c);
                         }
                         None => {
@@ -523,272 +342,6 @@ impl<'a> Iterator for PStrCharsIter<'a> {
     }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum PStrCmpResult {
-    Ordered(Ordering),
-    FirstIterContinuable(PStrIteratee),
-    SecondIterContinuable(PStrIteratee),
-    Unordered,
-}
-
-impl PStrCmpResult {
-    #[inline]
-    pub fn is_second_iter(&self) -> bool {
-        matches!(self, PStrCmpResult::SecondIterContinuable(_))
-    }
-}
-
-#[inline]
-pub fn compare_pstr_prefixes<'a>(
-    i1: &mut HeapPStrIter<'a>,
-    i2: &mut HeapPStrIter<'a>,
-) -> PStrCmpResult {
-    #[inline(always)]
-    fn step(iter: &mut HeapPStrIter, hare: usize) -> Option<PStrIterStep> {
-        let result = iter.step(hare);
-        iter.focus = iter.heap[hare];
-
-        if iter.focus.is_string_terminator(iter.heap) {
-            iter.focus = empty_list_as_cell!();
-        }
-
-        result
-    }
-
-    #[inline(always)]
-    fn cycle_detection_step(i1: &mut HeapPStrIter, i2: &HeapPStrIter, step: &PStrIterStep) -> bool {
-        if i1.cycle_detected() {
-            i1.brent_st.hare = step.next_hare;
-            i2.cycle_detected()
-        } else if i1.brent_st.step(step.next_hare).is_some() {
-            i1.stepper = HeapPStrIter::post_cycle_discovery_stepper;
-            i2.cycle_detected()
-        } else {
-            false
-        }
-    }
-
-    let mut r1 = step(i1, i1.brent_st.hare);
-    let mut r2 = step(i2, i2.brent_st.hare);
-
-    loop {
-        if let Some(step_1) = r1.as_mut() {
-            if let Some(step_2) = r2.as_mut() {
-                match (step_1.iteratee, step_2.iteratee) {
-                    (PStrIteratee::Char(_, c1), PStrIteratee::Char(_, c2)) => {
-                        if c1 != c2 {
-                            return PStrCmpResult::Ordered(c1.cmp(&c2));
-                        }
-
-                        cycle_detection_step(i1, i2, step_1);
-                        let both_cyclic = cycle_detection_step(i2, i1, step_2);
-
-                        r1 = step(i1, i1.brent_st.hare);
-                        r2 = step(i2, i2.brent_st.hare);
-
-                        if !both_cyclic {
-                            continue;
-                        }
-                    }
-                    (PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => {
-                        let pstr = PartialString::from(pstr_atom);
-
-                        if let Some(c2) = pstr.as_str_from(n).chars().next() {
-                            if c1 != c2 {
-                                return PStrCmpResult::Ordered(c1.cmp(&c2));
-                            }
-
-                            let n1 = n + c2.len_utf8();
-
-                            if n1 < pstr_atom.len() {
-                                step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1);
-
-                                let c1_result = cycle_detection_step(i1, i2, step_1);
-                                r1 = step(i1, i1.brent_st.hare);
-
-                                if !c1_result {
-                                    continue;
-                                }
-                            } else {
-                                cycle_detection_step(i1, i2, step_1);
-                                let both_cyclic = cycle_detection_step(i2, i1, step_2);
-
-                                r1 = step(i1, i1.brent_st.hare);
-                                r2 = step(i2, i2.brent_st.hare);
-
-                                if !both_cyclic {
-                                    continue;
-                                }
-                            }
-                        } else {
-                            let c2_result = cycle_detection_step(i2, i1, step_2);
-                            r2 = step(i2, i2.brent_st.hare);
-
-                            if !c2_result {
-                                continue;
-                            }
-                        }
-                    }
-                    (PStrIteratee::PStrSegment(f1, pstr_atom, n), PStrIteratee::Char(_, c2)) => {
-                        let pstr = PartialString::from(pstr_atom);
-
-                        if let Some(c1) = pstr.as_str_from(n).chars().next() {
-                            if c1 != c2 {
-                                return PStrCmpResult::Ordered(c1.cmp(&c2));
-                            }
-
-                            let n1 = n + c1.len_utf8();
-
-                            if n1 < pstr_atom.len() {
-                                step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1);
-
-                                let c2_result = cycle_detection_step(i2, i1, step_2);
-                                r2 = step(i2, step_2.next_hare);
-
-                                if !c2_result {
-                                    continue;
-                                }
-                            } else {
-                                cycle_detection_step(i1, i2, step_1);
-                                let both_cyclic = cycle_detection_step(i2, i1, step_2);
-
-                                r1 = step(i1, i1.brent_st.hare);
-                                r2 = step(i2, i2.brent_st.hare);
-
-                                if !both_cyclic {
-                                    continue;
-                                }
-                            }
-                        } else {
-                            let c1_result = cycle_detection_step(i1, i2, step_1);
-                            r1 = step(i1, i1.brent_st.hare);
-
-                            if !c1_result {
-                                continue;
-                            }
-                        }
-                    }
-                    (
-                        PStrIteratee::PStrSegment(f1, pstr1_atom, n1),
-                        PStrIteratee::PStrSegment(f2, pstr2_atom, n2),
-                    ) => {
-                        if pstr1_atom == pstr2_atom && n1 == n2 {
-                            cycle_detection_step(i1, i2, step_1);
-                            let both_cyclic = cycle_detection_step(i2, i1, step_2);
-
-                            r1 = step(i1, i1.brent_st.hare);
-                            r2 = step(i2, i2.brent_st.hare);
-
-                            if !both_cyclic {
-                                continue;
-                            }
-
-                            break;
-                        }
-
-                        let pstr1 = PartialString::from(pstr1_atom);
-                        let pstr2 = PartialString::from(pstr2_atom);
-
-                        let str1 = pstr1.as_str_from(n1);
-                        let str2 = pstr2.as_str_from(n2);
-
-                        match str1.len().cmp(&str2.len()) {
-                            Ordering::Equal if *str1 == *str2 => {
-                                cycle_detection_step(i1, i2, step_1);
-                                let both_cyclic = cycle_detection_step(i2, i1, step_2);
-
-                                r1 = step(i1, i1.brent_st.hare);
-                                r2 = step(i2, i2.brent_st.hare);
-
-                                if !both_cyclic {
-                                    continue;
-                                }
-                            }
-                            Ordering::Less if str2.starts_with(&*str1) => {
-                                step_2.iteratee =
-                                    PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len());
-                                let c1_result = cycle_detection_step(i1, i2, step_1);
-                                r1 = step(i1, i1.brent_st.hare);
-
-                                if !c1_result {
-                                    continue;
-                                }
-                            }
-                            Ordering::Greater if str1.starts_with(&*str2) => {
-                                step_1.iteratee =
-                                    PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len());
-                                let c2_result = cycle_detection_step(i2, i1, step_2);
-                                r2 = step(i2, i2.brent_st.hare);
-
-                                if !c2_result {
-                                    continue;
-                                }
-                            }
-                            _ => {
-                                return PStrCmpResult::Ordered(str1.cmp(&*str2));
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        break;
-    }
-
-    // to have a cyclic term, the cell at i1.focus must be:
-    //
-    // 1) 'continuable' as a cell in a string traversal, and,
-    // 2) matchable by compare_pstr_prefixes to the cell at i2.focus.
-    //
-    // If both cells are continuable they must have been encountered
-    // and thus matched by the compare_pstr_prefixes loop previously,
-    // so here it suffices to check if they are both continuable.
-
-    let r1_at_end = r1.is_none();
-    let r2_at_end = r2.is_none();
-
-    if r1_at_end && r2_at_end {
-        if i1.focus == i2.focus {
-            PStrCmpResult::Ordered(Ordering::Equal)
-        } else {
-            PStrCmpResult::Unordered
-        }
-    } else if r1_at_end {
-        if i1.focus == empty_list_as_cell!() {
-            PStrCmpResult::Ordered(Ordering::Less)
-        } else {
-            let r2_step = r2.unwrap();
-
-            // advance i2 to the next character so the same character
-            // isn't repeated
-            if matches!(r2_step.iteratee, PStrIteratee::Char(..)) {
-                cycle_detection_step(i2, i1, &r2_step);
-            }
-
-            PStrCmpResult::SecondIterContinuable(r2_step.iteratee)
-        }
-    } else if r2_at_end {
-        if i2.focus == empty_list_as_cell!() {
-            PStrCmpResult::Ordered(Ordering::Greater)
-        } else {
-            let r1_step = r1.unwrap();
-
-            // advance i1 to the next character so the same character
-            // isn't repeated
-            if matches!(r1_step.iteratee, PStrIteratee::Char(..)) {
-                cycle_detection_step(i1, i2, &r1_step);
-            }
-
-            PStrCmpResult::FirstIterContinuable(r1_step.iteratee)
-        }
-    } else if i1.is_continuable() && i2.is_continuable() {
-        PStrCmpResult::Ordered(Ordering::Equal)
-    } else {
-        PStrCmpResult::Unordered
-    }
-}
-
 #[cfg(test)]
 mod test {
     use super::*;
@@ -799,233 +352,158 @@ mod test {
     fn pstr_iter_tests() {
         let mut wam = MockWAM::new();
 
-        let pstr_var_cell =
-            put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
+        let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap();
+        wam.machine_st.heap.push_cell(empty_list_as_cell!()).unwrap();
 
-        let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
+        // not overwriting anything! 0 is an interstitial cell
+        // reserved for use by the runtime
+        wam.machine_st.heap[0] = pstr_cell;
 
         {
             let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
 
             assert_eq!(
                 iter.next(),
-                Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0))
+                Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }),
             );
             assert_eq!(iter.next(), None);
-
-            assert!(!iter.at_string_terminator());
+            assert!(!iter.is_cyclic());
         }
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.push(pstr_loc_as_cell!(2));
+        assert_eq!(wam.machine_st.heap[2], empty_list_as_cell!());
+
+        wam.machine_st.heap[2] = pstr_loc_as_cell!(heap_index!(3));
 
-        let pstr_second_var_cell =
-            put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
+        wam.machine_st.allocate_pstr("def").unwrap();
+        let h = wam.machine_st.heap.cell_len();
 
-        let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+        wam.machine_st.heap.push_cell(heap_loc_as_cell!(h)).unwrap();
 
         {
             let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
 
             assert_eq!(
                 iter.next(),
-                Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0))
+                Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() })
             );
             assert_eq!(
                 iter.next(),
-                Some(PStrIteratee::PStrSegment(
-                    2,
-                    cell_as_atom!(pstr_second_cell),
-                    0
-                ))
+                Some(PStrIteratee::PStrSlice {
+                    slice_loc: heap_index!(3),
+                    slice_len: "def".len(),
+                })
             );
 
             assert_eq!(iter.next(), None);
-            assert!(!iter.at_string_terminator());
+            assert!(!iter.is_cyclic());
         }
 
-        wam.machine_st.heap.pop();
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        assert_eq!(wam.machine_st.heap[h], heap_loc_as_cell!(h));
+
+        wam.machine_st.heap[h] = empty_list_as_cell!();
 
         {
             let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
 
             assert_eq!(
                 iter.next(),
-                Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0))
+                Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() })
             );
             assert_eq!(
                 iter.next(),
-                Some(PStrIteratee::PStrSegment(
-                    2,
-                    cell_as_atom!(pstr_second_cell),
-                    0
-                ))
+                Some(PStrIteratee::PStrSlice {
+                    slice_loc: heap_index!(3),
+                    slice_len: "def".len(),
+                })
             );
 
             assert_eq!(iter.next(), None);
-            assert!(iter.at_string_terminator());
+            assert!(!iter.is_cyclic());
         }
 
-        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(0)));
+        wam.machine_st.heap[h] = pstr_loc_as_cell!(heap_index!(3));
 
         {
             let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0);
-
             for _ in iter.by_ref() {}
-
-            assert!(!iter.at_string_terminator());
-        }
-
-        {
-            let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0);
-            let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 0);
-
-            assert_eq!(
-                compare_pstr_prefixes(&mut iter1, &mut iter2),
-                PStrCmpResult::Ordered(Ordering::Equal)
-            );
-        }
-
-        {
-            let second_h = wam.machine_st.heap.len();
-
-            // construct a structurally similar but different cyclic partial string
-            // matching the one beginning at wam.machine_st.heap[0].
-
-            put_partial_string(&mut wam.machine_st.heap, "ab", &wam.machine_st.atom_tbl);
-
-            wam.machine_st.heap.pop();
-
-            wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 2));
-
-            put_partial_string(&mut wam.machine_st.heap, "c ", &wam.machine_st.atom_tbl);
-
-            wam.machine_st.heap.pop();
-
-            wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 4));
-
-            wam.machine_st.heap.push(pstr_second_cell);
-            wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 6));
-
-            wam.machine_st.heap.push(pstr_offset_as_cell!(second_h));
-            wam.machine_st
-                .heap
-                .push(fixnum_as_cell!(Fixnum::build_with(0)));
-
-            let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0);
-            let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, second_h);
-
-            assert_eq!(
-                compare_pstr_prefixes(&mut iter1, &mut iter2),
-                PStrCmpResult::Ordered(Ordering::Equal)
-            );
-        }
-
-        wam.machine_st.heap.clear();
-
-        put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
-
-        let pstr_cell = wam.machine_st.heap[0];
-
-        wam.machine_st.heap[1] = list_loc_as_cell!(2);
-
-        wam.machine_st.heap.push(char_as_cell!('a'));
-        wam.machine_st.heap.push(list_loc_as_cell!(4));
-        wam.machine_st.heap.push(char_as_cell!('b'));
-        wam.machine_st.heap.push(empty_list_as_cell!());
-
-        wam.machine_st.heap.push(pstr_cell);
-        wam.machine_st.heap.push(heap_loc_as_cell!(7));
-
-        {
-            let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0);
-            let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 6);
-
-            assert_eq!(
-                compare_pstr_prefixes(&mut iter1, &mut iter2),
-                PStrCmpResult::FirstIterContinuable(PStrIteratee::Char(1, 'a')),
-            );
-
-            assert_eq!(iter2.focus, heap_loc_as_cell!(7));
+            assert!(iter.is_cyclic());
         }
 
         // test "abc" = [X,Y,Z].
 
         wam.machine_st.heap.clear();
 
-        let cstr_var_cell =
-            put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
-
-        wam.machine_st.heap.push(list_loc_as_cell!(2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
+        let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap();
+        let start = wam.machine_st.heap.cell_len();
 
-        wam.machine_st.heap.push(list_loc_as_cell!(4));
-        wam.machine_st.heap.push(heap_loc_as_cell!(4));
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
-        wam.machine_st.heap.push(list_loc_as_cell!(6));
-        wam.machine_st.heap.push(heap_loc_as_cell!(6));
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1 + start));
+            section.push_cell(heap_loc_as_cell!(1 + start));
 
-        wam.machine_st.heap.push(empty_list_as_cell!());
+            section.push_cell(list_loc_as_cell!(3 + start));
+            section.push_cell(heap_loc_as_cell!(3 + start));
 
-        unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1));
+            section.push_cell(list_loc_as_cell!(5 + start));
+            section.push_cell(heap_loc_as_cell!(5 + start));
 
-        assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),);
+            section.push_cell(empty_list_as_cell!());
+        });
 
-        assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),);
+        unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(2));
 
-        assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),);
+        assert_eq!(wam.machine_st.heap[1 + start], char_as_cell!('a'));
+        assert_eq!(wam.machine_st.heap[3 + start], char_as_cell!('b'));
+        assert_eq!(wam.machine_st.heap[5 + start], char_as_cell!('c'));
 
         // test "abc" = [X,Y,Z|D].
 
         wam.machine_st.heap.clear();
 
-        let cstr_var_cell =
-            put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
-
-        wam.machine_st.heap.push(list_loc_as_cell!(2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(2)); // X
-
-        wam.machine_st.heap.push(list_loc_as_cell!(4));
-        wam.machine_st.heap.push(heap_loc_as_cell!(4)); // Y
+        let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap();
+        let start = wam.machine_st.heap.cell_len();
 
-        wam.machine_st.heap.push(list_loc_as_cell!(6));
-        wam.machine_st.heap.push(heap_loc_as_cell!(6)); // Z
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
-        wam.machine_st.heap.push(heap_loc_as_cell!(7)); // D
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1 + start));
+            section.push_cell(heap_loc_as_cell!(1 + start)); // X
 
-        unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1));
+            section.push_cell(list_loc_as_cell!(3 + start));
+            section.push_cell(heap_loc_as_cell!(3 + start)); // Y
 
-        assert!(!wam.machine_st.fail);
+            section.push_cell(list_loc_as_cell!(5 + start));
+            section.push_cell(heap_loc_as_cell!(5 + start)); // Z
 
-        assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),);
+            section.push_cell(heap_loc_as_cell!(6 + start)); // D
+        });
 
-        assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),);
+        unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(2));
 
-        assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),);
+        assert!(!wam.machine_st.fail);
 
-        assert_eq!(wam.machine_st.heap[7], empty_list_as_cell!(),);
+        assert_eq!(wam.machine_st.heap[3], char_as_cell!('a'),);
+        assert_eq!(wam.machine_st.heap[5], char_as_cell!('b'),);
+        assert_eq!(wam.machine_st.heap[7], char_as_cell!('c'),);
+        assert_eq!(wam.machine_st.heap[8], empty_list_as_cell!(),);
 
         // test "d" = [d].
 
         wam.machine_st.heap.clear();
 
-        let cstr_var_cell =
-            put_complete_string(&mut wam.machine_st.heap, "d", &wam.machine_st.atom_tbl);
+        let pstr_cell = wam.machine_st.allocate_cstr("d").unwrap();
+        let start = wam.machine_st.heap.cell_len();
+
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
-        wam.machine_st.heap.push(list_loc_as_cell!(2));
-        wam.machine_st.heap.push(char_as_cell!('d'));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1 + start));
+            section.push_cell(char_as_cell!('d'));
+            section.push_cell(empty_list_as_cell!());
+        });
 
-        unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1));
+        unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(start));
 
         assert!(!wam.machine_st.fail);
 
@@ -1033,71 +511,83 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        let cstr_var_cell =
-            put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
+        let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap();
+        let start = wam.machine_st.heap.cell_len();
 
-        wam.machine_st.heap.push(list_loc_as_cell!(2));
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
-        wam.machine_st.heap.push(list_loc_as_cell!(4));
-        wam.machine_st.heap.push(char_as_cell!('b'));
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(1 + start));
+            section.push_cell(heap_loc_as_cell!(1 + start));
 
-        wam.machine_st.heap.push(list_loc_as_cell!(6));
-        wam.machine_st.heap.push(heap_loc_as_cell!(6));
+            section.push_cell(list_loc_as_cell!(3 + start));
+            section.push_cell(char_as_cell!('b'));
 
-        wam.machine_st.heap.push(empty_list_as_cell!());
+            section.push_cell(list_loc_as_cell!(5 + start));
+            section.push_cell(heap_loc_as_cell!(5 + start));
 
-        unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1));
-
-        assert!(!wam.machine_st.fail);
+            section.push_cell(empty_list_as_cell!());
+        });
 
-        assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),);
+        unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(start));
 
-        assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),);
+        assert!(!wam.machine_st.fail);
 
-        assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),);
+        assert_eq!(wam.machine_st.heap[1 + start], char_as_cell!('a'));
+        assert_eq!(wam.machine_st.heap[3 + start], char_as_cell!('b'));
+        assert_eq!(wam.machine_st.heap[5 + start], char_as_cell!('c'));
 
         // test "abcdef" = [a,b,c|X].
 
         wam.machine_st.heap.clear();
 
-        put_complete_string(&mut wam.machine_st.heap, "abcdef", &wam.machine_st.atom_tbl);
+        let pstr_cell = wam.machine_st.allocate_cstr("abcdef").unwrap();
+        let start = wam.machine_st.heap.cell_len();
 
-        wam.machine_st.heap.push(pstr_as_cell!(atom!("abc")));
-        wam.machine_st.heap.push(heap_loc_as_cell!(2));
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
-        unify!(wam.machine_st, heap_loc_as_cell!(0), pstr_loc_as_cell!(1));
+        writer.write_with(|section| {
+            section.push_pstr("abc");
+            let h = section.cell_len(); // h == 3
+            section.push_cell(heap_loc_as_cell!(h));
+        });
 
-        print_heap_terms(wam.machine_st.heap.iter(), 0);
+        unify!(wam.machine_st, pstr_cell, pstr_loc_as_cell!(heap_index!(start)));
 
         assert!(!wam.machine_st.fail);
 
-        assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(5));
-        assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(1));
-        assert_eq!(wam.machine_st.heap[4], atom_as_cstr_cell!(atom!("abcdef")));
-        assert_eq!(wam.machine_st.heap[5], pstr_offset_as_cell!(4));
         assert_eq!(
-            wam.machine_st.heap[6],
-            fixnum_as_cell!(Fixnum::build_with("abc".len() as i64))
+            wam.machine_st.heap.slice_to_str(0, "abcdef".len()),
+            "abcdef"
+        );
+        assert_eq!(
+            wam.machine_st.heap.slice_to_str(heap_index!(start), "abc".len()),
+            "abc"
+        );
+        assert_eq!(
+            wam.machine_st.heap[3],
+            pstr_loc_as_cell!(heap_index!(0) + 3)
         );
 
         // test iteration on X = [b,c,b,c,b,c,b,c|...] as an offset.
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(pstr_as_cell!(atom!("abc")));
-        wam.machine_st.heap.push(pstr_loc_as_cell!(2));
-        wam.machine_st.heap.push(pstr_offset_as_cell!(0));
-        wam.machine_st
-            .heap
-            .push(fixnum_as_cell!(Fixnum::build_with(1)));
+        wam.machine_st.allocate_cstr("abc").unwrap();
+        let start = wam.machine_st.heap.cell_len();
+
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(pstr_loc_as_cell!('a'.len_utf8()));
+        });
 
         {
-            let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 2);
+            let mut iter = HeapPStrIter::new(&wam.machine_st.heap, start);
 
             assert_eq!(
                 iter.next(),
-                Some(PStrIteratee::PStrSegment(2, atom!("abc"), 1))
+                Some(PStrIteratee::PStrSlice { slice_loc: 'a'.len_utf8(), slice_len: "bc".len() })
             );
 
             for _ in iter {}
@@ -1107,13 +597,19 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a ")));
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(char_as_cell!(' '));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        wam.machine_st.allocate_cstr("a ").unwrap();
+        let start = wam.machine_st.heap.cell_len();
+
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(heap_loc_as_cell!(start));
+            section.push_cell(list_loc_as_cell!(2 + start));
+            section.push_cell(char_as_cell!(' '));
+            section.push_cell(empty_list_as_cell!());
+        });
 
-        unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
+        unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0));
 
         assert!(!wam.machine_st.fail);
 
@@ -1121,98 +617,143 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a")));
-        wam.machine_st.heap.push(char_as_cell!(' '));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        wam.machine_st.allocate_cstr(" a").unwrap();
+        let start = wam.machine_st.heap.cell_len();
 
-        unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
+        writer.write_with(|section| {
+            section.push_cell(char_as_cell!(' '));
+            section.push_cell(list_loc_as_cell!(2 + start));
+            section.push_cell(heap_loc_as_cell!(2 + start));
+            section.push_cell(empty_list_as_cell!());
+        });
+
+        unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0));
+
+        assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a'));
         assert!(!wam.machine_st.fail);
 
         // #2293, test3.
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a b")));
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(char_as_cell!(' '));
-        wam.machine_st.heap.push(list_loc_as_cell!(5));
-        wam.machine_st.heap.push(heap_loc_as_cell!(5));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        wam.machine_st.allocate_cstr("a b").unwrap();
+        let start = wam.machine_st.heap.cell_len();
+
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(heap_loc_as_cell!(start));
+            section.push_cell(list_loc_as_cell!(2 + start));
+            section.push_cell(char_as_cell!(' '));
+            section.push_cell(list_loc_as_cell!(4 + start));
+            section.push_cell(heap_loc_as_cell!(4 + start));
+            section.push_cell(empty_list_as_cell!());
+        });
 
-        unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
+        unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0));
 
+        assert_eq!(wam.machine_st.heap[start], char_as_cell!('a'));
+        assert_eq!(wam.machine_st.heap[4 + start], char_as_cell!('b'));
         assert!(!wam.machine_st.fail);
 
         // #2293, test4.
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a ")));
-        wam.machine_st.heap.push(char_as_cell!(' '));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
-        wam.machine_st.heap.push(list_loc_as_cell!(5));
-        wam.machine_st.heap.push(char_as_cell!(' '));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        wam.machine_st.allocate_cstr(" a ").unwrap();
+        let start = wam.machine_st.heap.cell_len();
 
-        unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
+        writer.write_with(|section| {
+            section.push_cell(char_as_cell!(' '));
+            section.push_cell(list_loc_as_cell!(2 + start));
+            section.push_cell(heap_loc_as_cell!(2 + start));
+            section.push_cell(list_loc_as_cell!(4 + start));
+            section.push_cell(char_as_cell!(' '));
+            section.push_cell(empty_list_as_cell!());
+        });
+
+        unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0));
+
+        assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a'));
         assert!(!wam.machine_st.fail);
 
         // #2293, test5.
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a bc")));
-        wam.machine_st.heap.push(char_as_cell!(' '));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
-        wam.machine_st.heap.push(list_loc_as_cell!(5));
-        wam.machine_st.heap.push(char_as_cell!(' '));
-        wam.machine_st.heap.push(heap_loc_as_cell!(6));
+        wam.machine_st.allocate_cstr(" a bc").unwrap();
+        let start = wam.machine_st.heap.cell_len();
+
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
-        unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
+        writer.write_with(|section| {
+            section.push_cell(char_as_cell!(' '));
+            section.push_cell(list_loc_as_cell!(2 + start));
+            section.push_cell(heap_loc_as_cell!(2 + start));
+            section.push_cell(list_loc_as_cell!(4 + start));
+            section.push_cell(char_as_cell!(' '));
+            section.push_cell(heap_loc_as_cell!(5 + start));
+        });
 
+        unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0));
+
+        assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a'));
+        assert_eq!(wam.machine_st.heap[5 + start], pstr_loc_as_cell!(heap_index!(0) + 3));
         assert!(!wam.machine_st.fail);
 
         // #2293, test6.
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abc")));
-        wam.machine_st.heap.push(heap_loc_as_cell!(1));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(char_as_cell!('b'));
-        wam.machine_st.heap.push(list_loc_as_cell!(5));
-        wam.machine_st.heap.push(heap_loc_as_cell!(5));
-        wam.machine_st.heap.push(empty_list_as_cell!());
+        wam.machine_st.allocate_cstr("abc").unwrap();
+        let start = wam.machine_st.heap.cell_len();
+
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
 
-        unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
+        writer.write_with(|section| {
+            section.push_cell(heap_loc_as_cell!(start));
+            section.push_cell(list_loc_as_cell!(2 + start));
+            section.push_cell(char_as_cell!('b'));
+            section.push_cell(list_loc_as_cell!(4 + start));
+            section.push_cell(heap_loc_as_cell!(4 + start));
+            section.push_cell(empty_list_as_cell!());
+        });
 
+        unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0));
+
+        assert_eq!(wam.machine_st.heap[start], char_as_cell!('a'));
+        assert_eq!(wam.machine_st.heap[4 + start], char_as_cell!('c'));
         assert!(!wam.machine_st.fail);
 
         // #2293, test7.
 
         wam.machine_st.heap.clear();
-
-        wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abcde")));
-        wam.machine_st.heap.push(char_as_cell!('a'));
-        wam.machine_st.heap.push(list_loc_as_cell!(3));
-        wam.machine_st.heap.push(heap_loc_as_cell!(3));
-        wam.machine_st.heap.push(list_loc_as_cell!(5));
-        wam.machine_st.heap.push(char_as_cell!('c'));
-        wam.machine_st.heap.push(list_loc_as_cell!(7));
-        wam.machine_st.heap.push(heap_loc_as_cell!(7));
-        wam.machine_st.heap.push(list_loc_as_cell!(9));
-        wam.machine_st.heap.push(char_as_cell!('e'));
-        wam.machine_st.heap.push(empty_list_as_cell!());
-
-        unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0));
-
+        wam.machine_st.allocate_cstr("abcde").unwrap();
+
+        let start = wam.machine_st.heap.cell_len();
+        let mut writer = wam.machine_st.heap.reserve(16).unwrap();
+
+        writer.write_with(|section| {
+            section.push_cell(char_as_cell!('a'));
+            section.push_cell(list_loc_as_cell!(2 + start));
+            section.push_cell(heap_loc_as_cell!(2 + start));
+            section.push_cell(list_loc_as_cell!(4 + start));
+            section.push_cell(char_as_cell!('c'));
+            section.push_cell(list_loc_as_cell!(6 + start));
+            section.push_cell(heap_loc_as_cell!(6 + start));
+            section.push_cell(list_loc_as_cell!(8 + start));
+            section.push_cell(char_as_cell!('e'));
+            section.push_cell(empty_list_as_cell!());
+        });
+
+        unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0));
+
+        assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('b'));
+        assert_eq!(wam.machine_st.heap[6 + start], char_as_cell!('d'));
         assert!(!wam.machine_st.fail);
     }
 }
index 0173285e4b62b6d14558d2fba511403e1e981bf9..751b55b60d7f748054a636d919b37074ed8a1b92 100644 (file)
@@ -3,6 +3,7 @@ use crate::codegen::CodeGenSettings;
 use crate::forms::*;
 use crate::instructions::*;
 use crate::machine::disjuncts::*;
+use crate::machine::heap::*;
 use crate::machine::loader::*;
 use crate::machine::machine_errors::*;
 use crate::machine::CodeIndex;
@@ -27,25 +28,42 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result<OpDeclSpec, CompilationError
 fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> {
     let (focus, _cell) = subterm_index(term.heap, term.focus);
 
-    let name = match term.name(focus+3) {
-        Some(name) => name,
-        None => return Err(CompilationError::InconsistentEntry),
+    let name = match term_predicate_key(term.heap, focus+3) {
+        Some((name, 0)) => name,
+        _ => {
+            return Err(CompilationError::InvalidDirective(
+                DirectiveError::InvalidOpDeclNameType(term.heap[focus+3]),
+            ));
+        }
     };
 
-    let spec = match term.name(focus+2) {
-        Some(name) => name,
-        None => return Err(CompilationError::InconsistentEntry),
+    let spec = match term_predicate_key(term.heap, focus+2) {
+        Some((name, _)) => name,
+        None => {
+            return Err(CompilationError::InvalidDirective(
+                DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus+2]),
+            ));
+        }
     };
 
-    let prec = read_heap_cell!(term.deref_loc(focus+1),
+    let spec = to_op_decl_spec(spec)?;
+    let prec = term.deref_loc(focus+1);
+
+    let prec = read_heap_cell!(prec,
         (HeapCellValueTag::Fixnum, n) => {
             match u16::try_from(n.get_num()) {
                 Ok(n) if n <= 1200 => n,
-                _ => return Err(CompilationError::InconsistentEntry),
+                _ => {
+                    return Err(CompilationError::InvalidDirective(
+                        DirectiveError::InvalidOpDeclPrecDomain(n),
+                    ));
+                }
             }
         }
         _ => {
-            return Err(CompilationError::InconsistentEntry);
+            return Err(CompilationError::InvalidDirective(
+                DirectiveError::InvalidOpDeclPrecType(prec),
+            ));
         }
     );
 
@@ -71,10 +89,9 @@ fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> {
 }
 
 fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result<PredicateKey, CompilationError> {
-    let name_opt = term.name(term.focus);
-    let arity = term.arity(term.focus);
+    let key_opt = term_predicate_key(term.heap, term.focus);
 
-    if let (Some(atom!("/") | atom!("//")), 2) = (name_opt, arity) {
+    if let Some((atom!("/") | atom!("//"), 2)) = key_opt {
         let arity_loc = term.nth_arg(term.focus, 2).unwrap();
 
         let arity = match Number::try_from(term.deref_loc(arity_loc)) {
@@ -85,11 +102,11 @@ fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result<PredicateKey, C
         .ok_or(CompilationError::InvalidModuleExport)?;
 
         let name_loc = term.nth_arg(term.focus, 1).unwrap();
-        let name = term
-            .name(name_loc)
+        let name = term_predicate_key(term.heap, name_loc)
+            .map(|(name, _)| name)
             .ok_or(CompilationError::InvalidModuleExport)?;
 
-        if name_opt == Some(atom!("/")) {
+        if matches!(key_opt, Some((atom!("/"), _))) {
             Ok((name, arity))
         } else {
             Ok((name, arity + 2))
@@ -103,10 +120,9 @@ fn setup_module_export(term: &FocusedHeapRefMut) -> Result<ModuleExport, Compila
     setup_predicate_indicator(term)
         .map(ModuleExport::PredicateKey)
         .or_else(|_| {
-            let name_opt = term.name(term.focus);
-            let arity = term.arity(term.focus);
+            let key_opt = term_predicate_key(term.heap, term.focus);
 
-            if let (Some(atom!("op")), 3) = (name_opt, arity) {
+            if let Some((atom!("op"), 3)) = key_opt {
                 Ok(ModuleExport::OpDecl(setup_op_decl(term)?))
             } else {
                 Err(CompilationError::InvalidModuleDecl)
@@ -131,48 +147,46 @@ pub(super) fn setup_module_export_list(
     let mut focus = term.focus;
 
     loop {
-       read_heap_cell!(term.heap[focus],
-           (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-               if h == focus {
-                   break;
-               } else {
-                   focus = h;
-               }
-           }
-           (HeapCellValueTag::Lis, l) => {
-               let term = FocusedHeapRefMut {
-                   heap: term.heap,
-                   focus: l,
-               };
-               exports.push(setup_module_export(&term)?);
-
-               focus = l + 1;
-           }
-            (HeapCellValueTag::Atom, (name, _arity)) => {
-               if name == atom!("[]") {
-                   return Ok(exports);
-               } else {
-                   break;
-               }
-           }
-           _ => {
-               break;
-           }
-       );
+          read_heap_cell!(term.heap[focus],
+              (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+                      if h == focus {
+                          break;
+                      } else {
+                          focus = h;
+                      }
+              }
+              (HeapCellValueTag::Lis, l) => {
+                      let term = FocusedHeapRefMut {
+                          heap: term.heap,
+                          focus: l,
+                      };
+
+                      exports.push(setup_module_export(&term)?);
+                      focus = l + 1;
+              }
+           (HeapCellValueTag::Atom, (name, _arity)) => {
+                      if name == atom!("[]") {
+                          return Ok(exports);
+                      } else {
+                          break;
+                      }
+              }
+              _ => {
+                      break;
+              }
+          );
     }
 
     Err(CompilationError::InvalidModuleDecl)
 }
 
-fn setup_module_decl(term: FocusedHeapRefMut) -> Result<ModuleDecl, CompilationError> {
-    let name = term
-        .name(term.focus + 1)
+fn setup_module_decl(mut term: FocusedHeapRefMut) -> Result<ModuleDecl, CompilationError> {
+    let name = term_predicate_key(term.heap, term.focus + 1)
+        .map(|(name, _)| name)
         .ok_or(CompilationError::InvalidModuleDecl)?;
-    let export_list = FocusedHeapRefMut {
-        heap: term.heap,
-        focus: term.focus + 2,
-    };
-    let exports = setup_module_export_list(export_list)?;
+
+    term.focus = term.focus + 2;
+    let exports = setup_module_export_list(term)?;
 
     Ok(ModuleDecl { name, exports })
 }
@@ -224,8 +238,8 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, Co
             heap: term.heap,
             focus,
         };
-        exports.insert(setup_module_export(&term)?);
 
+        exports.insert(setup_module_export(&term)?);
         focus = focus + 1;
     }
 
@@ -276,7 +290,7 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, Co
  */
 
 fn setup_meta_predicate<'a, LS: LoadState<'a>>(
-    term: FocusedHeapRefMut,
+    term: TermWriteResult,
     loader: &mut Loader<'a, LS>,
 ) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
     fn get_meta_specs(
@@ -319,24 +333,27 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
         Ok(meta_specs)
     }
 
-    read_heap_cell!(term.deref_loc(term.focus+1),
+    let heap = loader.machine_heap();
+    let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[term.focus+1]));
+
+    read_heap_cell!(cell,
         (HeapCellValueTag::Str, s) => {
-            let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity();
+            let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
 
             match (name, arity) {
                 (atom!(":"), 2) => {
-                    let module_name = term.heap[s+1];
-                    let spec = term.heap[s+2];
+                    let module_name = heap[s+1];
+                    let spec = heap[s+2];
 
                     read_heap_cell!(module_name,
                         (HeapCellValueTag::Atom, (module_name, arity)) => {
                             if arity == 0 {
                                 read_heap_cell!(spec,
                                     (HeapCellValueTag::Str, s) => {
-                                        let (name, arity) = cell_as_atom_cell!(term.heap[s])
+                                        let (name, arity) = cell_as_atom_cell!(heap[s])
                                             .get_name_and_arity();
 
-                                        let term = FocusedHeapRefMut { heap: term.heap, focus: s };
+                                        let term = FocusedHeapRefMut { heap, focus: s };
                                         return Ok((module_name, name, get_meta_specs(term, arity)?));
                                     }
                                     _ => {
@@ -351,9 +368,11 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
                     );
                 }
                 _ => {
-                    let term = FocusedHeapRefMut { heap: term.heap, focus: s };
+                    let term = FocusedHeapRefMut { heap, focus: s };
+                    let specs = get_meta_specs(term, arity)?;
                     let module_name = loader.payload.compilation_target.module_name();
-                    return Ok((module_name, name, get_meta_specs(term, arity)?));
+
+                    return Ok((module_name, name, specs));
                 }
             }
 
@@ -367,38 +386,41 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
 
 pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
     loader: &mut Loader<'a, LS>,
-    term: FocusedHeapRefMut,
+    mut term: TermWriteResult,
 ) -> Result<Declaration, CompilationError> {
     let mut focus = term.focus;
+    let machine_st = LS::machine_st(&mut loader.payload);
 
     loop {
-        read_heap_cell!(term.heap[focus],
+        let decl = machine_st.heap[focus];
+
+        read_heap_cell!(decl,
             (HeapCellValueTag::Atom, (name, arity)) => {
-                let term = FocusedHeapRefMut { heap: term.heap, focus };
+                let mut focused = FocusedHeapRefMut::from(&mut machine_st.heap, focus);
 
                 return match (name, arity) {
                     (atom!("dynamic"), 1) => {
-                        let (name, arity) = setup_predicate_indicator(&term)?;
+                        let (name, arity) = setup_predicate_indicator(&focused)?;
                         Ok(Declaration::Dynamic(name, arity))
                     }
                     (atom!("module"), 2) => {
-                        Ok(Declaration::Module(setup_module_decl(term)?))
+                        Ok(Declaration::Module(setup_module_decl(focused)?))
                     }
                     (atom!("op"), 3) => {
-                        Ok(Declaration::Op(setup_op_decl(&term)?))
+                        Ok(Declaration::Op(setup_op_decl(&focused)?))
                     }
                     (atom!("non_counted_backtracking"), 1) => {
-                        let focus = term.nth_arg(term.focus, 1).unwrap();
-                        let (name, arity) = setup_predicate_indicator(&FocusedHeapRefMut { heap: term.heap, focus })?;
+                        focused.focus = focused.nth_arg(focused.focus, 1).unwrap();
+                        let (name, arity) = setup_predicate_indicator(&focused)?;
                         Ok(Declaration::NonCountedBacktracking(name, arity))
                     }
-                    (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&term)?)),
+                    (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&focused)?)),
                     (atom!("use_module"), 2) => {
-                        let (name, exports) = setup_qualified_import(term)?;
-
+                        let (name, exports) = setup_qualified_import(focused)?;
                         Ok(Declaration::UseQualifiedModule(name, exports))
                     }
                     (atom!("meta_predicate"), 1) => {
+                        term.focus = focus;
                         let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?;
                         Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
                     }
@@ -415,13 +437,13 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
                     focus = h;
                 } else {
                     return Err(CompilationError::InvalidDirective(
-                        DirectiveError::ExpectedDirective(heap_loc_as_cell!(h)),
+                        DirectiveError::ExpectedDirective(decl),
                     ));
                 }
             }
             _ => {
                 return Err(CompilationError::InvalidDirective(
-                    DirectiveError::ExpectedDirective(term.heap[focus])
+                    DirectiveError::ExpectedDirective(decl),
                 ));
             }
         );
@@ -432,41 +454,44 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
     loader: &mut Loader<'a, LS>,
     module_name: Atom,
     arity: usize,
-    term: &FocusedHeapRefMut,
+    term: &TermWriteResult,
     meta_specs: Vec<MetaSpec>,
 ) -> IndexMap<usize, CodeIndex, FxBuildHasher> {
+    use crate::machine::heap::Heap;
     let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default());
 
     for (subterm_loc, meta_spec) in (term.focus + 1..term.focus + arity + 1).zip(meta_specs) {
         if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
-            if let Some(name) = term.name(subterm_loc) {
+            let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc);
+
+            if let Some((name, arity)) = predicate_key_opt {
                 if name == atom!("$call") {
                     continue;
                 }
 
-                let arity = term.arity(subterm_loc);
-
                 struct QualifiedNameInfo {
                     module_name: Atom,
                     name: Atom,
+                    arity: usize,
                     qualified_term_loc: usize,
                 }
 
                 fn get_qualified_name(
-                    term: &FocusedHeapRefMut,
+                    heap: &Heap,
                     module_term_loc: usize,
                     qualified_term_loc: usize,
                 ) -> Option<QualifiedNameInfo> {
-                    let (module_term_loc, _) = subterm_index(term.heap, module_term_loc);
-                    let (qualified_term_loc, _) = subterm_index(term.heap, qualified_term_loc);
+                    let (module_term_loc, _) = subterm_index(heap, module_term_loc);
+                    let (qualified_term_loc, _) = subterm_index(heap, qualified_term_loc);
 
-                    read_heap_cell!(term.heap[module_term_loc],
+                    read_heap_cell!(heap[module_term_loc],
                         (HeapCellValueTag::Atom, (module_name, arity)) => {
                             if arity == 0 {
-                                if let Some(name) = term.name(qualified_term_loc) {
+                                if let Some((name, arity)) = term_predicate_key(heap, qualified_term_loc) {
                                     return Some(QualifiedNameInfo {
                                         module_name,
                                         name,
+                                        arity,
                                         qualified_term_loc,
                                     });
                                 }
@@ -478,23 +503,20 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
                     None
                 }
 
-                let (subterm_loc, _) = subterm_index(term.heap, subterm_loc);
-
-                let subterm_arity = term.arity(subterm_loc);
-                let subterm_name_opt = term.name(subterm_loc);
+                let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc);
+                let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc);
 
                 let (module_name, key, term_loc) =
-                    if subterm_name_opt == Some(atom!(":")) && subterm_arity == 2 {
-                        debug_assert_eq!(term.heap[subterm_loc].get_tag(), HeapCellValueTag::Atom);
-
-                        match get_qualified_name(term, subterm_loc + 1, subterm_loc + 2) {
+                    if subterm_key_opt == Some((atom!(":"), 2)) {
+                        match get_qualified_name(loader.machine_heap(), subterm_loc + 1, subterm_loc + 2) {
                             Some(QualifiedNameInfo {
                                 module_name,
                                 name,
+                                arity,
                                 qualified_term_loc,
                             }) => (
                                 module_name,
-                                (name, term.arity(qualified_term_loc) + supp_args),
+                                (name, arity + supp_args),
                                 qualified_term_loc,
                             ),
                             None => {
@@ -505,7 +527,7 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
                         (module_name, (name, arity + supp_args), subterm_loc)
                     };
 
-                if let Some(index_ptr) = fetch_index_ptr(term.heap, key.1, term_loc) {
+                if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), key.1, term_loc) {
                     index_ptrs.insert(term_loc, index_ptr);
                     continue;
                 }
@@ -525,13 +547,13 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
 pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
     loader: &mut Loader<'a, LS>,
     key: PredicateKey,
-    terms: FocusedHeapRefMut,
+    terms: &TermWriteResult,
     term: HeapCellValue,
     call_policy: CallPolicy,
 ) -> QueryClause {
     // supplementary code vector indices are unnecessary for
     // root-level clauses.
-    blunt_index_ptr(terms.heap, key, terms.focus);
+    blunt_index_ptr(loader.machine_heap(), key, terms.focus);
 
     let mut ct = loader.get_clause_type(key.0, key.1);
 
@@ -539,11 +561,10 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
         if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
             let module_name = loader.payload.compilation_target.module_name();
             let code_indices =
-                build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs);
+                build_meta_predicate_clause(loader, module_name, arity, terms, meta_specs);
 
             return QueryClause {
                 ct: ClauseType::Named(key.1, key.0, idx),
-                arity,
                 term,
                 code_indices,
                 call_policy,
@@ -555,7 +576,6 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
 
     QueryClause {
         ct,
-        arity: key.1,
         term,
         code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
         call_policy,
@@ -567,13 +587,13 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
     loader: &mut Loader<'a, LS>,
     key: PredicateKey,
     module_name: Atom,
-    terms: FocusedHeapRefMut,
+    terms: &TermWriteResult,
     term: HeapCellValue,
     call_policy: CallPolicy,
 ) -> QueryClause {
     // supplementary code vector indices are unnecessary for
     // root-level clauses.
-    blunt_index_ptr(terms.heap, key, terms.focus);
+    blunt_index_ptr(loader.machine_heap(), key, terms.focus);
 
     let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1);
 
@@ -584,7 +604,6 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
 
             return QueryClause {
                 ct: ClauseType::Named(key.1, key.0, idx),
-                arity,
                 term,
                 code_indices,
                 call_policy,
@@ -596,7 +615,6 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
 
     QueryClause {
         ct,
-        arity: key.1,
         term,
         code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
         call_policy,
@@ -613,15 +631,18 @@ impl Preprocessor {
         Preprocessor { settings }
     }
 
-    pub fn setup_fact(
+    pub fn setup_fact<'a, LS: LoadState<'a>>(
         &mut self,
-        mut term: FocusedHeap,
+        loader: &mut Loader<'a, LS>,
+        term: TermWriteResult,
     ) -> Result<(Fact, VarData), CompilationError> {
-        if term.name(term.focus).is_some() {
+        let heap = loader.machine_heap();
+
+        if term_predicate_key(heap, term.focus).is_some() {
             let classifier = VariableClassifier::new(self.settings.default_call_policy());
-            let var_data = classifier.classify_fact(&mut term)?;
+            let var_data = classifier.classify_fact(loader, &term)?;
 
-            Ok((Fact { term }, var_data))
+            Ok((Fact { term_loc: term.focus }, var_data))
         } else {
             Err(CompilationError::InadmissibleFact)
         }
@@ -630,14 +651,16 @@ impl Preprocessor {
     fn setup_rule<'a, LS: LoadState<'a>>(
         &mut self,
         loader: &mut Loader<'a, LS>,
-        mut term: FocusedHeap,
+        term: TermWriteResult,
     ) -> Result<(Rule, VarData), CompilationError> {
         let classifier = VariableClassifier::new(self.settings.default_call_policy());
-        let (clauses, var_data) = classifier.classify_rule(loader, &mut term)?;
-        let head_loc = term.nth_arg(term.focus, 1).unwrap();
+        let (clauses, var_data) = classifier.classify_rule(loader, &term)?;
+
+        let heap = loader.machine_heap();
+        let head_loc = term_nth_arg(heap, term.focus, 1).unwrap();
 
-        if term.name(head_loc).is_some() {
-            Ok((Rule { term, clauses }, var_data))
+        if term_predicate_key(heap, head_loc).is_some() {
+            Ok((Rule { term_loc: term.focus, clauses }, var_data))
         } else {
             Err(CompilationError::InvalidRuleHead)
         }
@@ -646,19 +669,18 @@ impl Preprocessor {
     pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
         &mut self,
         loader: &mut Loader<'a, LS>,
-        term: FocusedHeap,
-    ) -> Result<TopLevel, CompilationError> {
-        let name = term.name(term.focus);
-        let arity = term.arity(term.focus);
+        term: TermWriteResult,
+    ) -> Result<PredicateClause, CompilationError> {
+        let heap = &LS::machine_st(&mut loader.payload).heap;
 
-        match (name, arity) {
-            (Some(atom!(":-")), 2) => {
+        match term_predicate_key(heap, term.focus) {
+            Some((atom!(":-"), 2)) => {
                 let (rule, var_data) = self.setup_rule(loader, term)?;
-                Ok(TopLevel::Rule(rule, var_data))
+                Ok(PredicateClause::Rule(rule, var_data))
             }
             _ => {
-                let (fact, var_data) = self.setup_fact(term)?;
-                Ok(TopLevel::Fact(fact, var_data))
+                let (fact, var_data) = self.setup_fact(loader, term)?;
+                Ok(PredicateClause::Fact(fact, var_data))
             }
         }
     }
index ffb04a39835ef10f2acf50723d1035f4c36ca275..267a4a93a6b1a453f1eb413b4e469388342d2d5c 100644 (file)
@@ -1,12 +1,12 @@
 use crate::arena::*;
 use crate::atom_table::*;
+use crate::functor_macro::*;
 use crate::parser::ast::*;
 use crate::parser::char_reader::*;
 use crate::read::*;
 
 #[cfg(feature = "http")]
 use crate::http::HttpResponse;
-use crate::machine::heap::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
@@ -390,7 +390,7 @@ impl StreamOptions {
     #[inline]
     pub fn get_alias(self) -> Option<Atom> {
         if self.has_alias() {
-            Some(Atom::from(self.alias() << 3))
+            Some(Atom::from(self.alias() << 1))
         } else {
             None
         }
@@ -1735,7 +1735,7 @@ impl MachineState {
         let err = self.permission_error(
             Permission::Open,
             atom!("source_sink"),
-            functor!(atom!("alias"), [atom(alias)]),
+            functor!(atom!("alias"), [atom_as_cell(alias)]),
         );
 
         self.error_form(err, stub)
@@ -1743,7 +1743,7 @@ impl MachineState {
 
     pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub {
         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);
 
         self.error_form(err, stub)
index a61e8a722846d44be0c7cd99a450b08fd380c8d4..2378dfe2a494fe586c813c9b7cab2b514e94ebbd 100644 (file)
@@ -1,4 +1,5 @@
 use crate::parser::ast::*;
+use crate::parser::lexer::LexerParser;
 use crate::parser::parser::*;
 
 use base64::Engine;
@@ -11,6 +12,7 @@ use crate::atom_table::*;
 #[cfg(feature = "ffi")]
 use crate::ffi::*;
 use crate::forms::*;
+use crate::functor_macro::*;
 use crate::heap_iter::*;
 use crate::heap_print::*;
 #[cfg(feature = "http")]
@@ -39,7 +41,6 @@ use ordered_float::OrderedFloat;
 use fxhash::{FxBuildHasher, FxHasher};
 use indexmap::IndexSet;
 
-use std::cell::Cell;
 use std::cmp::Ordering;
 use std::collections::BTreeSet;
 use std::convert::TryFrom;
@@ -124,6 +125,56 @@ pub(crate) fn get_key() -> KeyEvent {
     key
 }
 
+fn pstr_segment_char_count_and_tail(heap: &Heap, pstr_loc: usize) -> (usize, usize) {
+    let char_iter = heap.char_iter(pstr_loc);
+
+    let mut char_count = 0;
+    let mut byte_offset = 0;
+
+    for c in char_iter {
+        if c == '\u{0}' {
+            break;
+        }
+
+        char_count += 1;
+        byte_offset += c.len_utf8();
+    }
+
+    (char_count, Heap::neighboring_cell_offset(pstr_loc + byte_offset))
+}
+
+fn pstr_segment_char_count_up_to(
+    heap: &Heap,
+    pstr_loc: usize,
+    max_chars: usize,
+) -> PStrSegmentCountResult {
+    let mut char_iter = heap.char_iter(pstr_loc);
+    let mut char_count = 0;
+    let mut byte_offset = 0;
+
+    if max_chars > 0 {
+        while let Some(c) = char_iter.next() {
+            if c == '\u{0}' {
+                break;
+            }
+
+            char_count += 1;
+            byte_offset += c.len_utf8();
+
+            if char_count >= max_chars {
+                break;
+            }
+        }
+    }
+
+    if char_iter.next().is_some() {
+        PStrSegmentCountResult::Mid { char_count, pstr_loc: pstr_loc + byte_offset }
+    } else {
+        let tail_loc = Heap::neighboring_cell_offset(pstr_loc + byte_offset);
+        PStrSegmentCountResult::End { char_count, tail_loc }
+    }
+}
+
 #[derive(Debug, Clone, Copy)]
 pub struct BrentAlgState {
     pub hare: usize,
@@ -161,7 +212,7 @@ impl BrentAlgState {
         self.lam += 1;
 
         if self.tortoise == self.hare {
-            return Some(CycleSearchResult::Cyclic(self.lam));
+            return Some(CycleSearchResult::Cyclic { lambda: self.lam });
         } else {
             self.teleport_tortoise();
         }
@@ -179,28 +230,26 @@ impl BrentAlgState {
         self.max_steps > -1 && self.num_steps() as i64 >= self.max_steps
     }
 
-    pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult {
+    pub fn to_result(mut self, heap: &Heap) -> CycleSearchResult {
         loop {
             read_heap_cell!(heap[self.hare],
-                (HeapCellValueTag::PStrOffset) => {
-                    let (pstr_loc, offset) = pstr_loc_and_offset(heap, self.hare);
-                    let offset = offset.get_num() as usize;
-
-                    let pstr = cell_as_string!(heap[self.hare]);
-                    self.pstr_chars += pstr.as_str_from(offset).chars().count();
-
-                    return CycleSearchResult::PStrLocation(self.num_steps(), pstr_loc, offset);
-                }
-                (HeapCellValueTag::PStrLoc, l) => {
-                    let (_pstr_loc, offset) = pstr_loc_and_offset(heap, l);
-                    let offset = offset.get_num() as usize;
-                    return CycleSearchResult::PStrLocation(self.num_steps(), l, offset);
+                (HeapCellValueTag::PStrLoc) => {
+                    // let (_pstr_loc, offset) = pstr_loc_and_offset(heap, l);
+                    // let offset = offset.get_num() as usize;
+                    let num_steps = self.num_steps();
+                    return CycleSearchResult::PStrLocation { num_steps, pstr_loc: heap[self.hare] };
                 }
                 (HeapCellValueTag::Atom, (name, arity)) => {
                     return if name == atom!("[]") && arity == 0 {
-                        CycleSearchResult::ProperList(self.num_steps())
+                        CycleSearchResult::ProperList { num_steps: self.num_steps() }
                     } else {
-                        CycleSearchResult::NotList(self.num_steps(), heap[self.hare])
+                        let heap_loc = if arity > 0 {
+                            str_loc_as_cell!(self.hare)
+                        } else {
+                            heap_loc_as_cell!(self.hare)
+                        };
+
+                        CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc }
                     };
                 }
                 (HeapCellValueTag::Str, s) => {
@@ -208,96 +257,72 @@ impl BrentAlgState {
                         .get_name_and_arity();
 
                     return if name == atom!("[]") && arity == 0 {
-                        CycleSearchResult::ProperList(self.num_steps())
+                        CycleSearchResult::ProperList { num_steps: self.num_steps() }
                     } else {
-                        CycleSearchResult::NotList(self.num_steps(), heap[self.hare])
+                        CycleSearchResult::NotList {
+                            num_steps: self.num_steps(),
+                            heap_loc: heap[self.hare],
+                        }
                     };
                 }
                 (HeapCellValueTag::Lis, l) => {
-                    return CycleSearchResult::UntouchedList(self.num_steps(), l);
+                    return CycleSearchResult::UntouchedList { num_steps: self.num_steps(), list_loc: l };
                 }
                 (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
                     if h == self.hare {
-                        let var = heap[self.hare].as_var().unwrap();
-                        return CycleSearchResult::PartialList(self.num_steps(), var);
+                        // let var = heap[self.hare].as_var().unwrap();
+                        return CycleSearchResult::PartialList {
+                            num_steps: self.num_steps(),
+                            heap_loc: heap[self.hare],
+                        };
                     } else {
                         self.hare = h;
                     }
                 }
                 _ => {
-                    return CycleSearchResult::NotList(self.num_steps(), heap[self.hare]);
+                    let heap_loc = heap_loc_as_cell!(self.hare);
+                    return CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc };
                 }
             );
         }
     }
 
-    fn add_pstr_offset_chars(
-        &mut self,
-        heap: &[HeapCellValue],
-        h: usize,
-        offset: usize,
-    ) -> Option<CycleSearchResult> {
-        read_heap_cell!(heap[h],
-            (HeapCellValueTag::CStr, cstr_atom) => {
-                let cstr = PartialString::from(cstr_atom);
-                let num_chars = cstr.as_str_from(offset).chars().count();
+    fn add_pstr_chars(&mut self, heap: &Heap, pstr_loc: usize) -> Option<CycleSearchResult> {
+        let next_cell_loc;
 
-                if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize {
-                    self.pstr_chars += num_chars;
-                    Some(CycleSearchResult::ProperList(self.num_steps()))
-                } else {
-                    let char_offset = self.max_steps as usize - self.num_steps();
-                    self.pstr_chars += char_offset;
-                    Some(CycleSearchResult::PStrLocation(self.max_steps as usize, h, char_offset + offset))
-                }
-            }
-            (HeapCellValueTag::PStr, pstr_atom) => {
-                let pstr = PartialString::from(pstr_atom);
-                let num_chars = pstr.as_str_from(offset).chars().count();
+        if self.max_steps == -1 {
+            let num_chars;
+            (num_chars, next_cell_loc) = pstr_segment_char_count_and_tail(heap, pstr_loc);
+            self.pstr_chars += num_chars - 1;
+        } else {
+            let max_chars = self.max_steps as usize - self.num_steps();
 
-                if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize {
-                    self.pstr_chars += num_chars - 1;
-                    self.step(h+1)
-                } else {
-                    let char_offset = self.max_steps as usize - self.num_steps();
-                    self.pstr_chars += char_offset;
-                    Some(CycleSearchResult::PStrLocation(self.max_steps as usize, h, char_offset + offset))
+            match pstr_segment_char_count_up_to(heap, pstr_loc, max_chars) {
+                PStrSegmentCountResult::Mid { char_count, pstr_loc } => {
+                    self.pstr_chars += char_count;
+                    return Some(CycleSearchResult::PStrLocation {
+                        num_steps: self.num_steps(),
+                        pstr_loc: pstr_loc_as_cell!(pstr_loc),
+                    });
+                }
+                PStrSegmentCountResult::End { char_count, tail_loc } => {
+                    self.pstr_chars += char_count.saturating_sub(1);
+                    next_cell_loc = tail_loc;
                 }
             }
-            _ => {
-                unreachable!()
-            }
-        )
-    }
+        }
 
-    fn add_pstr_chars_and_step(
-        &mut self,
-        heap: &[HeapCellValue],
-        h: usize,
-    ) -> Option<CycleSearchResult> {
-        read_heap_cell!(heap[h],
-            (HeapCellValueTag::PStrOffset, l) => {
-                let (pstr_loc, _) = pstr_loc_and_offset(heap, l);
-                let offset = cell_as_fixnum!(heap[h+1]);
-                self.add_pstr_offset_chars(heap, pstr_loc, offset.get_num() as usize)
-            }
-            _ => {
-                self.add_pstr_offset_chars(heap, h, 0)
-            }
-        )
+        self.step(next_cell_loc)
     }
 
     #[inline(always)]
-    fn cycle_step(&mut self, heap: &[HeapCellValue]) -> Option<CycleSearchResult> {
+    fn cycle_step(&mut self, heap: &Heap) -> Option<CycleSearchResult> {
         loop {
             let value = heap[self.hare];
 
             read_heap_cell!(value,
                 (HeapCellValueTag::PStrLoc, h) => {
-                    return self.add_pstr_chars_and_step(heap, h);
-                }
-                (HeapCellValueTag::CStr | HeapCellValueTag::PStrOffset) => {
-                    return self.add_pstr_chars_and_step(heap, self.hare);
+                    return self.add_pstr_chars(heap, h);
                 }
                 (HeapCellValueTag::Lis, h) => {
                     return self.step(h+1);
@@ -308,63 +333,49 @@ impl BrentAlgState {
                     return if name == atom!(".") && arity == 2 {
                         self.step(s+2)
                     } else {
-                        Some(CycleSearchResult::NotList(self.num_steps(), value))
+                        Some(CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc: value })
                     };
                 }
                 (HeapCellValueTag::Atom, (name, arity)) => {
                     debug_assert!(arity == 0);
 
                     return if name == atom!("[]") {
-                        Some(CycleSearchResult::ProperList(self.num_steps()))
+                        Some(CycleSearchResult::ProperList { num_steps: self.num_steps() })
                     } else {
-                        Some(CycleSearchResult::NotList(self.num_steps(), value))
+                        Some(CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc: value })
                     };
                 }
                 (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
                     if self.hare == h {
-                        let r = value.as_var().unwrap();
-                        return Some(CycleSearchResult::PartialList(self.num_steps(), r));
+                        return Some(CycleSearchResult::PartialList { num_steps: self.num_steps(), heap_loc: value });
                     }
 
                     self.hare = h;
                 }
                 _ => {
-                    return Some(CycleSearchResult::NotList(self.num_steps(), value));
+                    return Some(CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc: value });
                 }
             );
         }
     }
 
-    pub fn detect_cycles(heap: &[HeapCellValue], value: HeapCellValue) -> CycleSearchResult {
-        let mut pstr_chars = 0;
+    pub fn detect_cycles(heap: &Heap, value: HeapCellValue) -> CycleSearchResult {
+        let mut char_count = 0;
 
         let hare = read_heap_cell!(value,
             (HeapCellValueTag::Lis, offset) => {
                 offset+1
             }
             (HeapCellValueTag::PStrLoc, h) => {
-                let (h_offset, n) = pstr_loc_and_offset(heap, h);
-                let n = n.get_num() as usize;
-                let pstr = cell_as_string!(heap[h_offset]);
-
-                pstr_chars = pstr.as_str_from(n).chars().count() - 1;
+                let tail_idx;
+                (char_count, tail_idx) = pstr_segment_char_count_and_tail(heap, h);
 
-                if heap[h].get_tag() == HeapCellValueTag::PStrOffset {
-                    debug_assert!(heap[h].get_tag() == HeapCellValueTag::PStrOffset);
-
-                    if heap[h_offset].get_tag() == HeapCellValueTag::CStr {
-                        return CycleSearchResult::ProperList(pstr_chars + 1);
-                    }
+                if heap[tail_idx] == empty_list_as_cell!() {
+                    return CycleSearchResult::ProperList { num_steps: char_count };
                 }
 
-                h_offset+1
-            }
-            (HeapCellValueTag::PStrOffset) => {
-                unreachable!()
-            }
-            (HeapCellValueTag::CStr, cstr_atom) => {
-                let cstr = PartialString::from(cstr_atom);
-                return CycleSearchResult::ProperList(cstr.as_str_from(0).chars().count());
+                char_count = char_count.saturating_sub(1);
+                tail_idx
             }
             (HeapCellValueTag::Str, s) => {
                 let (name, arity) = cell_as_atom_cell!(heap[s])
@@ -375,28 +386,29 @@ impl BrentAlgState {
                 } else if name == atom!(".") && arity == 2 {
                     s + 2
                 } else {
-                    return CycleSearchResult::NotList(0, value);
+                    return CycleSearchResult::NotList { num_steps: 0, heap_loc: value };
                 }
             }
             (HeapCellValueTag::Atom, (name, arity)) => {
                 return if name == atom!("[]") && arity == 0 {
                     CycleSearchResult::EmptyList
                 } else {
-                    CycleSearchResult::NotList(0, value)
+                    debug_assert_eq!(arity, 0);
+                    CycleSearchResult::NotList { num_steps: 0, heap_loc: value }
                 };
             }
             (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => {
-                return CycleSearchResult::PartialList(0, value.as_var().unwrap());
+                return CycleSearchResult::PartialList { num_steps: 0, heap_loc: value };
             }
             _ => {
-                return CycleSearchResult::NotList(0, value);
+                return CycleSearchResult::NotList { num_steps: 0, heap_loc: value };
             }
         );
 
         let mut brent_st = BrentAlgState::new(hare);
 
         brent_st.power += 1; // advance a step.
-        brent_st.pstr_chars = pstr_chars;
+        brent_st.pstr_chars = char_count;
 
         loop {
             if let Some(result) = brent_st.cycle_step(heap) {
@@ -406,58 +418,31 @@ impl BrentAlgState {
     }
 
     pub fn detect_cycles_with_max(
-        heap: &[HeapCellValue],
+        heap: &Heap,
         max_steps: usize,
         value: HeapCellValue,
     ) -> CycleSearchResult {
-        let mut pstr_chars = 0;
+        let mut char_count = 0;
 
         let hare = read_heap_cell!(value,
             (HeapCellValueTag::Lis, offset) => {
                 if max_steps > 0 {
                     offset+1
                 } else {
-                    return CycleSearchResult::UntouchedList(0, offset);
+                    return CycleSearchResult::UntouchedList { num_steps: 0, list_loc: offset };
                 }
             }
             (HeapCellValueTag::PStrLoc, h) => {
-                let (h_offset, n) = pstr_loc_and_offset(heap, h);
-                let n = n.get_num() as usize;
-                let pstr = cell_as_string!(heap[h_offset]);
-
-                pstr_chars = pstr.as_str_from(n).chars().count() - 1;
-
-                if heap[h].get_tag() == HeapCellValueTag::PStrOffset && heap[h_offset].get_tag() == HeapCellValueTag::CStr {
-                    return if pstr_chars < max_steps {
-                        CycleSearchResult::ProperList(pstr_chars + 1)
-                    } else {
-                        let offset = max_steps + n;
-                        CycleSearchResult::PStrLocation(max_steps, h_offset, offset)
+                match pstr_segment_char_count_up_to(heap, h, max_steps) {
+                    PStrSegmentCountResult::Mid { char_count, pstr_loc } => {
+                        let pstr_loc = pstr_loc_as_cell!(pstr_loc);
+                        return CycleSearchResult::PStrLocation { num_steps: char_count, pstr_loc };
                     }
-                }
-
-                if pstr_chars + 1 > max_steps {
-                    return CycleSearchResult::PStrLocation(max_steps, h_offset, max_steps);
-                }
-
-                h_offset+1
-            }
-            (HeapCellValueTag::PStrOffset) => {
-                unreachable!()
-            }
-            (HeapCellValueTag::CStr, cstr_atom) => {
-                return if max_steps > 0 {
-                    let cstr = PartialString::from(cstr_atom);
-                    let pstr_chars = cstr.as_str_from(0).chars().count();
-
-                    if pstr_chars <= max_steps {
-                        CycleSearchResult::ProperList(pstr_chars)
-                    } else {
-                        CycleSearchResult::UntouchedCStr(cstr_atom, max_steps)
+                    PStrSegmentCountResult::End { char_count: num_chars, tail_loc } => {
+                        char_count = num_chars - 1;
+                        tail_loc
                     }
-                } else {
-                    CycleSearchResult::UntouchedCStr(cstr_atom, 0)
-                };
+                }
             }
             (HeapCellValueTag::Str, s) => {
                 let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
@@ -468,31 +453,32 @@ impl BrentAlgState {
                     if max_steps > 0 {
                         s + 2
                     } else {
-                        return CycleSearchResult::UntouchedList(0, s + 1);
+                        return CycleSearchResult::UntouchedList { num_steps: 0, list_loc: s + 1 };
                     }
                 } else {
-                    return CycleSearchResult::NotList(0, value);
+                    return CycleSearchResult::NotList { num_steps: 0, heap_loc: value };
                 }
             }
             (HeapCellValueTag::Atom, (name, arity)) => {
                 return if name == atom!("[]") && arity == 0 {
                     CycleSearchResult::EmptyList
                 } else {
-                    CycleSearchResult::NotList(0, value)
+                    debug_assert_eq!(arity, 0);
+                    CycleSearchResult::NotList { num_steps: 0, heap_loc: value }
                 };
             }
             (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => {
-                return CycleSearchResult::PartialList(0, value.as_var().unwrap());
+                return CycleSearchResult::PartialList { num_steps: 0, heap_loc: value };
             }
             _ => {
-                return CycleSearchResult::NotList(0, value);
+                return CycleSearchResult::NotList { num_steps: 0, heap_loc: value };
             }
         );
 
         let mut brent_st = BrentAlgState::new(hare);
 
         brent_st.power += 1; // advance a step.
-        brent_st.pstr_chars = pstr_chars;
+        brent_st.pstr_chars = char_count;
         brent_st.max_steps = max_steps as i64;
 
         loop {
@@ -513,6 +499,12 @@ enum MatchSite {
     Match(usize),          // a match
 }
 
+#[derive(Debug)]
+enum PStrSegmentCountResult {
+    Mid { char_count: usize, pstr_loc: usize },
+    End { char_count: usize, tail_loc: usize }
+}
+
 #[derive(Debug)]
 struct AttrListMatch {
     match_site: MatchSite,
@@ -539,24 +531,26 @@ impl MachineState {
         );
     }
 
-    pub(crate) fn get_attr_var_list(&mut self, attr_var: HeapCellValue) -> Option<usize> {
+    pub(crate) fn get_attr_var_list(&mut self, attr_var: HeapCellValue) -> Result<Option<usize>, usize> {
         read_heap_cell!(attr_var,
             (HeapCellValueTag::AttrVar, h) => {
-                Some(h + 1)
+                Ok(Some(h + 1))
             }
             (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
                 // create an AttrVar in the heap.
-                let h = self.heap.len();
+                let h = self.heap.cell_len();
+                let mut writer = self.heap.reserve(2)?;
 
-                self.heap.push(attr_var_as_cell!(h));
-                self.heap.push(heap_loc_as_cell!(h+1));
+                writer.write_with(|section| {
+                    section.push_cell(attr_var_as_cell!(h));
+                    section.push_cell(heap_loc_as_cell!(h+1));
+                });
 
                 self.bind(Ref::attr_var(h), attr_var);
-
-                Some(h + 1)
+                Ok(Some(h + 1))
             }
             _ => {
-                None
+                Ok(None)
             }
         )
     }
@@ -591,12 +585,13 @@ impl MachineState {
     }
 
     fn skip_max_list_cycle(&mut self, lam: usize) {
-        fn step(heap: &[HeapCellValue], mut value: HeapCellValue) -> usize {
+        fn step(heap: &Heap, mut value: HeapCellValue) -> usize {
             loop {
                 read_heap_cell!(value,
                     (HeapCellValueTag::PStrLoc, h) => {
-                        let (h_offset, _) = pstr_loc_and_offset(heap, h);
-                        return h_offset+1;
+                        let (_, tail) = heap.scan_slice_to_str(h);
+                        // let (h_offset, _) = pstr_loc_and_offset(heap, h);
+                        return tail;
                     }
                     (HeapCellValueTag::Lis, h) => {
                         return h+1;
@@ -614,13 +609,14 @@ impl MachineState {
             }
         }
 
-        let h = self.heap.len();
-        self.heap.push(self.registers[3]);
+        // let h = self.heap.cell_len();
+        // self.heap.push(self.registers[3]);
 
-        let mut hare = h;
+        let orig_hare = step(&self.heap, self.registers[3]);
+        let mut hare = orig_hare;
         let mut tortoise = hare;
 
-        for _ in 0..lam {
+        for _ in 1..lam {
             hare = step(&self.heap, self.heap[hare]);
         }
 
@@ -636,7 +632,7 @@ impl MachineState {
         // reached in the fashion of a C do-while loop since hare
         // may point to the beginning of a cycle.
 
-        let mut brent_st = BrentAlgState::new(h);
+        let mut brent_st = BrentAlgState::new(orig_hare);
 
         brent_st.cycle_step(&self.heap);
 
@@ -644,7 +640,7 @@ impl MachineState {
             brent_st.cycle_step(&self.heap);
         }
 
-        self.heap.pop();
+        // self.heap.pop_cell();
 
         let target_n = self.store(self.deref(self.registers[1]));
         self.unify_fixnum(Fixnum::build_with(brent_st.num_steps() as i64), target_n);
@@ -665,72 +661,45 @@ impl MachineState {
     }
 
     fn skip_max_list_result(&mut self, max_steps: i64) {
+        let cell = self.store(self.deref(self.registers[3]));
+
         let search_result = if max_steps == -1 {
-            BrentAlgState::detect_cycles(&self.heap, self.store(self.deref(self.registers[3])))
+            BrentAlgState::detect_cycles(&self.heap, cell)
         } else {
             BrentAlgState::detect_cycles_with_max(
                 &self.heap,
                 max_steps as usize,
-                self.store(self.deref(self.registers[3])),
+                cell
             )
         };
 
         match search_result {
-            CycleSearchResult::PStrLocation(steps, pstr_loc, offset) => {
+            CycleSearchResult::PStrLocation { num_steps, pstr_loc } => {
                 let steps = if max_steps > -1 {
-                    std::cmp::min(max_steps, steps as i64)
+                    std::cmp::min(max_steps, num_steps as i64)
                 } else {
-                    steps as i64
+                    max_steps as i64
                 };
 
-                let cell = if offset > 0 {
-                    let h = self.heap.len();
-                    let (pstr_loc, _) = pstr_loc_and_offset(&self.heap, pstr_loc);
-
-                    self.heap.push(pstr_offset_as_cell!(pstr_loc));
-                    self.heap
-                        .push(fixnum_as_cell!(Fixnum::build_with(offset as i64)));
-
-                    pstr_loc_as_cell!(h)
-                } else {
-                    pstr_loc_as_cell!(pstr_loc)
-                };
-
-                self.finalize_skip_max_list(steps, cell);
-            }
-            CycleSearchResult::UntouchedList(n, l) => {
-                self.finalize_skip_max_list(n as i64, list_loc_as_cell!(l));
+                self.finalize_skip_max_list(steps, pstr_loc); // cell);
             }
-            CycleSearchResult::UntouchedCStr(cstr_atom, n) => {
-                let cell = if n > 0 {
-                    let h = self.heap.len();
-
-                    self.heap.push(string_as_cstr_cell!(cstr_atom));
-                    self.heap.push(pstr_offset_as_cell!(h));
-                    self.heap
-                        .push(fixnum_as_cell!(Fixnum::build_with(n as i64)));
-
-                    pstr_loc_as_cell!(h + 1)
-                } else {
-                    string_as_cstr_cell!(cstr_atom)
-                };
-
-                self.finalize_skip_max_list(n as i64, cell);
+            CycleSearchResult::UntouchedList { num_steps, list_loc: l } => {
+                self.finalize_skip_max_list(num_steps as i64, list_loc_as_cell!(l));
             }
             CycleSearchResult::EmptyList => {
                 self.finalize_skip_max_list(0, empty_list_as_cell!());
             }
-            CycleSearchResult::PartialList(n, r) => {
-                self.finalize_skip_max_list(n as i64, r.as_heap_cell_value());
+            CycleSearchResult::PartialList { num_steps, heap_loc } => {
+                self.finalize_skip_max_list(num_steps as i64, heap_loc)
             }
-            CycleSearchResult::ProperList(steps) => {
-                self.finalize_skip_max_list(steps as i64, empty_list_as_cell!())
+            CycleSearchResult::ProperList { num_steps } => {
+                self.finalize_skip_max_list(num_steps as i64, empty_list_as_cell!())
             }
-            CycleSearchResult::NotList(n, value) => {
-                self.finalize_skip_max_list(n as i64, value);
+            CycleSearchResult::NotList { num_steps, heap_loc } => {
+                self.finalize_skip_max_list(num_steps as i64, heap_loc);
             }
-            CycleSearchResult::Cyclic(lam) => {
-                self.skip_max_list_cycle(lam);
+            CycleSearchResult::Cyclic { lambda } => {
+                self.skip_max_list_cycle(lambda);
             }
         };
     }
@@ -778,30 +747,33 @@ impl MachineState {
     ) {
         let mut seen_set = IndexSet::new();
 
-        let outcome = if term.is_ref() {
-            {
-                let mut iter = stackful_post_order_iter::<NonListElider>(
-                    &mut self.heap, &mut self.stack, term.get_value() as usize,
-                );
+        if term.is_ref() {
+            let mut iter = stackful_post_order_iter::<NonListElider>(
+                &mut self.heap, &mut self.stack, term.get_value() as usize,
+            );
 
-                while let Some(value) = iter.next() {
-                    if iter.parent_stack_len() >= max_depth {
-                        iter.pop_stack();
-                        continue;
-                    }
+            while let Some(value) = iter.next() {
+                if iter.parent_stack_len() >= max_depth {
+                    iter.pop_stack();
+                    continue;
+                }
 
-                    let value = unmark_cell_bits!(value);
+                let value = unmark_cell_bits!(value);
 
-                    if value.is_var() {
-                        seen_set.insert(value);
-                    }
+                if value.is_var() {
+                    seen_set.insert(value);
                 }
             }
+        }
 
-            heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter()))
-        } else {
-            empty_list_as_cell!()
-        };
+        let outcome = step_or_resource_error!(
+            self,
+            sized_iter_to_heap_list(
+                &mut self.heap,
+                seen_set.len(),
+                seen_set.into_iter(),
+            )
+        );
 
         unify_fn!(*self, list_of_vars, outcome);
     }
@@ -820,8 +792,8 @@ impl MachineState {
         &mut self,
         lh_offset: usize,
         copy_target: HeapCellValue,
-    ) -> usize {
-        let threshold = self.lifted_heap.len() - lh_offset;
+    ) -> Result<usize, usize> {
+        let threshold = self.lifted_heap.cell_len() - lh_offset;
 
         let mut copy_ball_term = CopyBallTerm::new(
             &mut self.attr_var_init.attr_var_queue,
@@ -830,13 +802,17 @@ impl MachineState {
             &mut self.lifted_heap,
         );
 
-        copy_ball_term.push(list_loc_as_cell!(threshold + 1));
-        copy_ball_term.push(heap_loc_as_cell!(threshold + 3));
-        copy_ball_term.push(heap_loc_as_cell!(threshold + 2));
+        let mut writer = copy_ball_term.reserve(3)?;
 
-        copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy);
+        writer.write_with(|section| {
+            section.push_cell(list_loc_as_cell!(threshold + 1));
+            section.push_cell(heap_loc_as_cell!(threshold + 3));
+            section.push_cell(heap_loc_as_cell!(threshold + 2));
+        });
+
+        copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy)?;
 
-        threshold + lh_offset + 2
+        Ok(threshold + lh_offset + 2)
     }
 
     #[inline(always)]
@@ -848,11 +824,14 @@ impl MachineState {
             (HeapCellValueTag::Fixnum, n) => {
                 let lh_offset = n.get_num() as usize;
 
-                if lh_offset >= self.lifted_heap.len() {
+                if lh_offset >= self.lifted_heap.cell_len() {
                     self.lifted_heap.truncate(lh_offset);
                 } else {
-                    let threshold = self.lifted_heap.len() - lh_offset;
-                    self.lifted_heap.push(addr_constr(threshold));
+                    let threshold = self.lifted_heap.cell_len() - lh_offset;
+                    step_or_resource_error!(
+                        self,
+                        self.lifted_heap.push_cell(addr_constr(threshold))
+                    );
                 }
             }
             _ => {
@@ -865,7 +844,7 @@ impl MachineState {
         &mut self,
         string: &str,
         indices: &IndexStore,
-        stub_gen: impl Fn() -> FunctorStub,
+        stub_gen: impl Fn() -> MachineStub,
     ) -> CallResult {
         use crate::parser::lexer::*;
 
@@ -883,14 +862,14 @@ impl MachineState {
             std::io::Cursor::new(dot_buf)
         });
 
-        let mut lexer = Lexer::new(CharReader::new(iter), self);
+        let mut lexer_parser = LexerParser::new(CharReader::new(iter), self);
         let mut tokens = vec![];
 
-        match lexer.next_token() {
-            Ok(token @ Token::Literal(Literal::Atom(atom!("-")) | Literal::Char('-'))) => {
+        match lexer_parser.next_token() {
+            Ok(token @ Token::Literal(atom)) if atom == atom_as_cell!(atom!("-")) => {
                 tokens.push(token);
 
-                if let Ok(token) = lexer.next_token() {
+                if let Ok(token) = lexer_parser.next_token() {
                     tokens.push(token);
                 }
             }
@@ -904,23 +883,16 @@ impl MachineState {
         }
 
         loop {
-            match lexer.lookahead_char() {
+            match lexer_parser.lookahead_char() {
                 Err(e) if e.is_unexpected_eof() => {
-                    let mut parser = Parser::from_lexer(lexer);
                     let op_dir = CompositeOpDir::new(&indices.op_dir, None);
 
                     tokens.reverse();
+                    let byte_size = heap_index!(tokens.len());
 
-                    match parser.read_term(&op_dir, Tokens::Provided(tokens)) {
+                    match lexer_parser.read_term(&op_dir, Tokens::Provided(tokens, byte_size)) {
                         Ok(term) => {
-                            let mut error_gen = || {
-                                let e = ParserError::ParseBigInt(ParserErrorSrc::default());
-                                let e = self.syntax_error(e);
-
-                                return Err(self.error_form(e, stub_gen()));
-                            };
-
-                            read_heap_cell!(term.heap[term.focus],
+                            read_heap_cell!(lexer_parser.machine_st.heap[term.focus],
                                 (HeapCellValueTag::Cons, c) => {
                                     match_untyped_arena_ptr!(c,
                                        (ArenaHeaderTag::Rational, n) => {
@@ -930,7 +902,10 @@ impl MachineState {
                                            self.unify_big_int(n, nx);
                                        }
                                        _ => {
-                                           return error_gen();
+                                           let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src());
+                                           let e = self.syntax_error(e);
+
+                                           return Err(self.error_form(e, stub_gen()));
                                        }
                                     )
                                 }
@@ -941,23 +916,26 @@ impl MachineState {
                                     self.unify_fixnum(n, nx);
                                 }
                                 _ => {
-                                    return error_gen();
+                                    let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src());
+                                    let e = self.syntax_error(e);
+
+                                    return Err(self.error_form(e, stub_gen()));
                                 }
                             );
+
+                            return Ok(());
                         }
                         Err(e) => {
                             let e = self.syntax_error(e);
                             return Err(self.error_form(e, stub_gen()));
                         }
                     }
-
-                    break;
                 }
                 Ok('.') => {
-                    lexer.skip_char('.');
+                    lexer_parser.skip_char('.');
                 }
                 Ok(c) => {
-                    let err_src = lexer.loc_to_err_src();
+                    let err_src = lexer_parser.loc_to_err_src();
 
                     let err = ParserError::UnexpectedChar(c, err_src);
                     let err = self.syntax_error(err);
@@ -967,8 +945,6 @@ impl MachineState {
                 Err(_) => unreachable!(),
             }
         }
-
-        Ok(())
     }
 
     pub(crate) fn call_continuation_chunk(
@@ -1020,6 +996,7 @@ impl MachineState {
 
     pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option<AtomOrString> {
         read_heap_cell!(value,
+            /*
             (HeapCellValueTag::CStr, cstr_atom) => {
                 // avoid allocating a String if possible:
                 // We must be careful to preserve the string "[]" as is,
@@ -1030,6 +1007,7 @@ impl MachineState {
                     Some(AtomOrString::Atom(cstr_atom))
                 }
             }
+            */
             (HeapCellValueTag::Atom, (atom, arity)) => {
                 if arity == 0 {
                     // ... likewise.
@@ -1048,27 +1026,23 @@ impl MachineState {
                     None
                 }
             }
-            (HeapCellValueTag::Char, c) => {
-                Some(AtomOrString::String(c.to_string()))
-            }
             _ => {
                 if value.is_constant() {
                     return None;
                 }
 
-                let h = self.heap.len();
-                self.heap.push(value);
+                // 0 is reserved for use by the machine. See
+                // MachineState::new.
+                self.heap[0] = value;
 
-                let mut iter = HeapPStrIter::new(&self.heap, h);
+                let mut iter = HeapPStrIter::new(&self.heap, 0);
                 let string = iter.to_string_mut();
-                let at_terminator = iter.at_string_terminator();
-
-                self.heap.pop();
+                let end_cell = iter.heap[iter.focus()];
 
                 // if the iteration doesn't terminate like a string
                 // (i.e. with the [] atom or a CStr), it is not
                 // "str_like" so return None.
-                if at_terminator {
+                if end_cell.is_string_terminator(iter.heap) {
                     Some(AtomOrString::String(string))
                 } else {
                     None
@@ -1080,7 +1054,7 @@ impl MachineState {
     pub(crate) fn codes_to_string(
         &mut self,
         addrs: impl Iterator<Item = HeapCellValue>,
-        stub_gen: impl Fn() -> FunctorStub,
+        stub_gen: impl Fn() -> MachineStub,
     ) -> Result<String, MachineStub> {
         let mut string = String::new();
 
@@ -1237,7 +1211,7 @@ impl Machine {
                             boip + extract_ptr!(hm.get(&key).cloned().unwrap())
                         }
                         IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => {
-                            boip + extract_ptr!(hm.get(&Literal::Atom(key.0)).cloned().unwrap())
+                            boip + extract_ptr!(hm.get(&atom_as_cell!(key.0)).cloned().unwrap())
                         }
                         _ => boip,
                     };
@@ -1274,6 +1248,7 @@ impl Machine {
                     }
                 }
                 &Instruction::RevJmpBy(offset) => {
+
                     bp -= offset;
                 }
                 _ => {
@@ -1332,8 +1307,12 @@ impl Machine {
             (HeapCellValueTag::Str, s) => {
                 let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity();
 
-                (name, arity, if self.machine_st.heap.len() > s + arity + 1 {
-                    get_structure_index(self.machine_st.heap[s + arity + 1])
+                (name, arity, if self.machine_st.heap.cell_len() > s + arity + 1 {
+                    if !self.machine_st.heap.pstr_at(s + arity + 1) {
+                        get_structure_index(self.machine_st.heap[s + arity + 1])
+                    } else {
+                        None
+                    }
                 } else {
                     None
                 })
@@ -1398,10 +1377,9 @@ impl Machine {
                 .get_predicate_code_index(name, arity, module_name)
         });
 
-        // println!("(fast) calling {}/{}", name.as_str(), arity);
-
         if let Some(code_index) = index_cell {
             if !code_index.is_undefined() {
+                // println!("(fast) calling {}/{}", name.as_str(), arity);
                 load_registers(&mut self.machine_st, goal, goal_arity);
                 self.machine_st.neck_cut();
                 return call_at_index(self, name, arity, code_index.get());
@@ -1454,9 +1432,7 @@ impl Machine {
                     // disjoint from them. if they are not, the
                     // expanded goal is not simple.
 
-                    let post_supp_args = self.machine_st.heap[s+arity-supp_vars.len()+1 .. s+arity+1]
-                        .iter()
-                        .cloned();
+                    let post_supp_args = self.machine_st.heap.splice(s+arity-supp_vars.len()+1 .. s+arity+1);
 
                     post_supp_args
                         .zip(supp_vars.iter())
@@ -1480,16 +1456,20 @@ impl Machine {
                 };
 
                 let goal = if is_simple_goal {
-                    let h = self.machine_st.heap.len();
+                    let h = self.machine_st.heap.cell_len();
                     let arity = arity - supp_vars.len();
 
-                    for idx in 0 .. arity + 1 {
-                        let value = self.machine_st.heap[s + idx];
-                        self.machine_st.heap.push(value);
-                    }
+                    resource_error_call_result!(
+                        self.machine_st,
+                        self.machine_st.heap.copy_slice_to_end(
+                            s .. s + arity + 1
+                        )
+                    );
 
                     self.machine_st.heap[h] = atom_as_cell!(name, arity);
 
+                    // even if arity == 0, goal must be a Str cell,
+                    // since an index is about to appended to it.
                     str_loc_as_cell!(h)
                 } else {
                     goal
@@ -1505,8 +1485,11 @@ impl Machine {
             (HeapCellValueTag::Atom, (name, arity)) => {
                 debug_assert_eq!(arity, 0);
 
-                let h = self.machine_st.heap.len();
-                self.machine_st.heap.push(goal);
+                let h = self.machine_st.heap.cell_len();
+                resource_error_call_result!(
+                    self.machine_st,
+                    self.machine_st.heap.push_cell(goal)
+                );
 
                 GoalAnalysisResult {
                     is_simple_goal: true,
@@ -1515,11 +1498,15 @@ impl Machine {
                     supp_vars,
                 }
             }
+            /*
             (HeapCellValueTag::Char, c) => {
                 let name = AtomTable::build_with(&self.machine_st.atom_tbl,&c.to_string());
+                let h = self.machine_st.heap.cell_len();
 
-                let h = self.machine_st.heap.len();
-                self.machine_st.heap.push(atom_as_cell!(name));
+                resource_error_call_result!(
+                    self.machine_st,
+                    self.machine_st.heap.push_cell(atom_as_cell!(name))
+                );
 
                 GoalAnalysisResult {
                     is_simple_goal: true,
@@ -1528,6 +1515,7 @@ impl Machine {
                     supp_vars,
                 }
             }
+            */
             _ => {
                 self.machine_st.fail = true;
                 return Ok(());
@@ -1541,9 +1529,14 @@ impl Machine {
 
         let expanded_term = if result.is_simple_goal {
             let idx = self.get_or_insert_qualified_code_index(module_name, result.key);
-            self.machine_st
-                .heap
-                .push(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)));
+
+            resource_error_call_result!(
+                self.machine_st,
+                self.machine_st
+                    .heap
+                    .push_cell(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)))
+            );
+
             result.goal
         } else {
             let mut unexpanded_vars = IndexSet::with_hasher(FxBuildHasher::default());
@@ -1566,20 +1559,26 @@ impl Machine {
                 Err(e) => {
                     let err = self.machine_st.session_error(e);
                     let stub = functor_stub(atom!("call"), result.key.1);
-
                     return Err(self.machine_st.error_form(err, stub));
                 }
                 Ok(()) => {
-                    let h = self.machine_st.heap.len();
+                    let h = self.machine_st.heap.cell_len();
+                    let mut writer = resource_error_call_result!(
+                        self.machine_st,
+                        self.machine_st.heap.reserve(unexpanded_vars.len() + 2)
+                    );
 
-                    self.machine_st.heap.push(atom_as_cell!(atom!("$aux"), 0));
+                    writer.write_with(|section| {
+                        section.push_cell(atom_as_cell!(atom!("$aux"), 0));
 
-                    for value in unexpanded_vars.difference(&result.supp_vars).cloned() {
-                        self.machine_st.heap.push(value);
-                    }
+                        for value in unexpanded_vars.difference(&result.supp_vars).cloned() {
+                            section.push_cell(value);
+                        }
 
-                    let anon_str_arity = self.machine_st.heap.len() - h - 1;
+                        section.push_cell(atom_as_cell!(atom!("[]")));
+                    });
 
+                    let anon_str_arity = self.machine_st.heap.cell_len() - h - 2;
                     self.machine_st.heap[h] = atom_as_cell!(atom!("$aux"), anon_str_arity);
 
                     let idx = CodeIndex::new(
@@ -1587,9 +1586,9 @@ impl Machine {
                         &mut self.machine_st.arena,
                     );
 
-                    self.machine_st
-                        .heap
-                        .push(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)));
+                    self.machine_st.heap.last_cell_mut().map(|cell| {
+                        *cell = untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx));
+                    });
 
                     str_loc_as_cell!(h)
                 }
@@ -1606,17 +1605,25 @@ impl Machine {
     pub(crate) fn is_expanded_or_inlined(&self) -> bool {
         let (_module_loc, qualified_goal) = self
             .machine_st
-            .strip_module(self.machine_st.registers[1], empty_list_as_cell!());
+            .strip_module(
+                self.machine_st.registers[1],
+                empty_list_as_cell!(),
+            );
 
         if HeapCellValueTag::Str == qualified_goal.get_tag() {
             let s = qualified_goal.get_value() as usize;
-            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!("$call") {
                 return false;
             }
 
-            if self.machine_st.heap.len() > s + 1 + arity {
+            if self.machine_st.heap.cell_len() > s + 1 + arity {
+                if self.machine_st.heap.pstr_at(s + 1 + arity) {
+                    return false;
+                }
+
                 let idx_cell = self.machine_st.heap[s + 1 + arity];
 
                 if HeapCellValueTag::Cons == idx_cell.get_tag() {
@@ -1641,11 +1648,9 @@ impl Machine {
             .strip_module(self.machine_st.registers[1], self.machine_st.registers[2]);
 
         let target_module_loc = self.machine_st.registers[2];
-
         unify_fn!(&mut self.machine_st, module_loc, target_module_loc);
 
         let target_qualified_goal = self.machine_st.registers[3];
-
         unify_fn!(&mut self.machine_st, qualified_goal, target_qualified_goal);
     }
 
@@ -1666,21 +1671,24 @@ impl Machine {
         let target_goal = if arity == 0 {
             qualified_goal
         } else {
-            // if narity + arity > 0 {
-            let h = self.machine_st.heap.len();
-            self.machine_st
-                .heap
-                .push(atom_as_cell!(name, narity + arity));
+            let h = self.machine_st.heap.cell_len();
 
-            for idx in 1..narity + 1 {
-                self.machine_st.heap.push(self.machine_st.heap[s + idx]);
-            }
+            let mut writer = resource_error_call_result!(
+                self.machine_st,
+                self.machine_st.heap.reserve(1 + narity + arity)
+            );
 
-            for idx in 1..arity + 1 {
-                self.machine_st
-                    .heap
-                    .push(self.machine_st.registers[2 + idx]);
-            }
+            writer.write_with(|section| {
+                section.push_cell(atom_as_cell!(name, narity + arity));
+
+                for idx in 1..narity + 1 {
+                    section.push_cell(section[s + idx]);
+                }
+
+                for idx in 1..arity + 1 {
+                    section.push_cell(self.machine_st.registers[2 + idx]);
+                }
+            });
 
             if narity + arity > 0 {
                 str_loc_as_cell!(h)
@@ -1690,9 +1698,7 @@ impl Machine {
         };
 
         let target_qualified_goal = self.machine_st.registers[1];
-
         unify_fn!(&mut self.machine_st, target_goal, target_qualified_goal);
-
         Ok(())
     }
 
@@ -1723,12 +1729,9 @@ impl Machine {
                 }
             }
             _ => {
-                let h = self.machine_st.heap.len();
-                let call_form = functor!(atom!(":"), [cell(module_name), cell(self.machine_st.registers[2])]);
-                self.machine_st.heap.extend(call_form);
-
+                let call_form = functor!(atom!(":"), [cell(module_name), cell((self.machine_st.registers[2]))]);
                 let stub = functor_stub(atom!("call"), narity + 1);
-                let err = self.machine_st.type_error(ValidType::Callable, str_loc_as_cell!(h));
+                let err = self.machine_st.type_error(ValidType::Callable, call_form);
                 return Err(self.machine_st.error_form(err, stub));
             }
         );
@@ -1903,9 +1906,12 @@ impl Machine {
                 for entry in entries {
                     if let Ok(entry) = entry {
                         if let Some(name) = entry.file_name().to_str() {
-                            let name = AtomTable::build_with(&self.machine_st.atom_tbl, name);
-                            files.push(atom_as_cstr_cell!(name));
+                            let file_string_cell = resource_error_call_result!(
+                                self.machine_st,
+                                self.machine_st.allocate_cstr(name)
+                            );
 
+                            files.push(file_string_cell);
                             continue;
                         }
                     }
@@ -1917,12 +1923,16 @@ impl Machine {
                     return Err(err);
                 }
 
-                let files_list = heap_loc_as_cell!(iter_to_heap_list(
-                    &mut self.machine_st.heap,
-                    files.into_iter()
-                ));
+                let files_list_cell = resource_error_call_result!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        files.len(),
+                        files.into_iter()
+                    )
+                );
 
-                unify!(self.machine_st, self.machine_st.registers[2], files_list);
+                unify!(self.machine_st, self.machine_st.registers[2], files_list_cell);
                 return Ok(());
             }
         }
@@ -2009,11 +2019,14 @@ impl Machine {
                         unreachable!()
                     }
                 } {
-                    let chars_atom = self.systemtime_to_timestamp(time);
+                    let chars_string = self.systemtime_to_timestamp(time);
 
-                    self.machine_st
-                        .unify_complete_string(chars_atom, self.machine_st.registers[3]);
+                    let cstr_cell = step_or_resource_error!(
+                        self.machine_st,
+                        self.machine_st.allocate_cstr(&chars_string)
+                    );
 
+                    unify!(self.machine_st, cstr_cell, self.machine_st.registers[3]);
                     return;
                 }
             }
@@ -2144,10 +2157,12 @@ impl Machine {
                 }
             };
 
-            let current_atom = AtomTable::build_with(&self.machine_st.atom_tbl, current);
+            let current_string = resource_error_call_result!(
+                self.machine_st,
+                self.machine_st.allocate_cstr(current)
+            );
 
-            let a1 = self.deref_register(1);
-            self.machine_st.unify_complete_string(current_atom, a1);
+            unify!(self.machine_st, current_string, self.machine_st.registers[1]);
 
             if self.machine_st.fail {
                 return Ok(());
@@ -2184,11 +2199,12 @@ impl Machine {
                     }
                 };
 
-                let canonical_atom = AtomTable::build_with(&self.machine_st.atom_tbl, cs);
-
-                let a2 = self.deref_register(2);
-                self.machine_st.unify_complete_string(canonical_atom, a2);
+                let canonical_string = resource_error_call_result!(
+                    self.machine_st,
+                    self.machine_st.allocate_cstr(cs)
+                );
 
+                unify!(self.machine_st, canonical_string, self.machine_st.registers[2]);
                 return Ok(());
             }
         }
@@ -2200,39 +2216,38 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn atom_chars(&mut self) {
         let a1 = self.deref_register(1);
-        let a2 = self.deref_register(2);
 
         read_heap_cell!(a1,
+            /*
             (HeapCellValueTag::Char) => {
-                let h = self.machine_st.heap.len();
+                let h = self.machine_st.heap.cell_len();
 
-                self.machine_st.heap.push(a1);
-                self.machine_st.heap.push(empty_list_as_cell!());
+                let mut writer = resource_error_call_result!(
+                    self.machine_st,
+                    self.machine_st.heap.reserve(2)
+                );
 
-                unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h));
-            }
-            (HeapCellValueTag::Str, s) => {
-                let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
-                    .get_name_and_arity();
+                step_or_resource_error!(
+                    self.machine_st,
+                    writer.write_with(|section| {
+                        section.push_cell(a1);
+                        section.push_cell(empty_list_as_cell!());
+                        Ok::<(), usize>(())
+                    })
+                );
 
-                if arity == 0 {
-                    self.machine_st.unify_complete_string(
-                        name,
-                        a2,
-                    );
-                } else {
-                    self.machine_st.fail = true;
-                }
+                unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h));
             }
+            */
             (HeapCellValueTag::Atom, (name, arity)) => {
-                if arity == 0 {
-                    self.machine_st.unify_complete_string(
-                        name,
-                        a2,
-                    );
-                } else {
-                    self.machine_st.fail = true;
-                }
+                debug_assert_eq!(arity, 0);
+
+                let cell = step_or_resource_error!(
+                    self.machine_st,
+                    self.machine_st.allocate_cstr(&*name.as_str())
+                );
+
+                unify!(self.machine_st, self.machine_st.registers[2], cell);
             }
             (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
                 let a2 = self.deref_register(2);
@@ -2258,7 +2273,7 @@ impl Machine {
                 self.machine_st.fail = true;
             }
             _ => {
-                unreachable!();
+                self.machine_st.fail = true;
             }
         );
     }
@@ -2268,6 +2283,7 @@ impl Machine {
         let a1 = self.deref_register(1);
 
         read_heap_cell!(a1,
+            /*
             (HeapCellValueTag::Char, c) => {
                 let h = self.machine_st.heap.len();
 
@@ -2276,33 +2292,50 @@ impl Machine {
 
                 unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]);
             }
+            */
             (HeapCellValueTag::Atom, (name, arity)) => {
-                if arity == 0 {
-                    let name = name.as_str();
-                    let iter = name.chars()
-                        .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
+                debug_assert_eq!(arity, 0);
 
-                    let h = iter_to_heap_list(&mut self.machine_st.heap, iter);
-                    unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]);
-                } else {
-                    self.machine_st.fail = true;
-                }
+                let name = name.as_str();
+                let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
+
+                let list_cell = resource_error_call_result!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        (&*name).chars().count(),
+                        iter,
+                    )
+                );
+
+                unify!(self.machine_st, list_cell, self.machine_st.registers[2]);
             }
+            /*
             (HeapCellValueTag::Str, s) => {
+                /*
                 let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
                     .get_name_and_arity();
 
                 if arity == 0 {
                     let name = name.as_str();
-                    let iter = name.chars()
-                        .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
+                    let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
+
+                    let list_cell = resource_error_call_result!(
+                        self.machine_st,
+                        sized_iter_to_heap_list(
+                            &mut self.machine_st.heap,
+                            name.as_str().chars().count(),
+                            iter,
+                        )
+                    );
 
-                    let h = iter_to_heap_list(&mut self.machine_st.heap, iter);
-                    unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]);
+                    unify!(self.machine_st, list_cell, self.machine_st.registers[2]);
                 } else {
-                    self.machine_st.fail = true;
-                }
+                */
+                self.machine_st.fail = true;
+                // }
             }
+            */
             (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
                 let stub_gen = || functor_stub(atom!("atom_codes"), 2);
 
@@ -2350,9 +2383,11 @@ impl Machine {
                     return;
                 }
             }
+            /*
             (HeapCellValueTag::Char) => {
                 1
             }
+            */
             _ => {
                 unreachable!()
             }
@@ -2406,20 +2441,27 @@ impl Machine {
             return;
         }
 
-        let pstr_h = self.machine_st.heap.len();
+        let pstr_h = self.machine_st.heap.cell_len();
+
+        let pstr_loc_cell = step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.allocate_pstr(&*atom.as_str())
+        );
 
-        self.machine_st.heap.push(pstr_as_cell!(atom));
-        self.machine_st.heap.push(heap_loc_as_cell!(pstr_h + 1));
+        let tail_loc = Heap::neighboring_cell_offset(
+            atom.as_str().len() + heap_index!(pstr_h),
+        );
 
-        unify!(
+        step_or_resource_error!(
             self.machine_st,
-            self.machine_st.registers[2],
-            pstr_loc_as_cell!(pstr_h)
+            self.machine_st.heap.push_cell(heap_loc_as_cell!(tail_loc))
         );
 
+        unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_cell);
+
         if !self.machine_st.fail {
             let tail = self.machine_st.registers[3];
-            unify!(self.machine_st, tail, heap_loc_as_cell!(pstr_h + 1));
+            unify!(self.machine_st, tail, heap_loc_as_cell!(tail_loc));
         }
     }
 
@@ -2427,17 +2469,21 @@ impl Machine {
     pub(crate) fn is_partial_string(&mut self) {
         let value = self.deref_register(1);
 
-        let h = self.machine_st.heap.len();
-        self.machine_st.heap.push(value);
-
-        let mut iter = HeapPStrIter::new(&self.machine_st.heap, h);
+        if value.is_constant() {
+            self.machine_st.fail = empty_list_as_cell!() != value;
+        } else {
+            self.machine_st.heap[0] = value;
+            let mut iter = HeapPStrIter::new(&self.machine_st.heap, 0);
 
-        for _ in iter.by_ref() {}
+            for _ in iter.by_ref() {}
 
-        let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator();
-        self.machine_st.fail = !at_end_of_pstr;
+            let focus = iter.focus();
+            let end_cell = self.machine_st.heap[focus];
+            let at_end_of_pstr = end_cell.is_var() ||
+                end_cell.is_string_terminator(&self.machine_st.heap);
 
-        self.machine_st.heap.pop();
+            self.machine_st.fail = !at_end_of_pstr;
+        }
     }
 
     #[inline(always)]
@@ -2447,26 +2493,8 @@ impl Machine {
 
         read_heap_cell!(pstr,
             (HeapCellValueTag::PStrLoc, h) => {
-                let (h, _) = pstr_loc_and_offset(&self.machine_st.heap, h);
-
-                if HeapCellValueTag::CStr == self.machine_st.heap[h].get_tag() {
-                    self.machine_st.unify_atom(
-                        atom!("[]"),
-                        a2
-                    );
-                } else {
-                    unify_fn!(
-                        self.machine_st,
-                        heap_loc_as_cell!(h+1),
-                        a2
-                    );
-                }
-            }
-            (HeapCellValueTag::CStr) => {
-                self.machine_st.unify_atom(
-                    atom!("[]"),
-                    a2
-                );
+                let (_, tail_loc) = self.machine_st.heap.scan_slice_to_str(h);
+                unify_fn!(self.machine_st, heap_loc_as_cell!(tail_loc), a2);
             }
             (HeapCellValueTag::Lis, h) => {
                 unify_fn!(
@@ -2608,9 +2636,11 @@ impl Machine {
         }
 
         let a2 = read_heap_cell!(a2,
+            /*
             (HeapCellValueTag::Char) => {
                 a2
             }
+            */
             (HeapCellValueTag::Atom, (name, arity)) => {
                 if arity == 0 {
                     if let Some(c) = name.as_char() {
@@ -2790,8 +2820,12 @@ impl Machine {
             }
         };
 
-        let chars_atom = AtomTable::build_with(&self.machine_st.atom_tbl, string.trim());
-        self.machine_st.unify_complete_string(chars_atom, chs);
+        let cstr_cell = step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.allocate_cstr(string.trim())
+        );
+
+        unify!(self.machine_st, cstr_cell, chs);
     }
 
     #[inline(always)]
@@ -2821,8 +2855,16 @@ impl Machine {
             .chars()
             .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
 
-        let h = iter_to_heap_list(&mut self.machine_st.heap, codes);
-        unify!(self.machine_st, heap_loc_as_cell!(h), chs);
+        let list_cell = step_or_resource_error!(
+            self.machine_st,
+            sized_iter_to_heap_list(
+                &mut self.machine_st.heap,
+                string.trim().chars().count(),
+                codes,
+            )
+        );
+
+        unify!(self.machine_st, list_cell, chs);
     }
 
     #[inline(always)]
@@ -2854,7 +2896,7 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn lifted_heap_length(&mut self) {
         let a1 = self.machine_st.registers[1];
-        let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.len() as i64);
+        let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.cell_len() as i64);
 
         self.machine_st.unify_fixnum(lh_len, a1);
     }
@@ -2876,9 +2918,11 @@ impl Machine {
                 debug_assert_eq!(arity, 0);
                 name.as_char().unwrap()
             }
+            /*
             (HeapCellValueTag::Char, c) => {
                 c
             }
+            */
             _ => {
                 match Number::try_from(a2) {
                     Ok(Number::Integer(n)) => {
@@ -2926,9 +2970,11 @@ impl Machine {
         let a2 = self.deref_register(2);
 
         let c = read_heap_cell!(a1,
+            /*
             (HeapCellValueTag::Char, c) => {
                 c
             }
+            */
             (HeapCellValueTag::Atom, (name, _arity)) => {
                 name.as_char().unwrap()
             }
@@ -3014,14 +3060,19 @@ impl Machine {
                 match (name, arity) {
                     (atom!("upper"), 1) => {
                         let reg = self.machine_st.deref(self.machine_st.heap[s+1]);
-                        let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_uppercase().to_string());
-                        let upper_str = string_as_cstr_cell!(atom);
+                        let upper_str = step_or_resource_error!(
+                            self.machine_st,
+                            self.machine_st.allocate_cstr(&c.to_uppercase().to_string())
+                        );
                         unify!(self.machine_st, reg, upper_str);
                     }
                     (atom!("lower"), 1) => {
                         let reg = self.machine_st.deref(self.machine_st.heap[s+1]);
-                        let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_lowercase().to_string());
-                        let lower_str = string_as_cstr_cell!(atom);
+                        let lower_str = step_or_resource_error!(
+                            self.machine_st,
+                            self.machine_st.allocate_cstr(&c.to_uppercase().to_string())
+                        );
+
                         unify!(self.machine_st, reg, lower_str);
                     }
                     _ => {
@@ -3069,10 +3120,10 @@ impl Machine {
                     unify_fn!(self.machine_st, addr, *value_loc);
                 }
                 None if !ball.stub.is_empty() => {
-                    let h = self.machine_st.heap.len();
-                    let stub = ball.copy_and_align(h);
-
-                    self.machine_st.heap.extend(stub);
+                    let h = step_or_resource_error!(
+                        self.machine_st,
+                        ball.copy_and_align_to(&mut self.machine_st.heap)
+                    );
 
                     unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h));
 
@@ -3170,10 +3221,12 @@ impl Machine {
                         return Ok(());
                     }
                 }
+                /*
                 (HeapCellValueTag::Char, c) => {
                     write!(&mut stream, "{}", c).unwrap();
                     return Ok(());
                 }
+                */
                 _ => {
                 }
             );
@@ -3428,9 +3481,11 @@ impl Machine {
                 (HeapCellValueTag::Atom, (atom, _arity)) => {
                     char_as_cell!(atom.as_char().unwrap())
                 }
+                /*
                 (HeapCellValueTag::Char) => {
                     addr
                 }
+                */
                 _ => {
                     let err = self.machine_st.type_error(ValidType::InCharacter, addr);
                     return Err(self.machine_st.error_form(err, stub_gen()));
@@ -3544,9 +3599,12 @@ impl Machine {
         };
 
         let output = self.deref_register(3);
-        let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &string);
+        let cstr_cell = resource_error_call_result!(
+            self.machine_st,
+            self.machine_st.allocate_cstr(&string)
+        );
 
-        self.machine_st.unify_complete_string(atom, output);
+        unify!(self.machine_st, cstr_cell, output);
         Ok(())
     }
 
@@ -3860,18 +3918,18 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn copy_to_lifted_heap(&mut self) {
         let lh_offset = cell_as_fixnum!(self.deref_register(1)).get_num() as usize;
-
         let copy_target = self.machine_st.registers[2];
+        let old_threshold = step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.copy_findall_solution(lh_offset, copy_target)
+        );
 
-        let old_threshold = self
-            .machine_st
-            .copy_findall_solution(lh_offset, copy_target);
-        let new_threshold = self.machine_st.lifted_heap.len() - lh_offset;
+        let new_threshold = self.machine_st.lifted_heap.cell_len() - lh_offset;
 
         self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold);
 
-        for addr in self.machine_st.lifted_heap[old_threshold + 1..].iter_mut() {
-            *addr -= self.machine_st.heap.len() + lh_offset;
+        for addr in &mut self.machine_st.lifted_heap.splice_mut(old_threshold + 1..) {
+            *addr -= self.machine_st.heap.cell_len() + lh_offset;
         }
     }
 
@@ -3956,7 +4014,7 @@ impl Machine {
             }
         };
 
-        let h = self.machine_st.heap.len();
+        let h = self.machine_st.heap.cell_len();
         let mut num_functors = 0;
 
         let code_dir = if module_name == atom!("user") {
@@ -3976,51 +4034,53 @@ impl Machine {
             }
         };
 
-        for (name, arity) in code_dir.keys() {
-            if self.indices.builtin_property((*name, *arity)) {
+        for (name, arity) in code_dir.keys().cloned() {
+            if self.indices.builtin_property((name, arity)) {
                 continue;
             }
 
-            if name_match(pred_atom, *name) && arity_match(pred_arity, *arity) {
-                self.machine_st.heap.extend(functor!(
+            if name_match(pred_atom, name) && arity_match(pred_arity, arity) {
+                let functor = functor!(
                     atom!("/"),
-                    [cell(atom_as_cell!(name)), fixnum(*arity)]
-                ));
+                    [atom_as_cell(name), fixnum(arity)]
+                ); // self.machine_st.heap.extend(
+
+                let mut functor_writer = Heap::functor_writer(functor);
+
+                step_or_resource_error!(
+                    self.machine_st,
+                    functor_writer(&mut self.machine_st.heap)
+                );
 
                 num_functors += 1;
             }
         }
 
-        if num_functors > 0 {
-            let h = iter_to_heap_list(
+        let functor_list_cell = step_or_resource_error!(
+            self.machine_st,
+            sized_iter_to_heap_list(
                 &mut self.machine_st.heap,
-                (0..num_functors).map(|i| str_loc_as_cell!(h + 3 * i)),
-            );
+                num_functors,
+                (0..num_functors).map(|i| str_loc_as_cell!(h + 3 * i))
+            )
+        );
 
-            unify!(
-                self.machine_st,
-                heap_loc_as_cell!(h),
-                self.machine_st.registers[4]
-            );
-        } else {
-            unify!(
-                self.machine_st,
-                empty_list_as_cell!(),
-                self.machine_st.registers[4]
-            );
-        }
+        unify!(
+            self.machine_st,
+            functor_list_cell,
+            self.machine_st.registers[4]
+        );
     }
 
     #[inline(always)]
     pub(crate) fn get_next_op_db_ref(&mut self) {
         let prec = self.deref_register(1);
-
-        let h = self.machine_st.heap.len();
+        let h = self.machine_st.heap.cell_len();
 
         fn write_op_functors_to_heap(
             heap: &mut Heap,
             op_descs: impl Iterator<Item = (Atom, OpDesc)>,
-        ) -> usize {
+        ) -> Result<usize, usize> {
             let mut num_functors = 0;
 
             for (name, op_desc) in op_descs {
@@ -4033,19 +4093,25 @@ impl Machine {
 
                 let spec_atom = op_desc.get_spec().get_spec();
 
-                heap.extend(functor!(
+                let functor = functor!(
                     atom!("op"),
                     [
                         fixnum(prec),
-                        cell(atom_as_cell!(spec_atom)),
-                        cell(atom_as_cell!(name))
+                        atom_as_cell(spec_atom),
+                        atom_as_cell(name)
                     ]
-                ));
+                );
+
+                let mut functor_writer = Heap::functor_writer(functor);
+
+                if let Err(e) = functor_writer(heap) {
+                    return Err(e);
+                }
 
                 num_functors += 1;
             }
 
-            num_functors
+            Ok(num_functors)
         }
 
         if prec.is_var() {
@@ -4071,9 +4137,11 @@ impl Machine {
                     (HeapCellValueTag::Str, s) => {
                         cell_as_atom!(self.machine_st.heap[s])
                     }
+                    /*
                     (HeapCellValueTag::Char, c) => {
                         AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_string())
                     }
+                    */
                     _ => {
                         unreachable!()
                     }
@@ -4096,17 +4164,26 @@ impl Machine {
                 if number_of_keys == 0 {
                     self.machine_st.fail = true;
                 } else {
-                    let num_functors =
-                        write_op_functors_to_heap(&mut self.machine_st.heap, op_descs);
+                    let num_functors = step_or_resource_error!(
+                        self.machine_st,
+                        write_op_functors_to_heap(
+                            &mut self.machine_st.heap,
+                            op_descs,
+                        )
+                    );
 
-                    let h = iter_to_heap_list(
-                        &mut self.machine_st.heap,
-                        (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)),
+                    let functor_list_cell = step_or_resource_error!(
+                        self.machine_st,
+                        sized_iter_to_heap_list(
+                            &mut self.machine_st.heap,
+                            num_functors,
+                            (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i))
+                        )
                     );
 
                     unify!(
                         self.machine_st,
-                        heap_loc_as_cell!(h),
+                        functor_list_cell,
                         self.machine_st.registers[4]
                     );
                 }
@@ -4131,23 +4208,28 @@ impl Machine {
                     Some((key.0, *op_desc))
                 });
 
-                write_op_functors_to_heap(&mut self.machine_st.heap, op_descs)
+                step_or_resource_error!(
+                    self.machine_st,
+                    write_op_functors_to_heap(
+                        &mut self.machine_st.heap,
+                        op_descs,
+                    )                )
             };
 
-            if num_functors > 0 {
-                let h = iter_to_heap_list(
+            let functor_list_cell = step_or_resource_error!(
+                self.machine_st,
+                sized_iter_to_heap_list(
                     &mut self.machine_st.heap,
+                    num_functors,
                     (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)),
-                );
+                )
+            );
 
-                unify!(
-                    self.machine_st,
-                    heap_loc_as_cell!(h),
-                    self.machine_st.registers[4]
-                );
-            } else {
-                self.machine_st.fail = true;
-            }
+            unify!(
+                self.machine_st,
+                functor_list_cell,
+                self.machine_st.registers[4]
+            );
         } else {
             let spec = cell_as_atom!(self.deref_register(2));
             let op_atom = cell_as_atom!(self.deref_register(3));
@@ -4164,19 +4246,26 @@ impl Machine {
 
             match self.indices.op_dir.get(&(op_atom, fixity)).cloned() {
                 Some(op_desc) => {
-                    let num_functors = write_op_functors_to_heap(
-                        &mut self.machine_st.heap,
-                        std::iter::once((op_atom, op_desc)),
+                    let num_functors = step_or_resource_error!(
+                        self.machine_st,
+                        write_op_functors_to_heap(
+                            &mut self.machine_st.heap,
+                            std::iter::once((op_atom, op_desc))
+                        )
                     );
 
-                    let h = iter_to_heap_list(
-                        &mut self.machine_st.heap,
-                        (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)),
+                    let functor_list = step_or_resource_error!(
+                        self.machine_st,
+                        sized_iter_to_heap_list(
+                            &mut self.machine_st.heap,
+                            num_functors,
+                            (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)),
+                        )
                     );
 
                     unify!(
                         self.machine_st,
-                        heap_loc_as_cell!(h),
+                        functor_list,
                         self.machine_st.registers[4]
                     );
                 }
@@ -4236,17 +4325,18 @@ impl Machine {
             }
         };
 
-        let h = self.machine_st.heap.len();
+        let h = self.machine_st.heap.cell_len();
 
-        iter_to_heap_list(
-            &mut self.machine_st.heap,
-            (0..n).map(|i| heap_loc_as_cell!(h + 2 * i + 1)),
+        let list_cell = resource_error_call_result!(
+            self.machine_st,
+            sized_iter_to_heap_list(
+                &mut self.machine_st.heap,
+                n,
+                (0..n).map(|i| heap_loc_as_cell!(h + 2 * i + 1)),
+            )
         );
 
-        let tail = self.deref_register(1);
-        self.machine_st
-            .bind(tail.as_var().unwrap(), heap_loc_as_cell!(h));
-
+        unify!(self.machine_st, self.deref_register(1), list_cell);
         Ok(())
     }
 
@@ -4322,35 +4412,47 @@ impl Machine {
                     self.machine_st
                         .unify_fixnum(Fixnum::build_with(status as i64), address_status);
                     // headers
-                    let headers: Vec<HeapCellValue> = resp
-                        .headers()
-                        .iter()
-                        .map(|(header_name, header_value)| {
-                            let h = self.machine_st.heap.len();
+                    let mut headers: Vec<HeapCellValue> = vec![];
 
-                            let header_term = functor!(
-                                AtomTable::build_with(
-                                    &self.machine_st.atom_tbl,
-                                    header_name.as_str()
-                                ),
-                                [cell(string_as_cstr_cell!(AtomTable::build_with(
-                                    &self.machine_st.atom_tbl,
-                                    header_value.to_str().unwrap()
-                                )))]
-                            );
+                    for (header_name, header_value) in resp.headers().iter() {
+                        let string_cell = resource_error_call_result!(
+                            self.machine_st,
+                            self.machine_st.allocate_cstr(header_value.to_str().unwrap())
+                        );
 
-                            self.machine_st.heap.extend(header_term);
-                            str_loc_as_cell!(h)
-                        })
-                        .collect();
+                        let header_term = functor!(
+                            AtomTable::build_with(
+                                &self.machine_st.atom_tbl,
+                                header_name.as_str()
+                            ),
+                            [cell(string_cell)]
+                        );
+
+                        let mut functor_writer = Heap::functor_writer(header_term);
+
+                        let functor_cell = resource_error_call_result!(
+                            self.machine_st,
+                            functor_writer(&mut self.machine_st.heap)
+                        );
+
+                        headers.push(functor_cell);
+                    }
+
+                    let headers_list_cell = resource_error_call_result!(
+                        self.machine_st,
+                        sized_iter_to_heap_list(
+                            &mut self.machine_st.heap,
+                            headers.len(),
+                            headers.into_iter(),
+                        )
+                    );
 
-                    let headers_list =
-                        iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter());
                     unify!(
                         self.machine_st,
-                        heap_loc_as_cell!(headers_list),
+                        headers_list_cell,
                         self.machine_st.registers[6]
                     );
+
                     // body
                     let reader = futures::executor::block_on(resp.bytes()).unwrap().reader();
 
@@ -4546,89 +4648,120 @@ impl Machine {
             (ArenaHeaderTag::HttpListener, http_listener) => {
             loop {
                 match http_listener.incoming.recv_timeout(std::time::Duration::from_millis(200)) {
-                Ok(request) => {
-                    let method_atom = match request.request_data.method {
-                    Method::GET => atom!("get"),
-                    Method::POST => atom!("post"),
-                    Method::PUT => atom!("put"),
-                    Method::DELETE => atom!("delete"),
-                    Method::PATCH => atom!("patch"),
-                    Method::HEAD => atom!("head"),
-                    Method::OPTIONS => atom!("options"),
-                    Method::TRACE => atom!("trace"),
-                    Method::CONNECT => atom!("connect"),
-                    _ => atom!("unsupported_extension"),
-                };
-                let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path);
-                let path_cell = atom_as_cstr_cell!(path_atom);
-                let headers: Vec<HeapCellValue> = request.request_data.headers.iter().map(|(header_name, header_value)| {
-                    let h = self.machine_st.heap.len();
-                    let header_term = functor!(AtomTable::build_with(&self.machine_st.atom_tbl, header_name.as_str()), [cell(string_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, header_value.to_str().unwrap())))]);
+                    Ok(request) => {
+                        let method_atom = match request.request_data.method {
+                            Method::GET => atom!("get"),
+                            Method::POST => atom!("post"),
+                            Method::PUT => atom!("put"),
+                            Method::DELETE => atom!("delete"),
+                            Method::PATCH => atom!("patch"),
+                            Method::HEAD => atom!("head"),
+                            Method::OPTIONS => atom!("options"),
+                            Method::TRACE => atom!("trace"),
+                            Method::CONNECT => atom!("connect"),
+                            _ => atom!("unsupported_extension"),
+                        };
 
-                                    self.machine_st.heap.extend(header_term.into_iter());
-                                    str_loc_as_cell!(h)
-                                }).collect();
+                        let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path);
+                        let path_cell = resource_error_call_result!(
+                            self.machine_st,
+                            self.machine_st.allocate_cstr(&request.request_data.path)
+                        );
 
-                                let headers_list = iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter());
+                        let mut headers = vec![];
 
-                let query_str = request.request_data.query;
-                let query_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &query_str);
-                let query_cell = string_as_cstr_cell!(query_atom);
+                        for (header_name, header_value) in request.request_data.headers {
+                            let header_value = resource_error_call_result!(
+                                self.machine_st,
+                                self.machine_st.allocate_cstr(header_value.to_str().unwrap())
+                            );
 
-                let mut stream = Stream::from_http_stream(
-                    path_atom,
-                    request.request_data.body,
-                    &mut self.machine_st.arena
-                );
-                *stream.options_mut() = StreamOptions::default();
-                stream.options_mut().set_stream_type(StreamType::Binary);
-                self.indices.streams.insert(stream);
-                let stream = stream_as_cell!(stream);
+                            let header_term = functor!(
+                                AtomTable::build_with(&self.machine_st.atom_tbl, header_name.unwrap().as_str()),
+                                [cell(header_value)]
+                            );
 
-                                let handle: TypedArenaPtr<HttpResponse> = arena_alloc!(request.response, &mut self.machine_st.arena);
+                            let mut functor_writer = Heap::functor_writer(header_term);
+
+                            let functor_cell = resource_error_call_result!(
+                                self.machine_st,
+                                functor_writer(&mut self.machine_st.heap)
+                            );
+
+                            headers.push(functor_cell);
+                        }
+
+                        let headers_list_cell = resource_error_call_result!(
+                            self.machine_st,
+                            sized_iter_to_heap_list(
+                                &mut self.machine_st.heap,
+                                headers.len(),
+                                headers.into_iter(),
+                            )
+                        );
+
+                        let query_str  = request.request_data.query;
+                        let query_cell = resource_error_call_result!(
+                            self.machine_st,
+                            self.machine_st.allocate_cstr(&query_str)
+                        );
+
+                        let mut stream = Stream::from_http_stream(
+                            path_atom,
+                            request.request_data.body,
+                            &mut self.machine_st.arena
+                        );
+
+                        *stream.options_mut() = StreamOptions::default();
+                        stream.options_mut().set_stream_type(StreamType::Binary);
+                        self.indices.streams.insert(stream);
+                        let stream = stream_as_cell!(stream);
+
+                        let handle = arena_alloc!(request.response, &mut self.machine_st.arena)
+                            as TypedArenaPtr<HttpResponse>;
+
+                        self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom));
+                        self.machine_st.bind(path.as_var().unwrap(), path_cell);
+                        unify!(self.machine_st, headers_list_cell, self.machine_st.registers[4]);
+                        self.machine_st.bind(query.as_var().unwrap(), query_cell);
+                        self.machine_st.bind(stream_addr.as_var().unwrap(), stream);
+                        self.machine_st.bind(handle_addr.as_var().unwrap(), typed_arena_ptr_as_cell!(handle));
 
-                                self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom));
-                                self.machine_st.bind(path.as_var().unwrap(), path_cell);
-                                unify!(self.machine_st, heap_loc_as_cell!(headers_list), self.machine_st.registers[4]);
-                                self.machine_st.bind(query.as_var().unwrap(), query_cell);
-                                self.machine_st.bind(stream_addr.as_var().unwrap(), stream);
-                                self.machine_st.bind(handle_addr.as_var().unwrap(), typed_arena_ptr_as_cell!(handle));
-                break
-                            }
-                    Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {
-                    let interrupted = machine::INTERRUPT.load(std::sync::atomic::Ordering::Relaxed);
-
-                match machine::INTERRUPT.compare_exchange(
-                    interrupted,
-                    false,
-                    std::sync::atomic::Ordering::Relaxed,
-                    std::sync::atomic::Ordering::Relaxed,
-                ) {
-                    Ok(interruption) => {
-                    if interruption {
-                        self.machine_st.throw_interrupt_exception();
-                        self.machine_st.backtrack();
-                        // We have extracted controll over the Tokio runtime to the calling context for enabling library use case
-                        // (see https://github.com/mthom/scryer-prolog/pull/1880)
-                        // So we only have access to a runtime handle in here and can't shut it down.
-                        // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880
-                        // was not merged, I'm only deactivating it for now.
-                        //let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap());
-                        //old_runtime.shutdown_background();
                         break
                     }
+                    Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {
+                        let interrupted = machine::INTERRUPT.load(std::sync::atomic::Ordering::Relaxed);
+
+                        match machine::INTERRUPT.compare_exchange(
+                            interrupted,
+                            false,
+                            std::sync::atomic::Ordering::Relaxed,
+                            std::sync::atomic::Ordering::Relaxed,
+                        ) {
+                            Ok(interruption) => {
+                                if interruption {
+                                    self.machine_st.throw_interrupt_exception();
+                                    self.machine_st.backtrack();
+                                    // We have extracted controll over the Tokio runtime to the calling context for enabling library use case
+                                    // (see https://github.com/mthom/scryer-prolog/pull/1880)
+                                    // So we only have access to a runtime handle in here and can't shut it down.
+                                    // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880
+                                    // was not merged, I'm only deactivating it for now.
+                                    //let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap());
+                                    //old_runtime.shutdown_background();
+                                    break
+                                }
+                            }
+                            Err(_) => unreachable!(),
+                        }
                     }
-                    Err(_) => unreachable!(),
-                }
-
-                  }
                   Err(_) => {
-                              self.machine_st.fail = true;
-                          }
-            }
-                    }
+                      self.machine_st.fail = true;
+                  }
                 }
-                _ => {
+            }
+            }
+            _ => {
                     unreachable!();
                 }
             );
@@ -4824,15 +4957,20 @@ impl Machine {
                                     self.machine_st.unify_f64(n, return_value)
                                 }
                                 Value::Struct(name, args) => {
-                                    let struct_value = self.build_struct(&name, args);
+                                    let struct_value = resource_error_call_result!(
+                                        self.machine_st,
+                                        self.build_struct(&name, args)
+                                    );
+
                                     unify!(self.machine_st, return_value, struct_value);
                                 }
                                 Value::CString(cstr) => {
-                                    let cstr = AtomTable::build_with(
-                                        &self.machine_st.atom_tbl,
-                                        cstr.to_str().unwrap(),
+                                    let str_cell = resource_error_call_result!(
+                                        self.machine_st,
+                                        self.machine_st.allocate_cstr(cstr.to_str().unwrap())
                                     );
-                                    self.machine_st.unify_complete_string(cstr, return_value);
+
+                                    unify!(self.machine_st, str_cell, return_value);
                                 }
                             }
                             return Ok(());
@@ -4848,30 +4986,34 @@ impl Machine {
                 Err(e) => return Err(e),
             }
         }
+
         self.machine_st.fail = true;
         Ok(())
     }
 
     #[cfg(feature = "ffi")]
-    fn build_struct(&mut self, name: &str, mut args: Vec<Value>) -> HeapCellValue {
+    fn build_struct(&mut self, name: &str, mut args: Vec<Value>) -> Result<HeapCellValue, usize> {
         args.insert(0, Value::CString(CString::new(name).unwrap()));
-        let cells: Vec<_> = args
-            .into_iter()
-            .map(|val| match val {
+
+        let mut expanded_args = Vec::with_capacity(args.len());
+
+        for val in args {
+            expanded_args.push(match val {
                 Value::Int(n) => fixnum_as_cell!(Fixnum::build_with(n)),
                 Value::Float(n) => HeapCellValue::from(float_alloc!(n, self.machine_st.arena)),
                 Value::CString(cstr) => atom_as_cell!(AtomTable::build_with(
                     &self.machine_st.atom_tbl,
                     &cstr.into_string().unwrap()
                 )),
-                Value::Struct(name, struct_args) => self.build_struct(&name, struct_args),
-            })
-            .collect();
+                Value::Struct(name, struct_args) => self.build_struct(&name, struct_args)?,
+            });
+        }
 
-        heap_loc_as_cell!(iter_to_heap_list(
+        sized_iter_to_heap_list(
             &mut self.machine_st.heap,
-            cells.into_iter()
-        ))
+            expanded_args.len(),
+            expanded_args.into_iter(),
+        )
     }
 
     #[cfg(feature = "ffi")]
@@ -4966,29 +5108,39 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn argv(&mut self) -> CallResult {
         let args = self.deref_register(1);
-
         let mut args_pstrs = vec![];
+
         for arg in env::args() {
-            args_pstrs.push(put_complete_string(
-                &mut self.machine_st.heap,
-                &arg,
-                &self.machine_st.atom_tbl,
-            ));
+            let pstr_cell = resource_error_call_result!(
+                self.machine_st,
+                self.machine_st.allocate_cstr(&arg)
+            );
+
+            args_pstrs.push(pstr_cell);
         }
-        let cell = heap_loc_as_cell!(iter_to_heap_list(
-            &mut self.machine_st.heap,
-            args_pstrs.into_iter()
-        ));
 
-        unify!(self.machine_st, args, cell);
+        let list_cell = resource_error_call_result!(
+            self.machine_st,
+            sized_iter_to_heap_list(
+                &mut self.machine_st.heap,
+                args_pstrs.len(),
+                args_pstrs.into_iter(),
+            )
+        );
+
+        unify!(self.machine_st, args, list_cell);
         Ok(())
     }
 
     #[inline(always)]
     pub(crate) fn current_time(&mut self) {
         let timestamp = self.systemtime_to_timestamp(SystemTime::now());
-        self.machine_st
-            .unify_complete_string(timestamp, self.machine_st.registers[1]);
+        let cstr_cell = step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.allocate_cstr(&timestamp)
+        );
+
+        unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]);
     }
 
     #[inline(always)]
@@ -5049,9 +5201,11 @@ impl Machine {
         };
 
         let op = read_heap_cell!(self.deref_register(3),
+            /*
             (HeapCellValueTag::Char, c) => {
                 AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_string())
             }
+            */
             (HeapCellValueTag::Atom, (name, _arity)) => {
                 name
             }
@@ -5116,14 +5270,12 @@ impl Machine {
 
     #[inline(always)]
     pub(crate) fn truncate_if_no_lifted_heap_growth_diff(&mut self) {
-        self.machine_st
-            .truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h))
+        self.machine_st.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h))
     }
 
     #[inline(always)]
     pub(crate) fn truncate_if_no_lifted_heap_growth(&mut self) {
-        self.machine_st
-            .truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!())
+        self.machine_st.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!())
     }
 
     #[inline(always)]
@@ -5212,10 +5364,16 @@ impl Machine {
         };
 
         if let Some(b) = b {
-            let iter = self.machine_st.gather_attr_vars_created_since(b);
+            let attr_vars = self.machine_st.gather_attr_vars_created_since(b);
 
-            let var_list_addr =
-                heap_loc_as_cell!(iter_to_heap_list(&mut self.machine_st.heap, iter));
+            let var_list_addr = step_or_resource_error!(
+                self.machine_st,
+                sized_iter_to_heap_list(
+                    &mut self.machine_st.heap,
+                    attr_vars.len(),
+                    attr_vars.into_iter(),
+                )
+            );
 
             let list_addr = self.machine_st.registers[2];
             unify!(self.machine_st, var_list_addr, list_addr);
@@ -5273,7 +5431,12 @@ impl Machine {
     pub(crate) fn put_to_attributed_variable_list(&mut self) {
         let attr_var = self.deref_register(1);
         let attr = self.deref_register(3);
-        let attr_var_list = match self.machine_st.get_attr_var_list(attr_var) {
+        let attr_var_list_result = step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.get_attr_var_list(attr_var)
+        );
+
+        let attr_var_list = match attr_var_list_result {
             Some(h) => h,
             None => {
                 self.machine_st.fail = true;
@@ -5300,12 +5463,19 @@ impl Machine {
          * or str cells (> 0-arity).
          */
 
-        let h = self.machine_st.heap.len();
+        let module_functor = functor!(atom!(":"), [cell(module), cell(attr)]);
+        let h = self.machine_st.heap.cell_len();
 
-        self.machine_st.heap.push(str_loc_as_cell!(h + 1));
-        self.machine_st
-            .heap
-            .extend(functor!(atom!(":"), [cell(module), cell(attr)]));
+        step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.heap.push_cell(str_loc_as_cell!(h + 1))
+        );
+
+        let mut functor_writer = Heap::functor_writer(module_functor);
+        step_or_resource_error!(
+            self.machine_st,
+            functor_writer(&mut self.machine_st.heap)
+        );
 
         match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) {
             Some(AttrListMatch { match_site, .. }) => {
@@ -5315,8 +5485,16 @@ impl Machine {
 
                         // at the end of the (non-empty) list here.
                         self.machine_st.heap[match_site] = list_loc_as_cell!(h + 4);
-                        self.machine_st.heap.push(heap_loc_as_cell!(h));
-                        self.machine_st.heap.push(heap_loc_as_cell!(h + 5));
+
+                        let mut writer = step_or_resource_error!(
+                            self.machine_st,
+                            self.machine_st.heap.reserve(2)
+                        );
+
+                        writer.write_with(|section| {
+                            section.push_cell(heap_loc_as_cell!(h));
+                            section.push_cell(heap_loc_as_cell!(h + 5));
+                        });
 
                         (match_site, l)
                     }
@@ -5334,8 +5512,16 @@ impl Machine {
             None => {
                 // the list is empty.
                 self.machine_st.heap[attr_var_list] = list_loc_as_cell!(h + 4);
-                self.machine_st.heap.push(heap_loc_as_cell!(h));
-                self.machine_st.heap.push(heap_loc_as_cell!(h + 5));
+
+                let mut writer = step_or_resource_error!(
+                    self.machine_st,
+                    self.machine_st.heap.reserve(2)
+                );
+
+                writer.write_with(|section| {
+                    section.push_cell(heap_loc_as_cell!(h));
+                    section.push_cell(heap_loc_as_cell!(h + 5));
+                });
 
                 self.machine_st
                     .attr_var_init
@@ -5433,10 +5619,56 @@ impl Machine {
     pub(crate) fn get_continuation_chunk(&mut self) {
         let e = self.deref_register(1);
         let e = cell_as_fixnum!(e).get_num() as usize;
+        let h = self.machine_st.heap.cell_len();
 
-        let p_functor = self.deref_register(2);
-
+        let p_functor_cell = self.deref_register(2);
         let num_cells = self.machine_st.stack.index_and_frame(e).prelude.num_cells;
+
+        let mut writer = step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.heap.reserve(2 + num_cells)
+        );
+
+        writer.write_with(|section| {
+            section.push_cell(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells));
+            section.push_cell(p_functor_cell);
+
+            for idx in 1 ..= num_cells {
+                let mut stack_offset = stack_loc!(AndFrame, e, idx);
+                let mut addr = self.machine_st.stack[stack_offset];
+
+                while addr.get_tag() == HeapCellValueTag::StackVar {
+                    stack_offset = addr.get_value() as usize;
+
+                    if self.machine_st.stack[stack_offset] == addr {
+                        break;
+                    }
+
+                    addr = self.machine_st.stack[stack_offset];
+                }
+
+                if addr.get_tag() == HeapCellValueTag::StackVar {
+                    section.push_cell(heap_loc_as_cell!(h + 1 + idx));
+
+                    self.machine_st.stack[stack_offset] = heap_loc_as_cell!(h + 1 + idx);
+
+                    // have to inline the TrailRef::Ref(RefTag::StackCell) case of MachineState::trail
+                    // here to get around the borrow checker.
+                    if stack_offset < self.machine_st.b {
+                        self.machine_st.trail.push(TrailEntry::build_with(
+                            TrailEntryTag::TrailedStackVar,
+                            stack_offset as u64,
+                        ));
+
+                        self.machine_st.tr += 1;
+                    }
+                } else {
+                    section.push_cell(addr);
+                }
+            }
+        });
+
+        /*
         let mut addrs = vec![];
 
         for idx in 1..num_cells + 1 {
@@ -5446,7 +5678,7 @@ impl Machine {
             // avoid pushing stack variables to the heap where they
             // must not go.
             if addr.is_stack_var() {
-                let h = self.machine_st.heap.len();
+                let h = self.machine_st.heap.cell_len();
 
                 self.machine_st.heap.push(heap_loc_as_cell!(h));
                 self.machine_st.bind(Ref::heap_cell(h), addr);
@@ -5456,14 +5688,17 @@ impl Machine {
                 addrs.push(addr);
             }
         }
+        */
 
-        let chunk = str_loc_as_cell!(self.machine_st.heap.len());
+        let chunk = str_loc_as_cell!(self.machine_st.heap.cell_len());
 
+        /*
         self.machine_st
             .heap
             .push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells));
-        self.machine_st.heap.push(p_functor);
+        self.machine_st.heap.push(p_functor_cell);
         self.machine_st.heap.extend(addrs);
+        */
 
         unify!(self.machine_st, self.machine_st.registers[3], chunk);
     }
@@ -5474,25 +5709,28 @@ impl Machine {
         let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset)))
             .get_num() as usize;
 
-        if lh_offset >= self.machine_st.lifted_heap.len() {
+        if lh_offset >= self.machine_st.lifted_heap.cell_len() {
             let solutions = self.machine_st.registers[2];
             let diff = self.machine_st.registers[3];
 
             unify_fn!(self.machine_st, solutions, diff);
         } else {
-            let h = self.machine_st.heap.len();
-            let mut last_index = h;
+            let h = self.machine_st.heap.cell_len();
 
-            for value in self.machine_st.lifted_heap[lh_offset..].iter().cloned() {
-                last_index = self.machine_st.heap.len();
-                self.machine_st.heap.push(value + h);
-            }
+            step_or_resource_error!(
+                self.machine_st,
+                self.machine_st.heap.append(
+                    self.machine_st.lifted_heap.splice(lh_offset ..),
+                )
+            );
 
-            if last_index < self.machine_st.heap.len() {
-                let diff = self.machine_st.registers[3];
-                unify_fn!(self.machine_st, diff, self.machine_st.heap[last_index]);
+            for cell in &mut self.machine_st.heap.splice_mut(h ..) {
+                *cell = *cell + h;
             }
 
+            let diff = self.machine_st.registers[3];
+            unify_fn!(self.machine_st, diff, self.machine_st.heap.last_cell().unwrap());
+
             self.machine_st.lifted_heap.truncate(lh_offset);
 
             let solutions = self.machine_st.registers[2];
@@ -5506,14 +5744,21 @@ impl Machine {
         let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset)))
             .get_num() as usize;
 
-        if lh_offset >= self.machine_st.lifted_heap.len() {
+        if lh_offset >= self.machine_st.lifted_heap.cell_len() {
             let solutions = self.machine_st.registers[2];
             unify_fn!(self.machine_st, solutions, empty_list_as_cell!());
         } else {
-            let h = self.machine_st.heap.len();
+            let h = self.machine_st.heap.cell_len();
+
+            step_or_resource_error!(
+                self.machine_st,
+                self.machine_st.heap.append(
+                    self.machine_st.lifted_heap.splice(lh_offset ..),
+                )
+            );
 
-            for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() {
-                self.machine_st.heap.push(addr + h);
+            for cell in &mut self.machine_st.heap.splice_mut(h ..) {
+                *cell = *cell + h;
             }
 
             self.machine_st.lifted_heap.truncate(lh_offset);
@@ -5592,8 +5837,7 @@ impl Machine {
                 // n has already been confirmed as an integer, and
                 // internally, Rational is assumed reduced, so its
                 // denominator must be 1.
-                let r = r.numerator().try_into().unwrap();
-                r
+                r.numerator().try_into().unwrap()
             }
             _ => {
                 unreachable!()
@@ -5610,7 +5854,6 @@ impl Machine {
         let prev_block = self.machine_st.scc_block;
 
         self.machine_st.run_cleaners_fn = Machine::run_cleaners;
-
         self.machine_st.scc_block = b;
         self.machine_st.cont_pts.push((addr, b, prev_block));
     }
@@ -5626,7 +5869,6 @@ impl Machine {
             Ok(Number::Integer(n)) => (*n).clone(),
             _ => {
                 let stub = functor_stub(atom!("call_with_inference_limit"), 3);
-
                 let err = self.machine_st.type_error(ValidType::Integer, a2);
                 return Err(self.machine_st.error_form(err, stub));
             }
@@ -5644,8 +5886,7 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn inference_count(&mut self, count_var: HeapCellValue, count: Integer) {
         if let Ok(value) = <&Integer as TryInto<i64>>::try_into(&count) {
-            self.machine_st
-                .unify_fixnum(Fixnum::build_with(value), count_var);
+            self.machine_st.unify_fixnum(Fixnum::build_with(value), count_var);
         } else {
             let count = arena_alloc!(count, &mut self.machine_st.arena);
             self.machine_st.unify_big_int(count, count_var);
@@ -5690,7 +5931,6 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn no_such_predicate(&mut self) -> CallResult {
         let module_name = cell_as_atom!(self.deref_register(1));
-
         let head = self.deref_register(2);
 
         self.machine_st.fail = read_heap_cell!(head,
@@ -5975,15 +6215,15 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn get_ball(&mut self) {
         let addr = self.deref_register(1);
-        let h = self.machine_st.heap.len();
-
-        if !self.machine_st.ball.stub.is_empty() {
-            let stub = self.machine_st.ball.copy_and_align(h);
-            self.machine_st.heap.extend(stub);
+        let h = if !self.machine_st.ball.stub.is_empty() {
+            step_or_resource_error!(
+                self.machine_st,
+                self.machine_st.ball.copy_and_align_to(&mut self.machine_st.heap)
+            )
         } else {
             self.machine_st.fail = true;
             return;
-        }
+        };
 
         match addr.as_var() {
             Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]),
@@ -6063,15 +6303,17 @@ impl Machine {
             let e = and_frame.prelude.e;
             let e = Fixnum::build_with(i64::try_from(e).unwrap());
 
-            let p = str_loc_as_cell!(machine_st.heap.len());
+            let mut writer = Heap::functor_writer(functor!(atom!("dir_entry"), [fixnum(cp)]));
+
+            let p_functor_cell = step_or_resource_error!(
+                machine_st,
+                writer(&mut machine_st.heap)
+            );
 
-            machine_st
-                .heap
-                .extend(functor!(atom!("dir_entry"), [fixnum(cp)]));
             machine_st.unify_fixnum(e, machine_st.registers[2]);
 
             if !machine_st.fail {
-                unify!(machine_st, p, machine_st.registers[3]);
+                unify!(machine_st, p_functor_cell, machine_st.registers[3]);
             }
         };
 
@@ -6098,15 +6340,18 @@ impl Machine {
                 // it later.
                 let and_frame = self.machine_st.stack.index_and_frame(e);
                 let cp = and_frame.prelude.cp - 1;
+                let mut writer = Heap::functor_writer(functor!(atom!("dir_entry"), [fixnum(cp)]));
 
-                let p = str_loc_as_cell!(self.machine_st.heap.len());
-                self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)]));
+                let p_functor_cell = step_or_resource_error!(
+                    self.machine_st,
+                    writer(&mut self.machine_st.heap)
+                );
 
                 let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap());
                 self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
 
                 if !self.machine_st.fail {
-                    unify!(self.machine_st, p, self.machine_st.registers[3]);
+                    unify!(self.machine_st, p_functor_cell, self.machine_st.registers[3]);
                 }
             }
             _ => {
@@ -6146,9 +6391,11 @@ impl Machine {
                     None => true,
                 };
             }
+            /*
             (HeapCellValueTag::Char, c) => {
                 self.machine_st.fail = non_quoted_token(once(c));
             }
+            */
             (HeapCellValueTag::Atom, (name, arity)) => {
                 debug_assert_eq!(arity, 0);
                 self.machine_st.fail = non_quoted_token(name.as_str().chars());
@@ -6216,14 +6463,14 @@ impl Machine {
     fn read_term_from_atom(
         &mut self,
         atom_or_string: AtomOrString,
-    ) -> Result<Option<FocusedHeap>, MachineStub> {
+    ) -> Result<Option<TermWriteResult>, MachineStub> {
         let string = match atom_or_string {
             AtomOrString::Atom(atom!("[]")) => "".to_owned(),
             _ => atom_or_string.into(),
         };
 
         let chars = CharReader::new(ByteStream::from_string(string));
-        let mut parser = Parser::new(chars, &mut self.machine_st);
+        let mut parser = LexerParser::new(chars, &mut self.machine_st);
         let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
 
         let term = parser
@@ -6254,14 +6501,8 @@ impl Machine {
             .value_to_str_like(self.machine_st.registers[1])
             .unwrap();
 
-        if let Some(mut term) = self.read_term_from_atom(atom_or_string)? {
-            let heap_len = self.machine_st.heap.len();
-
-            self.machine_st.heap.extend(
-                copy_and_align_iter(term.heap.drain(..), 0, heap_len as i64),
-            );
-
-            let result = heap_loc_as_cell!(heap_len + term.focus);
+        if let Some(term) = self.read_term_from_atom(atom_or_string)? {
+            let result = self.machine_st.heap[term.focus];
             let var = self.deref_register(2).as_var().unwrap();
 
             self.machine_st.bind(var, result);
@@ -6283,8 +6524,8 @@ impl Machine {
         };
 
         let chars = CharReader::new(ByteStream::from_string(string));
-        let term_write_result = self.machine_st.read(chars, &self.indices.op_dir)
-            .map(|(term, _)| term.to_machine_heap(&mut self.machine_st))
+        let term = self.machine_st.read(chars, &self.indices.op_dir)
+            .map(|(term, _)| term)
             .map_err(|e| {
                 let e = self.machine_st.session_error(SessionError::from(e));
                 let stub = functor_stub(atom!("read_term_from_chars"), 3);
@@ -6292,7 +6533,7 @@ impl Machine {
                 self.machine_st.error_form(e, stub)
             })?;
 
-        self.machine_st.read_term_body(term_write_result)
+        self.machine_st.read_term_body(term)
     }
 
     #[inline(always)]
@@ -6325,12 +6566,15 @@ impl Machine {
 
     #[inline(always)]
     pub(crate) fn reset_continuation_marker(&mut self) {
-        let h = self.machine_st.heap.len();
+        let h = self.machine_st.heap.cell_len();
 
         self.machine_st.registers[3] = atom_as_cell!(atom!("none"));
         self.machine_st.registers[4] = heap_loc_as_cell!(h);
 
-        self.machine_st.heap.push(heap_loc_as_cell!(h));
+        step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.heap.push_cell(heap_loc_as_cell!(h))
+        );
     }
 
     #[inline(always)]
@@ -6671,10 +6915,9 @@ impl Machine {
             let stream = Stream::from_tls_stream(addr, stream, &mut self.machine_st.arena);
             self.indices.streams.insert(stream);
 
-            self.machine_st.heap.push(stream_as_cell!(stream));
+            // self.machine_st.heap.push(stream_as_cell!(stream));
             let stream_addr = self.deref_register(3);
-            self.machine_st
-                .bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
+            self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
 
             Ok(())
         } else {
@@ -6844,18 +7087,20 @@ impl Machine {
             }
             atom!("position") => {
                 if let Some((position, lines_read)) = stream.position() {
-                    let h = self.machine_st.heap.len();
-
                     let position_term = functor!(
                         atom!("position_and_lines_read"),
                         [
-                            integer(position, &mut self.machine_st.arena),
-                            integer(lines_read, &mut self.machine_st.arena)
+                            number(position, (&mut self.machine_st.arena)),
+                            number(lines_read, (&mut self.machine_st.arena))
                         ]
                     );
 
-                    self.machine_st.heap.extend(position_term);
-                    str_loc_as_cell!(h)
+                    let mut functor_writer = Heap::functor_writer(position_term);
+
+                    resource_error_call_result!(
+                        self.machine_st,
+                        functor_writer(&mut self.machine_st.heap)
+                    )
                 } else {
                     self.machine_st.fail = true;
                     return Ok(());
@@ -6892,17 +7137,20 @@ impl Machine {
         let value = self.machine_st.registers[2];
         let mut ball = Ball::new();
 
-        ball.boundary = self.machine_st.heap.len();
+        ball.boundary = self.machine_st.heap.cell_len();
 
-        copy_term(
-            CopyBallTerm::new(
-                &mut self.machine_st.attr_var_init.attr_var_queue,
-                &mut self.machine_st.stack,
-                &mut self.machine_st.heap,
-                &mut ball.stub,
-            ),
-            value,
-            AttrVarPolicy::DeepCopy,
+        step_or_resource_error!(
+            self.machine_st,
+            copy_term(
+                CopyBallTerm::new(
+                    &mut self.machine_st.attr_var_init.attr_var_queue,
+                    &mut self.machine_st.stack,
+                    &mut self.machine_st.heap,
+                    &mut ball.stub,
+                ),
+                value,
+                AttrVarPolicy::DeepCopy,
+            )
         );
 
         self.indices.global_variables.insert(key, (ball, None));
@@ -6946,10 +7194,15 @@ impl Machine {
         let seen_vars = self
             .machine_st
             .attr_vars_of_term(self.machine_st.registers[1]);
-        let outcome = heap_loc_as_cell!(iter_to_heap_list(
-            &mut self.machine_st.heap,
-            seen_vars.into_iter()
-        ));
+
+        let outcome = step_or_resource_error!(
+            self.machine_st,
+            sized_iter_to_heap_list(
+                &mut self.machine_st.heap,
+                seen_vars.len(),
+                seen_vars.into_iter(),
+            )
+        );
 
         unify_fn!(self.machine_st, self.machine_st.registers[2], outcome);
     }
@@ -6965,24 +7218,30 @@ impl Machine {
         }
 
         let stored_v = if stored_v.is_stack_var() {
-            let h = self.machine_st.heap.len();
+            let h = self.machine_st.heap.cell_len();
 
-            self.machine_st.heap.push(heap_loc_as_cell!(h));
-            self.machine_st.bind(Ref::heap_cell(h), stored_v);
+            step_or_resource_error!(
+                self.machine_st,
+                self.machine_st.heap.push_cell(heap_loc_as_cell!(h))
+            );
 
+            self.machine_st.bind(Ref::heap_cell(h), stored_v);
             heap_loc_as_cell!(h)
         } else {
             stored_v
         };
 
         let mut seen_set = IndexSet::with_hasher(FxBuildHasher::default());
-
         self.machine_st.variable_set(&mut seen_set, stored_v);
 
-        let outcome = heap_loc_as_cell!(iter_to_heap_list(
-            &mut self.machine_st.heap,
-            seen_set.into_iter()
-        ));
+        let outcome = step_or_resource_error!(
+            self.machine_st,
+            sized_iter_to_heap_list(
+                &mut self.machine_st.heap,
+                seen_set.len(),
+                seen_set.into_iter(),
+            )
+        );
 
         unify_fn!(self.machine_st, a2, outcome);
     }
@@ -7037,18 +7296,18 @@ impl Machine {
         false
     }
 
-    fn walk_code_at_ptr(&mut self, index_ptr: usize) -> HeapCellValue {
-        let mut h = self.machine_st.heap.len();
+    fn walk_code_at_ptr(&mut self, index_ptr: usize) -> Result<HeapCellValue, usize> {
+        let orig_h = self.machine_st.heap.cell_len();
+        let mut h = orig_h;
 
         let mut functors = vec![];
         let mut functor_list = vec![];
 
         walk_code(&self.code, index_ptr, |instr| {
             let old_len = functors.len();
-            instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors);
+            instr.enqueue_functors(&mut self.machine_st.arena, &mut functors);
             let new_len = functors.len();
 
-            #[allow(clippy::needless_range_loop)]
             for index in old_len..new_len {
                 let functor_len = functors[index].len();
 
@@ -7056,24 +7315,30 @@ impl Machine {
                     0 => {}
                     1 => {
                         functor_list.push(heap_loc_as_cell!(h));
-                        h += functor_len;
+                        h += cell_index!(Heap::compute_functor_byte_size(&functors[index]));
                     }
                     _ => {
                         functor_list.push(str_loc_as_cell!(h));
-                        h += functor_len;
+                        h += cell_index!(Heap::compute_functor_byte_size(&functors[index]));
                     }
-                }
+                };
             }
         });
 
-        for functor in functors {
-            self.machine_st.heap.extend(functor.into_iter());
-        }
+        let mut writer = self.machine_st.heap.reserve(h - orig_h)?;
+
+        writer.write_with(|section| {
+            for functor in functors {
+                let mut functor_writer = ReservedHeapSection::functor_writer(functor);
+                functor_writer(section);
+            }
+        });
 
-        heap_loc_as_cell!(iter_to_heap_list(
+        sized_iter_to_heap_list(
             &mut self.machine_st.heap,
-            functor_list.into_iter()
-        ))
+            functor_list.len(),
+            functor_list.into_iter(),
+        )
     }
 
     #[inline(always)]
@@ -7128,7 +7393,11 @@ impl Machine {
             }
         };
 
-        let listing = self.walk_code_at_ptr(first_idx);
+        let listing = resource_error_call_result!(
+            self.machine_st,
+            self.walk_code_at_ptr(first_idx)
+        );
+
         let listing_var = self.machine_st.registers[4];
 
         unify!(self.machine_st, listing, listing_var);
@@ -7149,7 +7418,11 @@ impl Machine {
             }
         };
 
-        let listing = self.walk_code_at_ptr(index_ptr);
+        let listing = step_or_resource_error!(
+            self.machine_st,
+            self.walk_code_at_ptr(index_ptr)
+        );
+
         let listing_var = self.machine_st.registers[2];
 
         unify!(self.machine_st, listing, listing_var);
@@ -7237,19 +7510,15 @@ impl Machine {
         };
 
         let result = printer.print().result();
-        let chars = put_complete_string(
-            &mut self.machine_st.heap,
-            &result,
-            &self.machine_st.atom_tbl,
+        let chars = resource_error_call_result!(
+            self.machine_st,
+            self.machine_st.allocate_cstr(&result)
         );
 
         let result_addr = self.deref_register(1);
+        let var = result_addr.as_var().unwrap();
 
-        if let Some(var) = result_addr.as_var() {
-            self.machine_st.bind(var, chars);
-        } else {
-            unreachable!()
-        }
+        self.machine_st.bind(var, chars);
 
         Ok(())
     }
@@ -7259,10 +7528,12 @@ impl Machine {
         use git_version::git_version;
 
         let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown");
-        let buffer_atom = AtomTable::build_with(&self.machine_st.atom_tbl, buffer);
+        let cstr_cell = step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.allocate_cstr(&buffer)
+        );
 
-        let a1 = self.deref_register(1);
-        self.machine_st.unify_complete_string(buffer_atom, a1);
+        unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]);
     }
 
     #[inline(always)]
@@ -7297,84 +7568,121 @@ impl Machine {
                 let mut context = Sha3_224::new();
                 context.update(&bytes);
 
-                heap_loc_as_cell!(iter_to_heap_list(
-                    &mut self.machine_st.heap,
-                    context
-                        .finalize()
-                        .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                ))
+                let finalized_context = context.finalize();
+                let context_len = finalized_context.len();
+
+                step_or_resource_error!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context_len,
+                        finalized_context
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                    )
+                )
             }
             atom!("sha3_256") => {
                 let mut context = Sha3_256::new();
                 context.update(&bytes);
-                heap_loc_as_cell!(iter_to_heap_list(
-                    &mut self.machine_st.heap,
-                    context
-                        .finalize()
-                        .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                ))
+                let finalized_context = context.finalize();
+                let context_len = finalized_context.len();
+
+                step_or_resource_error!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context_len,
+                        finalized_context
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                    )
+                )
             }
             atom!("sha3_384") => {
                 let mut context = Sha3_384::new();
                 context.update(&bytes);
+                let finalized_context = context.finalize();
+                let context_len = finalized_context.len();
 
-                heap_loc_as_cell!(iter_to_heap_list(
-                    &mut self.machine_st.heap,
-                    context
-                        .finalize()
-                        .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                ))
+                step_or_resource_error!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context_len,
+                        finalized_context
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                    )
+                )
             }
             atom!("sha3_512") => {
                 let mut context = Sha3_512::new();
                 context.update(&bytes);
+                let finalized_context = context.finalize();
+                let context_len = finalized_context.len();
 
-                heap_loc_as_cell!(iter_to_heap_list(
-                    &mut self.machine_st.heap,
-                    context
-                        .finalize()
-                        .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                ))
+                step_or_resource_error!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context_len,
+                        finalized_context
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
             }
             atom!("blake2s256") => {
                 let mut context = Blake2s256::new();
                 context.update(&bytes);
+                let finalized_context = context.finalize();
+                let context_len = finalized_context.len();
 
-                heap_loc_as_cell!(iter_to_heap_list(
-                    &mut self.machine_st.heap,
-                    context
-                        .finalize()
-                        .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                ))
+                step_or_resource_error!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context_len,
+                        finalized_context
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
             }
             atom!("blake2b512") => {
                 let mut context = Blake2b512::new();
                 context.update(&bytes);
+                let finalized_context = context.finalize();
+                let context_len = finalized_context.len();
 
-                heap_loc_as_cell!(iter_to_heap_list(
-                    &mut self.machine_st.heap,
-                    context
-                        .finalize()
-                        .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                ))
+                step_or_resource_error!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context_len,
+                        finalized_context
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
             }
             atom!("ripemd160") => {
                 let mut context = Ripemd160::new();
                 context.update(&bytes);
+                let finalized_context = context.finalize();
+                let context_len = finalized_context.len();
 
-                heap_loc_as_cell!(iter_to_heap_list(
-                    &mut self.machine_st.heap,
-                    context
-                        .finalize()
-                        .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                ))
+                step_or_resource_error!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context_len,
+                        finalized_context
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                    )
+                )
             }
             _ => {
                 let ints = digest::digest(
@@ -7390,12 +7698,16 @@ impl Machine {
                     &bytes,
                 );
 
-                heap_loc_as_cell!(iter_to_heap_list(
-                    &mut self.machine_st.heap,
-                    ints.as_ref()
-                        .iter()
-                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                ))
+                step_or_resource_error!(
+                    self.machine_st,
+                    sized_iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        ints.as_ref().len(),
+                        ints.as_ref()
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                    )
+                )
             }
         };
 
@@ -7426,12 +7738,16 @@ impl Machine {
         let rkey = hmac::Key::new(ralg, key.as_ref());
         let tag = hmac::sign(&rkey, &data);
 
-        let ints_list = heap_loc_as_cell!(iter_to_heap_list(
-            &mut self.machine_st.heap,
-            tag.as_ref()
-                .iter()
-                .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-        ));
+        let ints_list = step_or_resource_error!(
+            self.machine_st,
+            sized_iter_to_heap_list(
+                &mut self.machine_st.heap,
+                tag.as_ref().len(),
+                tag.as_ref()
+                    .iter()
+                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+            )
+        );
 
         unify!(self.machine_st, self.machine_st.registers[4], ints_list);
     }
@@ -7493,12 +7809,16 @@ impl Machine {
                 }
             }
 
-            heap_loc_as_cell!(iter_to_heap_list(
-                &mut self.machine_st.heap,
-                bytes
-                    .iter()
-                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-            ))
+            step_or_resource_error!(
+                self.machine_st,
+                sized_iter_to_heap_list(
+                    &mut self.machine_st.heap,
+                    bytes.len(),
+                    bytes
+                        .iter()
+                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                )
+            )
         };
 
         unify!(self.machine_st, self.machine_st.registers[7], ints_list);
@@ -7545,12 +7865,16 @@ impl Machine {
                 &mut bytes,
             );
 
-            heap_loc_as_cell!(iter_to_heap_list(
-                &mut self.machine_st.heap,
-                bytes
-                    .iter()
-                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-            ))
+            step_or_resource_error!(
+                self.machine_st,
+                sized_iter_to_heap_list(
+                    &mut self.machine_st.heap,
+                    bytes.len(),
+                    bytes
+                        .iter()
+                        .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+                )
+            )
         };
 
         unify!(self.machine_st, self.machine_st.registers[4], ints_list);
@@ -7588,14 +7912,21 @@ impl Machine {
             }
         };
 
-        let tag_list = heap_loc_as_cell!(iter_to_heap_list(
-            &mut self.machine_st.heap,
-            tag.as_ref()
-                .iter()
-                .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-        ));
+        let tag_list = step_or_resource_error!(
+            self.machine_st,
+            sized_iter_to_heap_list(
+                &mut self.machine_st.heap,
+                tag.as_ref().len(),
+                tag.as_ref()
+                    .iter()
+                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+            )
+        );
 
-        let complete_string = self.u8s_to_string(&in_out);
+        let complete_string = step_or_resource_error!(
+            self.machine_st,
+            self.u8s_to_string(&in_out)
+        );
 
         unify!(self.machine_st, self.machine_st.registers[6], tag_list);
         unify!(
@@ -7654,7 +7985,10 @@ impl Machine {
             if buffer.is_empty() {
                 empty_list_as_cell!()
             } else {
-                atom_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, &buffer))
+                step_or_resource_error!(
+                    self.machine_st,
+                    self.machine_st.allocate_cstr(&buffer)
+                )
             }
         };
 
@@ -7679,7 +8013,10 @@ impl Machine {
         let scalar = secp256k1::Scalar::decode_reduce(&scalar_bytes);
         point *= scalar;
 
-        let uncompressed = self.u8s_to_string(&point.encode_uncompressed());
+        let uncompressed = step_or_resource_error!(
+            self.machine_st,
+            self.u8s_to_string(&point.encode_uncompressed())
+        );
 
         unify!(self.machine_st, self.machine_st.registers[4], uncompressed);
     }
@@ -7693,7 +8030,10 @@ impl Machine {
 
         let skey = ed25519::PrivateKey::from_seed(&seed_bytes);
 
-        let complete_string = self.u8s_to_string(skey.public_key.encoded.as_ref());
+        let complete_string = step_or_resource_error!(
+            self.machine_st,
+            self.u8s_to_string(skey.public_key.encoded.as_ref())
+        );
 
         unify!(
             self.machine_st,
@@ -7715,13 +8055,16 @@ impl Machine {
         let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
 
         let sig = skey.sign_raw(&data);
-
-        let sig_list = heap_loc_as_cell!(iter_to_heap_list(
-            &mut self.machine_st.heap,
-            sig.as_ref()
-                .iter()
-                .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-        ));
+        let sig_list = step_or_resource_error!(
+            self.machine_st,
+            sized_iter_to_heap_list(
+                &mut self.machine_st.heap,
+                sig.as_ref().len(),
+                sig.as_ref()
+                    .iter()
+                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64)))
+            )
+        );
 
         unify!(self.machine_st, self.machine_st.registers[4], sig_list);
     }
@@ -7759,7 +8102,10 @@ impl Machine {
             &<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap(),
         );
 
-        let string = self.u8s_to_string(&result[..]);
+        let string = step_or_resource_error!(
+            self.machine_st,
+            self.u8s_to_string(&result[..])
+        );
 
         unify!(self.machine_st, self.machine_st.registers[3], string);
     }
@@ -7784,29 +8130,31 @@ impl Machine {
     }
 
     #[inline(always)]
-    pub(crate) fn load_html(&mut self) {
+    pub(crate) fn load_html(&mut self) -> Result<(), usize> {
         if let Some(string) = self
             .machine_st
             .value_to_str_like(self.machine_st.registers[1])
         {
             let document = scraper::Html::parse_document(&string.as_str());
-            let result = self.html_node_to_term(document.tree.root().first_child().unwrap());
+            let result = self.html_node_to_term(document.tree.root().first_child().unwrap())?;
 
             unify!(self.machine_st, self.machine_st.registers[2], result);
         } else {
             self.machine_st.fail = true;
         }
+
+        Ok(())
     }
 
     #[inline(always)]
-    pub(crate) fn load_xml(&mut self) {
+    pub(crate) fn load_xml(&mut self) -> Result<(), usize> {
         if let Some(string) = self
             .machine_st
             .value_to_str_like(self.machine_st.registers[1])
         {
             match roxmltree::Document::parse(&string.as_str()) {
                 Ok(doc) => {
-                    let result = self.xml_node_to_term(doc.root_element());
+                    let result = self.xml_node_to_term(doc.root_element())?;
                     unify!(self.machine_st, self.machine_st.registers[2], result);
                 }
                 _ => {
@@ -7816,6 +8164,8 @@ impl Machine {
         } else {
             self.machine_st.fail = true;
         }
+
+        Ok(())
     }
 
     #[inline(always)]
@@ -7826,10 +8176,9 @@ impl Machine {
         {
             match env::var(&*key.as_str()) {
                 Ok(value) => {
-                    let cstr = put_complete_string(
-                        &mut self.machine_st.heap,
-                        &value,
-                        &self.machine_st.atom_tbl,
+                    let cstr = step_or_resource_error!(
+                        self.machine_st,
+                        self.machine_st.allocate_cstr(&value)
                     );
 
                     unify!(self.machine_st, self.machine_st.registers[2], cstr);
@@ -7960,7 +8309,10 @@ impl Machine {
 
             match bytes {
                 Ok(bs) => {
-                    let string = self.u8s_to_string(&bs);
+                    let string = resource_error_call_result!(
+                        self.machine_st,
+                        self.u8s_to_string(&bs)
+                    );
 
                     unify!(self.machine_st, self.machine_st.registers[1], string);
                 }
@@ -7982,7 +8334,10 @@ impl Machine {
             }
 
             let b64 = b64_engine.encode(bytes);
-            let string = self.u8s_to_string(b64.as_bytes());
+            let string = resource_error_call_result!(
+                self.machine_st,
+                self.u8s_to_string(b64.as_bytes())
+            );
 
             unify!(self.machine_st, self.machine_st.registers[2], string);
         }
@@ -8040,12 +8395,12 @@ impl Machine {
             1,
         )?;
 
-        let mut parser = Parser::new(stream, &mut self.machine_st);
+        let mut lexer_parser = LexerParser::new(stream, &mut self.machine_st);
 
-        match devour_whitespace(&mut parser) {
+        match devour_whitespace(&mut lexer_parser) {
             Ok(false) => {
                 // not at EOF ...
-                stream.add_lines_read(parser.lines_read());
+                stream.add_lines_read(lexer_parser.line_num());
 
                 // ... unless we are.
                 if stream.at_end_of_stream() {
@@ -8053,7 +8408,7 @@ impl Machine {
                 }
             }
             Ok(true) => {
-                stream.add_lines_read(parser.lines_read());
+                stream.add_lines_read(lexer_parser.line_num());
                 self.machine_st.fail = true;
             }
             Err(err) => {
@@ -8113,8 +8468,10 @@ impl Machine {
 
         if path.is_dir() {
             if let Some(path) = path.to_str() {
-                let path_string =
-                    put_complete_string(&mut self.machine_st.heap, path, &self.machine_st.atom_tbl);
+                let path_string = step_or_resource_error!(
+                    self.machine_st,
+                    self.machine_st.allocate_cstr(path)
+                );
 
                 unify!(self.machine_st, self.machine_st.registers[1], path_string);
                 return;
@@ -8149,7 +8506,7 @@ impl Machine {
         unify!(self.machine_st, self.machine_st.registers[2], pop_count);
     }
 
-    pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom {
+    pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> String {
         let datetime: DateTime<Local> = system_time.into();
 
         let mut fstr = "[".to_string();
@@ -8163,9 +8520,7 @@ impl Machine {
         }
 
         fstr.push_str("finis].");
-        let s = datetime.format(&fstr).to_string();
-
-        AtomTable::build_with(&self.machine_st.atom_tbl, &s)
+        datetime.format(&fstr).to_string()
     }
 
     pub(super) fn string_encoding_bytes(
@@ -8184,128 +8539,125 @@ impl Machine {
         }
     }
 
-    pub(super) fn xml_node_to_term(&mut self, node: roxmltree::Node) -> HeapCellValue {
+    pub(super) fn xml_node_to_term(&mut self, node: roxmltree::Node) -> Result<HeapCellValue, usize> {
         if node.is_text() {
-            put_complete_string(
-                &mut self.machine_st.heap,
-                node.text().unwrap(),
-                &self.machine_st.atom_tbl,
-            )
+            self.machine_st.allocate_cstr(node.text().unwrap())
         } else {
             let mut avec = Vec::new();
 
             for attr in node.attributes() {
                 let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.name());
-                let value = put_complete_string(
-                    &mut self.machine_st.heap,
-                    attr.value(),
-                    &self.machine_st.atom_tbl,
-                );
+                let value = self.machine_st.allocate_cstr(attr.value())?;
 
-                avec.push(str_loc_as_cell!(self.machine_st.heap.len()));
+                avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len()));
 
-                self.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
-                self.machine_st.heap.push(atom_as_cell!(name));
-                self.machine_st.heap.push(value);
+                let mut writer = self.machine_st.heap.reserve(3)?;
+
+                writer.write_with(|section| {
+                    section.push_cell(atom_as_cell!(atom!("="), 2));
+                    section.push_cell(atom_as_cell!(name));
+                    section.push_cell(value);
+                });
             }
 
-            let attrs = heap_loc_as_cell!(iter_to_heap_list(
+            let attrs = sized_iter_to_heap_list(
                 &mut self.machine_st.heap,
-                avec.into_iter()
-            ));
+                avec.len(),
+                avec.into_iter(),
+            )?;
 
             let mut cvec = Vec::new();
 
             for child in node.children() {
-                cvec.push(self.xml_node_to_term(child));
+                cvec.push(self.xml_node_to_term(child)?);
             }
 
-            let children = heap_loc_as_cell!(iter_to_heap_list(
+            let children = sized_iter_to_heap_list(
                 &mut self.machine_st.heap,
-                cvec.into_iter()
-            ));
+                cvec.len(),
+                cvec.into_iter(),
+            )?;
 
             let tag = AtomTable::build_with(&self.machine_st.atom_tbl, node.tag_name().name());
+            let result = str_loc_as_cell!(self.machine_st.heap.cell_len());
+            let mut writer = self.machine_st.heap.reserve(4)?;
+
+            writer.write_with(|section| {
+                section.push_cell(atom_as_cell!(atom!("element"), 3));
+                section.push_cell(atom_as_cell!(tag));
+                section.push_cell(attrs);
+                section.push_cell(children);
+            });
 
-            let result = str_loc_as_cell!(self.machine_st.heap.len());
-
-            self.machine_st
-                .heap
-                .push(atom_as_cell!(atom!("element"), 3));
-            self.machine_st.heap.push(atom_as_cell!(tag));
-            self.machine_st.heap.push(attrs);
-            self.machine_st.heap.push(children);
-
-            result
+            Ok(result)
         }
     }
 
-    pub(super) fn html_node_to_term(
+     pub(super) fn html_node_to_term(
         &mut self,
         node: ego_tree::NodeRef<'_, scraper::Node>,
-    ) -> HeapCellValue {
+    ) -> Result<HeapCellValue, usize> {
         match node.value().as_element() {
-            None => put_complete_string(
-                &mut self.machine_st.heap,
-                &node.value().as_text().unwrap().text,
-                &self.machine_st.atom_tbl,
-            ),
+            None => self.machine_st.allocate_cstr(&node.value().as_text().unwrap().text),
             Some(element) => {
                 let mut avec = Vec::new();
 
                 for attr in element.attrs() {
                     let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.0);
-                    let value = put_complete_string(
-                        &mut self.machine_st.heap,
-                        attr.1,
-                        &self.machine_st.atom_tbl,
-                    );
+                    let value = self.machine_st.allocate_cstr(attr.1)?;
+
+                    avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len()));
 
-                    avec.push(str_loc_as_cell!(self.machine_st.heap.len()));
+                    let mut writer = self.machine_st.heap.reserve(3)?;
 
-                    self.machine_st.heap.push(atom_as_cell!(atom!("="), 2));
-                    self.machine_st.heap.push(atom_as_cell!(name));
-                    self.machine_st.heap.push(value);
+                    writer.write_with(|section| {
+                        section.push_cell(atom_as_cell!(atom!("="), 2));
+                        section.push_cell(atom_as_cell!(name));
+                        section.push_cell(value);
+                    });
                 }
 
-                let attrs = heap_loc_as_cell!(iter_to_heap_list(
+                let attrs = sized_iter_to_heap_list(
                     &mut self.machine_st.heap,
-                    avec.into_iter()
-                ));
+                    avec.len(),
+                    avec.into_iter(),
+                )?;
 
                 let mut cvec = Vec::new();
 
                 for child in node.children() {
-                    cvec.push(self.html_node_to_term(child));
+                    cvec.push(self.html_node_to_term(child)?);
                 }
 
-                let children = heap_loc_as_cell!(iter_to_heap_list(
+                let children = sized_iter_to_heap_list(
                     &mut self.machine_st.heap,
-                    cvec.into_iter()
-                ));
+                    cvec.len(),
+                    cvec.into_iter(),
+                )?;
 
                 let tag = AtomTable::build_with(&self.machine_st.atom_tbl, element.name());
-                let result = str_loc_as_cell!(self.machine_st.heap.len());
-
-                self.machine_st
-                    .heap
-                    .push(atom_as_cell!(atom!("element"), 3));
-                self.machine_st.heap.push(atom_as_cell!(tag));
-                self.machine_st.heap.push(attrs);
-                self.machine_st.heap.push(children);
+                let result = str_loc_as_cell!(self.machine_st.heap.cell_len());
+                let mut writer = self.machine_st.heap.reserve(4)?;
+
+                writer.write_with(|section| {
+                    section.push_cell(atom_as_cell!(atom!("element"), 3));
+                    section.push_cell(atom_as_cell!(tag));
+                    section.push_cell(attrs);
+                    section.push_cell(children);
+                });
 
-                result
+                Ok(result)
             }
         }
     }
 
-    pub(super) fn u8s_to_string(&mut self, data: &[u8]) -> HeapCellValue {
+    pub(super) fn u8s_to_string(&mut self, data: &[u8]) -> Result<HeapCellValue, usize> {
         let buffer = String::from_iter(data.iter().map(|b| *b as char));
 
         if buffer.is_empty() {
-            empty_list_as_cell!()
+            Ok(empty_list_as_cell!())
         } else {
-            atom_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, &buffer))
+            self.machine_st.allocate_cstr(&buffer)
         }
     }
 }
index 58c6e2c88c4976a483a12c5b7319782334a7f1cd..9a1f9fa699503bf2c2769d00cfc47a8dfcf2ec98 100644 (file)
@@ -4,6 +4,7 @@ use crate::machine::loader::*;
 use crate::machine::machine_errors::*;
 use crate::machine::*;
 use crate::parser::ast::*;
+use crate::parser::lexer::*;
 use crate::parser::parser::*;
 use crate::read::devour_whitespace;
 
@@ -20,11 +21,11 @@ pub struct LoadStatePayload<TS> {
     pub(super) module_op_exports: ModuleOpExports,
     pub(super) non_counted_bt_preds: IndexSet<PredicateKey, FxBuildHasher>,
     pub(super) predicates: PredicateQueue,
-    pub(super) clause_clauses: Vec<FocusedHeap>,
+    pub(super) clause_clauses: Vec<TermWriteResult>,
 }
 
 pub trait TermStream: Sized {
-    fn next(&mut self, op_dir: &CompositeOpDir) -> Result<FocusedHeap, CompilationError>;
+    fn next(&mut self, op_dir: &CompositeOpDir) -> Result<TermWriteResult, CompilationError>;
     fn eof(&mut self) -> Result<bool, CompilationError>;
     fn listing_src(&self) -> &ListingSource;
 }
@@ -32,7 +33,7 @@ pub trait TermStream: Sized {
 #[derive(Debug)]
 pub struct BootstrappingTermStream<'a> {
     listing_src: ListingSource,
-    pub(super) parser: Parser<'a, Stream>,
+    pub(super) lexer_parser: LexerParser<'a, Stream>,
 }
 
 impl<'a> BootstrappingTermStream<'a> {
@@ -42,26 +43,23 @@ impl<'a> BootstrappingTermStream<'a> {
         machine_st: &'a mut MachineState,
         listing_src: ListingSource,
     ) -> Self {
-        let parser = Parser::new(stream, machine_st);
-        Self {
-            parser,
-            listing_src,
-        }
+        let lexer_parser = LexerParser::new(stream, machine_st);
+        Self { lexer_parser, listing_src }
     }
 }
 
 impl<'a> TermStream for BootstrappingTermStream<'a> {
     #[inline]
-    fn next(&mut self, op_dir: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
-        self.parser.reset();
-        self.parser
-            .read_term(op_dir, Tokens::Default)
-            .map_err(CompilationError::from)
+    fn next(&mut self, op_dir: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> {
+        let result = self.lexer_parser.read_term(op_dir, Tokens::Default)
+            .map_err(CompilationError::from);
+
+        result
     }
 
     #[inline]
     fn eof(&mut self) -> Result<bool, CompilationError> {
-        devour_whitespace(&mut self.parser) // eliminate dangling comments before checking for EOF.
+        devour_whitespace(&mut self.lexer_parser) // eliminate dangling comments before checking for EOF.
             .map_err(CompilationError::from)
     }
 
@@ -72,7 +70,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
 }
 
 pub struct LiveTermStream {
-    pub(super) term_queue: VecDeque<FocusedHeap>,
+    pub(super) term_queue: VecDeque<TermWriteResult>,
     pub(super) listing_src: ListingSource,
 }
 
@@ -108,7 +106,7 @@ impl<TS> LoadStatePayload<TS> {
 
 impl TermStream for LiveTermStream {
     #[inline]
-    fn next(&mut self, _: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
+    fn next(&mut self, _: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> {
         Ok(self.term_queue.pop_front().unwrap())
     }
 
@@ -126,7 +124,7 @@ impl TermStream for LiveTermStream {
 pub struct InlineTermStream {}
 
 impl TermStream for InlineTermStream {
-    fn next(&mut self, _: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
+    fn next(&mut self, _: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> {
         Err(CompilationError::from(ParserError::unexpected_eof(ParserErrorSrc::default())))
     }
 
index 05ba4749dc60a933ada8f4ee5b1af4bd4cabf0d5..5b7c23e82a710563fb1c79491d132f4d97ccc499 100644 (file)
@@ -2,11 +2,9 @@ use crate::arena::*;
 use crate::forms::*;
 use crate::heap_iter::{stackful_preorder_iter, NonListElider};
 use crate::machine::machine_state::*;
-use crate::machine::partial_string::*;
 use crate::machine::*;
 use crate::types::*;
 
-use std::cmp::Ordering;
 use std::ops::{Deref, DerefMut};
 
 use derive_more::*;
@@ -14,6 +12,18 @@ use fxhash::FxBuildHasher;
 use indexmap::IndexSet;
 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> {
     fn unify_structure(&mut self, s1: usize, value: HeapCellValue) {
         // s1 is the value of a STR cell.
@@ -82,8 +92,8 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
                     self.fail = true;
                 }
             }
-            (HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => {
-                Self::unify_partial_string(self, list_loc_as_cell!(l1), value)
+            (HeapCellValueTag::PStrLoc, l) => {
+                Self::unify_partial_string(self, l, list_loc_as_cell!(l1))
             }
             (HeapCellValueTag::AttrVar, h) => {
                 Self::bind(self, Ref::attr_var(h), list_loc_as_cell!(l1));
@@ -100,263 +110,42 @@ 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 atom == atom!("") {
-                Self::bind(self, r, atom_as_cell!(atom!("[]")));
-            } else {
-                Self::bind(self, r, atom_as_cstr_cell!(atom));
-            }
-
+            Self::bind(self, r, pstr_loc_as_cell!(pstr_loc));
             return;
         }
 
+        let machine_st = self.deref_mut();
+
         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])
+                let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
                     .get_name_and_arity();
 
-                if arity == 0 {
-                    self.fail = atom == atom!("") && name != atom!("[]");
+                if name == atom!(".") && arity == 2 {
+                    machine_st.partial_string_to_pdl(pstr_loc, s+1);
                 } 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);
-                    }
+                    machine_st.fail = true;
                 }
             }
-            (HeapCellValueTag::CStr, cstr_atom) => {
-                self.fail = atom != cstr_atom;
+            (HeapCellValueTag::Lis, l) => {
+                machine_st.partial_string_to_pdl(pstr_loc, l);
             }
-            (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
-                Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value);
+            (HeapCellValueTag::PStrLoc, other_pstr_loc) => {
+                let cmp_result = machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc);
 
-                if !self.pdl.is_empty() {
-                    Self::unify_internal(self);
+                if cmp_result.continue_pstr_compare(&mut machine_st.pdl).is_some() {
+                    debug_assert!(matches!(cmp_result, PStrSegmentCmpResult::Mismatch { .. }));
+                    machine_st.fail = true;
                 }
             }
             _ => {
-                self.fail = true;
+                machine_st.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;
-        }
-
-        let machine_st = self.deref_mut();
-
-        let s1 = machine_st.heap.len();
-
-        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) => {
-                                let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s])
-                                    .get_name_and_arity();
-
-                                if name == atom!(".") && arity == 2 {
-                                    machine_st.pdl.push(pstr_iter2.heap[s+1]);
-                                    machine_st.pdl.push(char_as_cell!(c));
-
-                                    focus = pstr_iter2.heap[s+2];
-                                } else {
-                                    machine_st.fail = true;
-                                    break 'outer;
-                                }
-                            }
-                            (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
-                                unify_sequence(machine_st, chars_iter.item.unwrap(), focus);
-                                return;
-                            }
-                            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                                if unify_sequence(machine_st, chars_iter.item.unwrap(), heap_loc_as_cell!(h)) {
-                                    return;
-                                }
-
-                                break 'outer;
-                            }
-                            _ => {
-                                machine_st.fail = true;
-                                break 'outer;
-                            }
-                        );
-
-                        chars_iter.next();
-                    }
-
-                    chars_iter.iter.next();
-
-                    machine_st.pdl.push(focus);
-                    machine_st.pdl.push(chars_iter.iter.focus);
-                }
-            }
-            PStrCmpResult::Unordered => {
-                machine_st.pdl.push(pstr_iter1.focus);
-                machine_st.pdl.push(pstr_iter2.focus);
-            }
-        }
-
-        machine_st.heap.pop();
-        machine_st.heap.pop();
-    }
-
     fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) {
         read_heap_cell!(value,
             (HeapCellValueTag::Atom, (name, arity)) => {
@@ -368,6 +157,7 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
 
                 self.fail = !(arity == 0 && name == atom);
             }
+            /*
             (HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => {
                 self.fail = cstr_atom != atom!("");
             }
@@ -378,6 +168,7 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
                     self.fail = true;
                 }
             }
+            */
             (HeapCellValueTag::AttrVar, h) => {
                 Self::bind(self, Ref::attr_var(h), atom_as_cell!(atom));
             }
@@ -412,11 +203,13 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
                     self.fail = true;
                 }
             }
+            /*
             (HeapCellValueTag::Char, c2) => {
                 if c != c2 {
                     self.fail = true;
                 }
             }
+            */
             (HeapCellValueTag::AttrVar, h) => {
                 Self::bind(self, Ref::attr_var(h), char_as_cell!(c));
             }
@@ -610,7 +403,7 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
                             tabu_list.insert((d1, d2));
                         }
                     }
-                    (HeapCellValueTag::PStrLoc) => {
+                    (HeapCellValueTag::PStrLoc, l) => {
                         read_heap_cell!(d2,
                             (HeapCellValueTag::PStrLoc |
                              HeapCellValueTag::Lis |
@@ -619,8 +412,7 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
                                     continue;
                                 }
                             }
-                            (HeapCellValueTag::CStr |
-                             HeapCellValueTag::AttrVar |
+                            (HeapCellValueTag::AttrVar |
                              HeapCellValueTag::Var |
                              HeapCellValueTag::StackVar) => {
                             }
@@ -630,13 +422,14 @@ 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() {
                             let d2 = self.store(d2);
                             tabu_list.insert((d1, d2));
                         }
                     }
+                    /*
                     (HeapCellValueTag::CStr) => {
                         read_heap_cell!(d2,
                             (HeapCellValueTag::AttrVar, h) => {
@@ -667,15 +460,18 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
 
                         Self::unify_partial_string(self, d2, d1);
                     }
+                    */
                     (HeapCellValueTag::F64, f1) => {
                         Self::unify_f64(self, f1, d2);
                     }
                     (HeapCellValueTag::Fixnum, n1) => {
                         Self::unify_fixnum(self, n1, d2);
                     }
+                    /*
                     (HeapCellValueTag::Char, c1) => {
                         Self::unify_char(self, c1, d2);
                     }
+                    */
                     (HeapCellValueTag::Cons, ptr_1) => {
                         Self::unify_constant(self, ptr_1, d2);
                     }
@@ -709,12 +505,12 @@ fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellVa
     let value = machine_st.store(MachineState::deref(machine_st, value));
 
     if value.is_ref() && !value.is_stack_var() {
-        let root_loc = value.get_value() as usize;
+        machine_st.heap[0] = value;
 
         for cell in stackful_preorder_iter::<NonListElider>(
             &mut machine_st.heap,
             &mut machine_st.stack,
-            root_loc, // value,
+            0,
         ) {
             let cell = unmark_cell_bits!(cell);
 
index 0218a812f5df5d05eac9cd6a067760efa1269396..fb8dc197f14b7515dd90f3f7bc9f921998df7557 100644 (file)
@@ -1,15 +1,10 @@
 /* A simple macro to count the arguments in a variadic list
  * 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 {
     ($c: expr) => {
-        HeapCellValue::build_with(HeapCellValueTag::Char, $c as u64)
+        HeapCellValue::from_bytes(AtomCell::new_char_inlined($c).into_bytes())
     };
 }
 
@@ -46,32 +41,23 @@ macro_rules! empty_list_as_cell {
 macro_rules! atom_as_cell {
     ($atom:expr) => {
         HeapCellValue::from_bytes(
-            AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::Atom).into_bytes(),
+            AtomCell::build_with($atom.index, 0).into_bytes(),
         )
     };
     ($atom:expr, $arity:expr) => {
         HeapCellValue::from_bytes(
-            AtomCell::build_with($atom.flat_index(), $arity as u16, HeapCellValueTag::Atom)
+            AtomCell::build_with($atom.index, $arity as u8)
                 .into_bytes(),
         )
     };
 }
 
-macro_rules! cell_as_string {
+macro_rules! cell_as_atom {
     ($cell:expr) => {
-        PartialString::from(cell_as_atom!($cell))
+        AtomCell::from_bytes($cell.into_bytes()).get_name()
     };
 }
 
-macro_rules! cell_as_atom {
-    ($cell:expr) => {{
-        let cell = AtomCell::from_bytes($cell.into_bytes());
-        let name = (cell.get_index() as u64) << 3;
-
-        Atom::from(name)
-    }};
-}
-
 macro_rules! cell_as_atom_cell {
     ($cell:expr) => {
         AtomCell::from_bytes($cell.into_bytes())
@@ -91,26 +77,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 {
     ($h:expr) => {
         HeapCellValue::build_with(HeapCellValueTag::PStrLoc, $h as u64)
     };
 }
 
-macro_rules! pstr_offset_as_cell {
-    ($h:expr) => {
-        HeapCellValue::build_with(HeapCellValueTag::PStrOffset, $h as u64)
-    };
-}
-
 macro_rules! list_loc_as_cell {
     ($h:expr) => {
         HeapCellValue::build_with(HeapCellValueTag::Lis, $h as u64)
@@ -185,38 +157,6 @@ macro_rules! untyped_arena_ptr_as_cell {
     };
 }
 
-macro_rules! atom_as_cstr_cell {
-    ($atom:expr) => {{
-        let offset = $atom.flat_index();
-
-        HeapCellValue::from_bytes(
-            AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(),
-        )
-    }};
-}
-
-macro_rules! string_as_cstr_cell {
-    ($ptr:expr) => {{
-        let atom: Atom = $ptr.into();
-        let offset = atom.flat_index();
-
-        HeapCellValue::from_bytes(
-            AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(),
-        )
-    }};
-}
-
-macro_rules! string_as_pstr_cell {
-    ($ptr:expr) => {{
-        let atom: Atom = $ptr.into();
-        let offset = atom.flat_index();
-
-        HeapCellValue::from_bytes(
-            AtomCell::build_with(offset as u64, 0, HeapCellValueTag::PStr).into_bytes(),
-        )
-    }};
-}
-
 macro_rules! stream_as_cell {
     ($ptr:expr) => {
         raw_ptr_as_cell!($ptr.as_ptr())
@@ -354,6 +294,7 @@ macro_rules! read_heap_cell_pat_body {
         #[allow(unused_braces)]
         $code
     }};
+    /*
     ($cell:ident, PStr, $atom:ident, $code:expr) => {{
         let $atom = cell_as_atom!($cell);
         #[allow(unused_braces)]
@@ -374,6 +315,7 @@ macro_rules! read_heap_cell_pat_body {
         #[allow(unused_braces)]
         $code
     }};
+    */
     ($cell:ident, Fixnum, $value:ident, $code:expr) => {{
         let $value = Fixnum::from_bytes($cell.into_bytes());
         #[allow(unused_braces)]
@@ -440,119 +382,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 {
     ($cmp: expr, $at_1: expr, $at_2: expr) => {{
         $cmp.set_terms($at_1, $at_2);
@@ -637,3 +466,40 @@ macro_rules! compare_term_test {
         $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![]); // TODO: return Ok(());
+        })
+    };
+}
+
+macro_rules! heap_index {
+    ($idx:expr) => {($idx) * std::mem::size_of::<HeapCellValue>()};
+}
+
+macro_rules! cell_index {
+    ($idx:expr) => {(($idx) / std::mem::size_of::<HeapCellValue>())};
+}
index 477e93826a6f1ce8d6a2726bcf8f4bd2e89ce83f..0e8b37bfe17bc45052ca7a45f7b23068b991ee20 100644 (file)
@@ -3,10 +3,8 @@
 use crate::arena::*;
 use crate::atom_table::*;
 use crate::forms::PredicateKey;
-use crate::machine::copier::*;
 use crate::machine::heap::*;
 use crate::machine::machine_indices::*;
-use crate::machine::machine_state::*;
 use crate::types::*;
 
 use std::fmt;
@@ -14,11 +12,8 @@ use std::hash::Hash;
 use std::io::{Error as IOError, ErrorKind};
 use std::ops::Neg;
 use std::rc::Rc;
-use std::sync::Arc;
 use std::vec::Vec;
 
-use crate::parser::dashu::{Integer, Rational};
-
 use fxhash::FxBuildHasher;
 use indexmap::IndexMap;
 use scryer_modular_bitfield::error::OutOfBounds;
@@ -26,7 +21,7 @@ use scryer_modular_bitfield::prelude::*;
 
 pub type Specifier = u32;
 
-pub const MAX_ARITY: usize = 1023;
+pub const MAX_ARITY: usize = 255;
 
 #[allow(clippy::upper_case_acronyms)]
 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
@@ -143,7 +138,12 @@ pub const BTERM: u32 = 0x11000;
 pub const NEGATIVE_SIGN: u32 = 0x0200;
 
 macro_rules! fixnum {
-    ($wrapper:tt, $n:expr, $arena:expr) => {
+    ($n:expr, $arena:expr) => {
+        Fixnum::build_with_checked($n)
+            .map(|n| fixnum_as_cell!(n))
+            .unwrap_or_else(|_| typed_arena_ptr_as_cell!(arena_alloc!(Integer::from($n), $arena) as TypedArenaPtr<Integer>))
+    };
+    ($wrapper:ty, $n:expr, $arena:expr) => {
         Fixnum::build_with_checked($n)
             .map(<$wrapper>::Fixnum)
             .unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena)))
@@ -272,37 +272,6 @@ impl fmt::Display for RegType {
     }
 }
 
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum VarReg {
-    ArgAndNorm(RegType, usize),
-    Norm(RegType),
-}
-
-impl VarReg {
-    pub fn norm(self) -> RegType {
-        match self {
-            VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg,
-        }
-    }
-}
-
-impl fmt::Display for VarReg {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
-            VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
-            VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg),
-            VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg),
-        }
-    }
-}
-
-impl Default for VarReg {
-    fn default() -> Self {
-        VarReg::Norm(RegType::default())
-    }
-}
-
 macro_rules! temp_v {
     ($x:expr) => {
         $crate::parser::ast::RegType::Temp($x)
@@ -410,7 +379,6 @@ pub fn default_op_dir() -> OpDir {
 #[derive(Debug, Clone)]
 pub enum ArithmeticError {
     NonEvaluableFunctor(HeapCellValue, usize),
-    UninstantiatedVar,
 }
 
 #[derive(Debug, Copy, Clone, Default)]
@@ -424,11 +392,12 @@ pub enum ParserError {
     BackQuotedString(ParserErrorSrc),
     IO(IOError, ParserErrorSrc),
     IncompleteReduction(ParserErrorSrc),
-    InvalidSingleQuotedCharacter(char, ParserErrorSrc),
-    LexicalError(lexical::Error, ParserErrorSrc),
+    InvalidSingleQuotedCharacter(ParserErrorSrc),
+    LexicalError(ParserErrorSrc),
     MissingQuote(ParserErrorSrc),
     NonPrologChar(ParserErrorSrc),
     ParseBigInt(ParserErrorSrc),
+    ResourceError(ParserErrorSrc),
     UnexpectedChar(char, ParserErrorSrc),
     // UnexpectedEOF,
     Utf8Error(ParserErrorSrc),
@@ -440,11 +409,12 @@ impl ParserError {
             &ParserError::BackQuotedString(err_src)
             | &ParserError::IO(_, err_src)
             | &ParserError::IncompleteReduction(err_src)
-            | &ParserError::InvalidSingleQuotedCharacter(_, err_src)
-            | &ParserError::LexicalError(_, err_src)
+            | &ParserError::InvalidSingleQuotedCharacter(err_src)
+            | &ParserError::LexicalError(err_src)
             | &ParserError::MissingQuote(err_src)
             | &ParserError::NonPrologChar(err_src)
             | &ParserError::ParseBigInt(err_src)
+            | &ParserError::ResourceError(err_src)
             | &ParserError::UnexpectedChar(_, err_src)
             | &ParserError::Utf8Error(err_src) => err_src,
         }
@@ -470,6 +440,7 @@ impl ParserError {
             ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
             ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
             ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
+            ParserError::ResourceError(..) => atom!("resource_error"),
         }
     }
 
@@ -487,29 +458,13 @@ impl ParserError {
         }
     }
 }
-/*
-impl From<lexical::Error> for ParserError {
-    fn from((e, err_src): (lexical::Error, ParserErrorSrc)) -> ParserError {
-        ParserError::LexicalError(e, err_src)
-    }
-}
 
-impl From<IOError> for ParserError {
-    fn from(e: IOError) -> ParserError {
-        ParserError::IO(e)
+impl From<ParserErrorSrc> for ParserError {
+    fn from(err_src: ParserErrorSrc) -> ParserError {
+        ParserError::LexicalError(err_src)
     }
 }
 
-impl From<&IOError> for ParserError {
-    fn from(error: &IOError) -> ParserError {
-        if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
-            ParserError::Utf8Error(0, 0)
-        } else {
-            ParserError::IO(error.kind().into())
-        }
-    }
-}
-*/
 #[derive(Debug, Clone, Copy)]
 pub struct CompositeOpDir<'a, 'b> {
     pub primary_op_dir: Option<&'b OpDir>,
@@ -618,16 +573,16 @@ impl Neg for Fixnum {
     }
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+/*
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Literal {
     Atom(Atom),
-    Char(char),
     CodeIndex(CodeIndex),
     Fixnum(Fixnum),
     Integer(TypedArenaPtr<Integer>),
     Rational(TypedArenaPtr<Rational>),
     Float(F64Offset),
-    String(Atom),
+    String(Rc<String>),
 }
 
 impl From<F64Ptr> for Literal {
@@ -643,7 +598,7 @@ impl fmt::Display for Literal {
             Literal::Atom(ref atom) => {
                 write!(f, "{}", atom.flat_index())
             }
-            Literal::Char(c) => write!(f, "'{}'", *c as u32),
+            // Literal::Char(c) => write!(f, "'{}'", *c as u32),
             Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64),
             Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
             Literal::Integer(ref n) => write!(f, "{}", n),
@@ -662,10 +617,14 @@ impl Literal {
         }
     }
 }
+*/
 
 pub type Var = Rc<String>;
 
-pub(crate) fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) {
+pub(crate) fn subterm_index(
+    heap: &impl SizedHeap,
+    subterm_loc: usize,
+) -> (usize, HeapCellValue) {
     let subterm = heap[subterm_loc];
 
     if subterm.is_ref() {
@@ -691,11 +650,12 @@ pub enum Term {
     AnonVar,
     Clause(Cell<RegType>, Atom, Vec<Term>),
     Cons(Cell<RegType>, Box<Term>, Box<Term>),
-    Literal(Cell<RegType>, Literal),
+    Literal(Cell<RegType>, HeapCellValue),
+    // Literal(Cell<RegType>, Literal),
     // PartialString wraps a String in anticipation of it absorbing
     // other PartialString variants in as_partial_string.
-    PartialString(Cell<RegType>, String, Box<Term>),
-    CompleteString(Cell<RegType>, Atom),
+    PartialString(Cell<RegType>, Rc<String>, Box<Term>),
+    CompleteString(Cell<RegType>, Rc<String>),
     Var(Cell<VarReg>, VarPtr),
 }
 
@@ -709,8 +669,11 @@ impl Term {
 
     pub fn name(&self) -> Option<Atom> {
         match self {
-            &Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => {
-                Some(*atom)
+            Term::Literal(_, cell) => {
+                cell.to_atom()
+            }
+            &Term::Clause(_, atom, ..) => {
+                Some(atom)
             }
             _ => None,
         }
@@ -755,11 +718,11 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec<Term> {
  */
 
 pub(crate) fn fetch_index_ptr(
-    heap: &[HeapCellValue],
+    heap: &impl SizedHeap,
     arity: usize,
     term_loc: usize,
 ) -> Option<CodeIndex> {
-    if term_loc + arity + 1 >= heap.len() {
+    if term_loc + arity + 1 >= heap.cell_len() || heap.pstr_at(term_loc + arity + 1) {
         return None;
     }
 
@@ -779,7 +742,7 @@ pub(crate) fn fetch_index_ptr(
 }
 
 pub(crate) fn blunt_index_ptr(
-    heap: &mut [HeapCellValue],
+    heap: &mut impl SizedHeapMut,
     key: PredicateKey,
     term_loc: usize,
 ) -> bool {
@@ -792,7 +755,7 @@ pub(crate) fn blunt_index_ptr(
 }
 
 pub(crate) fn unfold_by_str_once(
-    heap: &mut [HeapCellValue],
+    heap: &mut impl SizedHeapMut,
     start_term: HeapCellValue,
     atom: Atom,
 ) -> Option<usize> {
@@ -816,7 +779,7 @@ pub(crate) fn unfold_by_str_once(
 }
 
 pub fn unfold_by_str(
-    heap: &mut [HeapCellValue],
+    heap: &mut impl SizedHeapMut,
     mut start_term: HeapCellValue,
     atom: Atom,
 ) -> Vec<HeapCellValue> {
@@ -857,7 +820,7 @@ pub fn unfold_by_str_locs(
 */
 
 pub fn unfold_by_str_locs(
-    heap: &mut [HeapCellValue],
+    heap: &mut impl SizedHeapMut,
     mut term_loc: usize,
     atom: Atom,
 ) -> Vec<(HeapCellValue, usize)> {
@@ -875,11 +838,14 @@ pub fn unfold_by_str_locs(
     terms
 }
 
-pub fn term_name(heap: &[HeapCellValue], mut term_loc: usize) -> Option<Atom> {
+pub fn term_predicate_key(
+    heap: &impl SizedHeap,
+    mut term_loc: usize,
+) -> Option<PredicateKey> {
     loop {
         read_heap_cell!(heap[term_loc],
-            (HeapCellValueTag::Atom, (name, _arity)) => {
-                return Some(name);
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                return Some((name, arity));
             }
             (HeapCellValueTag::Str, s) => {
                 term_loc = s;
@@ -898,32 +864,6 @@ pub fn term_name(heap: &[HeapCellValue], mut term_loc: usize) -> Option<Atom> {
     }
 }
 
-pub fn term_arity(heap: &[HeapCellValue], mut term_loc: usize) -> usize {
-    loop {
-        read_heap_cell!(heap[term_loc],
-            (HeapCellValueTag::Atom, (_name, arity)) => {
-                return arity;
-            }
-            (HeapCellValueTag::Str, s) => {
-                term_loc = s;
-            }
-            (HeapCellValueTag::Lis) => {
-                return 2;
-            }
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                if h != term_loc {
-                    term_loc = h;
-                } else {
-                    return 0;
-                }
-            }
-            _ => {
-                return 0;
-            }
-        );
-    }
-}
-
 pub fn inverse_var_locs_from_iter<I: Iterator<Item = HeapCellValue>>(iter: I) -> InverseVarLocs {
     let mut occurrence_set: IndexMap<HeapCellValue, usize, FxBuildHasher> =
         IndexMap::with_hasher(FxBuildHasher::default());
@@ -970,7 +910,7 @@ pub fn term_deref(heap: &[HeapCellValue], mut term_loc: usize) -> HeapCellValue
 }
 */
 
-pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Option<usize> {
+pub fn term_nth_arg(heap: &impl SizedHeap, mut term_loc: usize, n: usize) -> Option<usize> {
     loop {
         read_heap_cell!(heap[term_loc],
             (HeapCellValueTag::Str, s) => {
@@ -1010,108 +950,55 @@ pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Op
     }
 }
 
-pub type VarLocs = IndexMap<Var, HeapCellValue, FxBuildHasher>;
-pub type InverseVarLocs = IndexMap<usize, Var, FxBuildHasher>;
-
 #[derive(Debug)]
-pub struct FocusedHeap {
-    pub heap: Vec<HeapCellValue>,
+pub struct TermWriteResult {
     pub focus: usize,
     pub inverse_var_locs: InverseVarLocs,
 }
 
-impl FocusedHeap {
-    pub fn empty() -> Self {
-        Self {
-            heap: vec![],
-            focus: 0,
-            inverse_var_locs: InverseVarLocs::default(),
-        }
-    }
-
-    pub fn copy_term_from_machine_heap(
-        &mut self,
-        machine_st: &mut MachineState,
-        cell: HeapCellValue,
-    ) {
-        let hb = machine_st.heap.len();
-
-        copy_term(
-            CopyBallTerm::new(
-                &mut machine_st.attr_var_init.attr_var_queue,
-                &mut machine_st.stack,
-                &mut machine_st.heap,
-                &mut self.heap,
-            ),
-            cell,
-            AttrVarPolicy::DeepCopy,
-        );
-
-        for cell in self.heap.iter_mut() {
-            *cell = *cell - hb;
-        }
-    }
-
-    pub fn as_ref_mut(&mut self, focus: usize) -> FocusedHeapRefMut {
-        FocusedHeapRefMut {
-            heap: &mut self.heap,
-            focus,
-        }
-    }
-
-    pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue {
-        use crate::machine::heap::*;
-
-        let cell = self.heap[term_loc];
-        heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell))
-    }
-
-    pub fn name(&self, term_loc: usize) -> Option<Atom> {
-        term_name(&self.heap, term_loc)
-    }
-
-    pub fn arity(&self, term_loc: usize) -> usize {
-        term_arity(&self.heap, term_loc)
-    }
-
-    pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option<usize> {
-        term_nth_arg(&self.heap, term_loc, n)
-    }
-}
+pub type VarLocs = IndexMap<Var, HeapCellValue, FxBuildHasher>;
+pub type InverseVarLocs = IndexMap<usize, Var, FxBuildHasher>;
 
+#[derive(Debug)]
 pub struct FocusedHeapRefMut<'a> {
-    pub heap: &'a mut Vec<HeapCellValue>,
+    pub heap: &'a mut Heap,
     pub focus: usize,
 }
 
 impl<'a> FocusedHeapRefMut<'a> {
-    pub fn name(&self, term_loc: usize) -> Option<Atom> {
-        term_name(&self.heap, term_loc)
+    #[inline]
+    pub fn from(heap: &'a mut Heap, focus: usize) -> Self {
+        Self { heap, focus }
+    }
+
+    pub fn predicate_key(&self, term_loc: usize) -> Option<PredicateKey> {
+        term_predicate_key(self.heap, term_loc)
     }
 
     pub fn arity(&self, term_loc: usize) -> usize {
-        term_arity(&self.heap, term_loc)
+        self.predicate_key(term_loc)
+            .map(|(_, arity)| arity)
+            .unwrap_or(0)
     }
 
     pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue {
-        use crate::machine::heap::*;
-
         let cell = self.heap[term_loc];
-        heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell))
+        heap_bound_store(self.heap, heap_bound_deref(self.heap, cell))
     }
 
     pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option<usize> {
         term_nth_arg(self.heap, term_loc, n)
     }
 
-    pub fn from_cell(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
+    /*
+    pub fn from_cell(heap: &'a mut Heap, cell: HeapCellValue) -> Self {
         let focus = read_heap_cell!(cell,
             (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
                 h
             }
             _ => {
                 let h = heap.len();
-                heap.push(cell);
+                heap.push_cell(cell).unwrap();
 
                 h
             }
@@ -1119,4 +1006,5 @@ impl<'a> FocusedHeapRefMut<'a> {
 
         Self { heap, focus }
     }
+    */
 }
index 05868fbfcdd791e74ee5c0f3a2b8a9b302810a93..18aa18048e7cf8a92f0bc6c8e3ebd5aa6e943f85 100644 (file)
@@ -1,11 +1,13 @@
-use lexical::{FromLexicalLossy, parse_lossy};
+use lexical::{FromLexical, parse};
 
-use crate::arena::ArenaAllocated;
+use crate::arena::*;
 use crate::atom_table::*;
+use crate::machine::heap::*;
 pub use crate::machine::machine_state::*;
 use crate::parser::ast::*;
 use crate::parser::char_reader::*;
 use crate::parser::dashu::Integer;
+use crate::types::*;
 
 use std::convert::TryFrom;
 use std::fmt;
@@ -31,8 +33,9 @@ struct LayoutInfo {
 
 #[derive(Debug, PartialEq)]
 pub enum Token {
-    Literal(Literal),
+    Literal(HeapCellValue),
     Var(String),
+    String(String),
     Open,              // '('
     OpenCT,            // '('
     Close,             // ')'
@@ -46,22 +49,46 @@ pub enum Token {
 }
 
 impl Token {
+    pub(super) fn byte_size(&self, flags: MachineFlags) -> usize {
+        match self {
+            Token::String(string) if flags.double_quotes.is_codes() => {
+                2 * string.chars().count() + 1
+            }
+            Token::String(string) => {
+                Heap::compute_pstr_size(&string)
+            }
+            Token::Literal(_) |
+            Token::Comma |
+            Token::HeadTailSeparator |
+            Token::Open |
+            Token::OpenCT |
+            Token::OpenCurly |
+            Token::OpenList |
+            Token::Var(_) => {
+                heap_index!(1)
+            }
+            _ => {
+                0
+            }
+        }
+    }
+
     #[inline]
     pub(super) fn is_end(&self) -> bool {
         matches!(self, Token::End)
     }
 }
 
-pub struct Lexer<'a, R> {
+pub struct LexerParser<'a, R> {
     pub(crate) reader: R,
     pub(crate) machine_st: &'a mut MachineState,
     pub(crate) line_num: usize,
     pub(crate) col_num: usize,
 }
 
-impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
+impl<'a, R: fmt::Debug> fmt::Debug for LexerParser<'a, R> {
     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("line_num", &self.line_num)
             .field("col_num", &self.col_num)
@@ -69,9 +96,9 @@ impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
     }
 }
 
-impl<'a, R: CharRead> Lexer<'a, R> {
+impl<'a, R: CharRead> LexerParser<'a, R> {
     pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
-        Lexer {
+        LexerParser {
             reader: src,
             machine_st,
             line_num: 0,
@@ -93,11 +120,6 @@ impl<'a, R: CharRead> Lexer<'a, R> {
         }
     }
 
-    #[inline]
-    pub fn loc_to_err_src(&self) -> ParserErrorSrc {
-        ParserErrorSrc { line_num: self.line_num, col_num: self.col_num }
-    }
-
     #[inline(always)]
     fn return_char(&mut self, c: char) {
         self.reader.put_back_char(c);
@@ -460,14 +482,16 @@ impl<'a, R: CharRead> Lexer<'a, R> {
             }
 
             i64::from_str_radix(&token, 16)
-                .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
+                .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
                 .or_else(|_| {
                     Integer::from_str_radix(&token, 16)
                         .map(|n| {
-                            Token::Literal(Literal::Integer(arena_alloc!(
-                                n,
-                                &mut self.machine_st.arena
-                            )))
+                            Token::Literal(typed_arena_ptr_as_cell!(
+                                arena_alloc!(
+                                    n,
+                                    &mut self.machine_st.arena
+                                ) as TypedArenaPtr<Integer>
+                            ))
                         })
                         .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
                 })
@@ -495,14 +519,16 @@ impl<'a, R: CharRead> Lexer<'a, R> {
             }
 
             i64::from_str_radix(&token, 8)
-                .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
+                .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
                 .or_else(|_| {
                     Integer::from_str_radix(&token, 8)
                         .map(|n| {
-                            Token::Literal(Literal::Integer(arena_alloc!(
-                                n,
-                                &mut self.machine_st.arena
-                            )))
+                            Token::Literal(typed_arena_ptr_as_cell!(
+                                arena_alloc!(
+                                    n,
+                                    &mut self.machine_st.arena
+                                ) as TypedArenaPtr<Integer>
+                            ))
                         })
                         .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
                 })
@@ -530,14 +556,16 @@ impl<'a, R: CharRead> Lexer<'a, R> {
             }
 
             i64::from_str_radix(&token, 2)
-                .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
+                .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
                 .or_else(|_| {
                     Integer::from_str_radix(&token, 2)
                         .map(|n| {
-                            Token::Literal(Literal::Integer(arena_alloc!(
-                                n,
-                                &mut self.machine_st.arena
-                            )))
+                            Token::Literal(typed_arena_ptr_as_cell!(
+                                arena_alloc!(
+                                    n,
+                                    &mut self.machine_st.arena
+                                ) as TypedArenaPtr<Integer>
+                            ))
                         })
                         .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
                 })
@@ -610,11 +638,11 @@ impl<'a, R: CharRead> Lexer<'a, R> {
 
                 if !token.is_empty() && token.chars().nth(1).is_none() {
                     if let Some(c) = token.chars().next() {
-                        return Ok(Token::Literal(Literal::Char(c)));
+                        return Ok(Token::Literal(char_as_cell!(c)));
                     }
                 }
             } else {
-                return Err(ParserError::InvalidSingleQuotedCharacter(c, self.loc_to_err_src()));
+                return Err(ParserError::InvalidSingleQuotedCharacter(self.loc_to_err_src()));
             }
         } else {
             match self.get_back_quoted_string() {
@@ -624,26 +652,29 @@ impl<'a, R: CharRead> Lexer<'a, R> {
         }
 
         if token.as_str() == "[]" {
-            Ok(Token::Literal(Literal::Atom(atom!("[]"))))
+            Ok(Token::Literal(empty_list_as_cell!()))
         } else {
-            Ok(Token::Literal(Literal::Atom(AtomTable::build_with(
+            Ok(Token::Literal(atom_as_cell!(AtomTable::build_with(
                 &self.machine_st.atom_tbl,
                 &token,
             ))))
         }
     }
 
-    fn parse_lossy_wrapper<T: FromLexicalLossy>(&self, token: String) -> Result<T, ParserError> {
-        match parse_lossy::<T, _>(token.as_bytes()) {
+    fn parse_lossy_wrapper<T: FromLexical>(&self, token: &str) -> Result<T, ParserError> {
+        match parse::<T, _>(token.as_bytes()) {
             Ok(n) => Ok(n),
-            Err(e) => return Err(ParserError::LexicalError(e, self.loc_to_err_src())),
+            Err(_) => return Err(ParserError::LexicalError(self.loc_to_err_src())),
         }
     }
 
     fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
         self.return_char(token.pop().unwrap());
-        let n = self.parse_lossy_wrapper::<f64>(token)?;
-        Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena))))
+        let n = self.parse_lossy_wrapper::<f64>(&token)?;
+        Ok(Token::Literal(HeapCellValue::from(float_alloc!(
+            n,
+            self.machine_st.arena
+        ))))
     }
 
     fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
@@ -685,15 +716,17 @@ impl<'a, R: CharRead> Lexer<'a, R> {
 
                 token
                     .parse::<i64>()
-                    .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
+                    .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
                     .or_else(|_| {
                         token
                             .parse::<Integer>()
                             .map(|n| {
-                                Token::Literal(Literal::Integer(arena_alloc!(
-                                    n,
-                                    &mut self.machine_st.arena
-                                )))
+                                Token::Literal(typed_arena_ptr_as_cell!(
+                                    arena_alloc!(
+                                        n,
+                                        &mut self.machine_st.arena
+                                    ) as TypedArenaPtr<Integer>
+                                ))
                             })
                             .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
                     })
@@ -757,9 +790,8 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                             }
                         }
 
-                        let n = self.parse_lossy_wrapper::<f64>(token)?;
-
-                        Ok(Token::Literal(Literal::from(float_alloc!(
+                        let n = self.parse_lossy_wrapper::<f64>(&token)?;
+                        Ok(Token::Literal(HeapCellValue::from(float_alloc!(
                             n,
                             self.machine_st.arena
                         ))))
@@ -767,8 +799,8 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                         return self.vacate_with_float(token);
                     }
                 } else {
-                    let n = self.parse_lossy_wrapper::<f64>(token)?;
-                    Ok(Token::Literal(Literal::from(float_alloc!(
+                    let n = self.parse_lossy_wrapper::<f64>(&token)?;
+                    Ok(Token::Literal(HeapCellValue::from(float_alloc!(
                         n,
                         self.machine_st.arena
                     ))))
@@ -778,15 +810,17 @@ impl<'a, R: CharRead> Lexer<'a, R> {
 
                 token
                     .parse::<i64>()
-                    .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
+                    .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
                     .or_else(|_| {
                         token
                             .parse::<Integer>()
                             .map(|n| {
-                                Token::Literal(Literal::Integer(arena_alloc!(
-                                    n,
-                                    &mut self.machine_st.arena
-                                )))
+                                Token::Literal(typed_arena_ptr_as_cell!(
+                                    arena_alloc!(
+                                        n,
+                                        &mut self.machine_st.arena
+                                    ) as TypedArenaPtr<Integer>
+                                ))
                             })
                             .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
                     })
@@ -798,16 +832,18 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                         token
                             .parse::<i64>()
                             .map(|n| {
-                                Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
+                                Token::Literal(fixnum!(n, &mut self.machine_st.arena))
                             })
                             .or_else(|_| {
                                 token
                                     .parse::<Integer>()
                                     .map(|n| {
-                                        Token::Literal(Literal::Integer(arena_alloc!(
-                                            n,
-                                            &mut self.machine_st.arena
-                                        )))
+                                        Token::Literal(typed_arena_ptr_as_cell!(
+                                            arena_alloc!(
+                                                n,
+                                                &mut self.machine_st.arena
+                                            ) as TypedArenaPtr<Integer>
+                                        ))
                                     })
                                     .map_err(|_| {
                                         ParserError::ParseBigInt(self.loc_to_err_src())
@@ -823,16 +859,18 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                         token
                             .parse::<i64>()
                             .map(|n| {
-                                Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
+                                Token::Literal(fixnum!(n, &mut self.machine_st.arena))
                             })
                             .or_else(|_| {
                                 token
                                     .parse::<Integer>()
                                     .map(|n| {
-                                        Token::Literal(Literal::Integer(arena_alloc!(
-                                            n,
-                                            &mut self.machine_st.arena
-                                        )))
+                                        Token::Literal(typed_arena_ptr_as_cell!(
+                                            arena_alloc!(
+                                                n,
+                                                &mut self.machine_st.arena
+                                            ) as TypedArenaPtr<Integer>
+                                        ))
                                     })
                                     .map_err(|_| {
                                         ParserError::ParseBigInt(self.loc_to_err_src())
@@ -848,16 +886,18 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                         token
                             .parse::<i64>()
                             .map(|n| {
-                                Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
+                                Token::Literal(fixnum!(n, &mut self.machine_st.arena))
                             })
                             .or_else(|_| {
                                 token
                                     .parse::<Integer>()
                                     .map(|n| {
-                                        Token::Literal(Literal::Integer(arena_alloc!(
-                                            n,
-                                            &mut self.machine_st.arena
-                                        )))
+                                        Token::Literal(typed_arena_ptr_as_cell!(
+                                            arena_alloc!(
+                                                n,
+                                                &mut self.machine_st.arena
+                                            ) as TypedArenaPtr<Integer>
+                                        ))
                                     })
                                     .map_err(|_| {
                                         ParserError::ParseBigInt(self.loc_to_err_src())
@@ -879,14 +919,14 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                         self.skip_char(c);
                         self.return_char('\'');
 
-                        return Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(0))));
+                        return Ok(Token::Literal(fixnum_as_cell!(Fixnum::build_with(0))));
                     } else {
                         self.return_char('\\');
                     }
                 }
 
                 self.get_single_quoted_char()
-                    .map(|c| Token::Literal(Literal::Fixnum(Fixnum::build_with(c as i64))))
+                    .map(|c| Token::Literal(fixnum_as_cell!(Fixnum::build_with(c as i64))))
                     .or_else(|err| {
                         match err {
                             ParserError::UnexpectedChar('\'', ..) => {}
@@ -898,16 +938,18 @@ impl<'a, R: CharRead> Lexer<'a, R> {
                         token
                             .parse::<i64>()
                             .map(|n| {
-                                Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
+                                Token::Literal(fixnum!(n, &mut self.machine_st.arena))
                             })
                             .or_else(|_| {
                                 token
                                     .parse::<Integer>()
                                     .map(|n| {
-                                        Token::Literal(Literal::Integer(arena_alloc!(
-                                            n,
-                                            &mut self.machine_st.arena
-                                        )))
+                                        Token::Literal(typed_arena_ptr_as_cell!(
+                                            arena_alloc!(
+                                                n,
+                                                &mut self.machine_st.arena
+                                            ) as TypedArenaPtr<Integer>
+                                        ))
                                     })
                                     .map_err(|_| {
                                         ParserError::ParseBigInt(self.loc_to_err_src())
@@ -917,15 +959,17 @@ impl<'a, R: CharRead> Lexer<'a, R> {
             } else {
                 token
                     .parse::<i64>()
-                    .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
+                    .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
                     .or_else(|_| {
                         token
                             .parse::<Integer>()
                             .map(|n| {
-                                Token::Literal(Literal::Integer(arena_alloc!(
-                                    n,
-                                    &mut self.machine_st.arena
-                                )))
+                                Token::Literal(typed_arena_ptr_as_cell!(
+                                    arena_alloc!(
+                                        n,
+                                        &mut self.machine_st.arena
+                                    ) as TypedArenaPtr<Integer>
+                                ))
                             })
                             .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
                     })
@@ -933,15 +977,17 @@ impl<'a, R: CharRead> Lexer<'a, R> {
         } else {
             token
                 .parse::<i64>()
-                .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
+                .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
                 .or_else(|_| {
                     token
                         .parse::<Integer>()
                         .map(|n| {
-                            Token::Literal(Literal::Integer(arena_alloc!(
-                                n,
-                                &mut self.machine_st.arena
-                            )))
+                            Token::Literal(typed_arena_ptr_as_cell!(
+                                arena_alloc!(
+                                    n,
+                                    &mut self.machine_st.arena
+                                ) as TypedArenaPtr<Integer>
+                            ))
                         })
                         .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
                 })
@@ -1085,12 +1131,12 @@ impl<'a, R: CharRead> Lexer<'a, R> {
 
                 if 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 {
-                        Ok(Token::Literal(Literal::Atom(atom)))
+                        let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s);
+                        Ok(Token::Literal(atom_as_cell!(atom)))
                     } else {
-                        Ok(Token::Literal(Literal::String(atom)))
+                        Ok(Token::String(s))
                     };
                 }
 
@@ -1104,13 +1150,3 @@ impl<'a, R: CharRead> Lexer<'a, R> {
         }
     }
 }
-
-fn parse_float_lossy(token: &str) -> Result<f64, ParserError> {
-    const FORMAT: u128 = lexical::format::STANDARD;
-    let options = lexical::ParseFloatOptions::builder()
-        .lossy(true)
-        .build()
-        .unwrap();
-    let n = lexical::parse_with_options::<f64, _, FORMAT>(token.as_bytes(), &options)?;
-    Ok(n)
-}
index 5271b4a047209e8a82cd732efb1005a5d3daa330..d059eee397e484029d6f45a8fbc42b979e562e27 100644 (file)
@@ -3,14 +3,13 @@ use dashu::Rational;
 
 use crate::arena::*;
 use crate::atom_table::*;
-use crate::machine::heap::{heap_bound_deref, heap_bound_store};
-use crate::machine::partial_string::*;
+use crate::forms::Number;
+use crate::machine::heap::*;
 use crate::parser::ast::*;
 use crate::parser::char_reader::*;
 use crate::parser::lexer::*;
 use crate::types::*;
 
-use std::mem;
 use std::ops::Neg;
 use std::rc::Rc;
 
@@ -53,7 +52,7 @@ provided via the Provided variant.
 #[derive(Debug)]
 pub enum Tokens {
     Default,
-    Provided(Vec<Token>),
+    Provided(Vec<Token>, usize),
 }
 
 impl TokenType {
@@ -176,22 +175,27 @@ pub struct CompositeOpDesc {
 }
 
 #[derive(Debug)]
-pub struct Parser<'a, R> {
-    pub lexer: Lexer<'a, R>,
+struct Parser<'a> {
     tokens: Vec<Token>,
     stack: Vec<TokenDesc>,
-    terms: Vec<HeapCellValue>,
+    terms: HeapWriter<'a>,
+    arena: &'a mut Arena,
+    flags: MachineFlags,
+    line_num: &'a mut usize,
+    col_num: &'a mut usize,
     var_locs: VarLocs,
     inverse_var_locs: InverseVarLocs,
 }
 
-fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> {
+pub fn read_tokens<R: CharRead>(lexer: &mut LexerParser<R>) -> Result<(Vec<Token>, usize), ParserError> {
     let mut tokens = vec![];
+    let mut term_size = 0;
 
     loop {
         match lexer.next_token() {
             Ok(token) => {
                 let at_end = token.is_end();
+                term_size += token.byte_size(lexer.machine_st.flags);
                 tokens.push(token);
 
                 if at_end {
@@ -209,19 +213,11 @@ fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserEr
 
     tokens.reverse();
 
-    Ok(tokens)
-}
-
-fn atomize_literal(atom_tbl: &AtomTable, c: Literal) -> Option<Atom> {
-    match c {
-        Literal::Atom(ref name) => Some(*name),
-        Literal::Char(c) => Some(AtomTable::build_with(atom_tbl, &c.to_string())),
-        _ => None,
-    }
+    Ok((tokens, term_size))
 }
 
 pub(crate) fn as_partial_string(
-    heap: &[HeapCellValue],
+    heap: &impl SizedHeap,
     head: HeapCellValue,
     tail: HeapCellValue,
 ) -> Option<(String, Option<HeapCellValue>)> {
@@ -240,9 +236,6 @@ pub(crate) fn as_partial_string(
                return None;
            }
        }
-       (HeapCellValueTag::Char, c) => {
-           c.to_string()
-       }
        _ => {
            return None;
        }
@@ -263,9 +256,6 @@ pub(crate) fn as_partial_string(
                            break;
                        }
                    }
-                   (HeapCellValueTag::Char, c) => {
-                       string.push(c);
-                   }
                    _ => {
                        return None;
                    }
@@ -274,16 +264,9 @@ pub(crate) fn as_partial_string(
                tail = heap[l+1];
            }
            (HeapCellValueTag::PStrLoc, l) => {
-               let (index, n) = pstr_loc_and_offset(&heap, l);
-               let n = n.get_num() as usize;
-
-               string += &*cell_as_string!(heap[index]).as_str_from(n);
-               tail = heap[l+1];
-           }
-           (HeapCellValueTag::CStr, cstr_atom) => {
-               string += &*cstr_atom.as_str();
-               tail = empty_list_as_cell!();
-               break;
+               let (pstr, tail_loc) = heap.scan_slice_to_str(l);
+               string += pstr;
+               tail = heap[tail_loc];
            }
            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
                if heap[h] != tail {
@@ -316,36 +299,15 @@ pub(crate) fn as_partial_string(
     )
 }
 
-impl<'a, R: CharRead> Parser<'a, R> {
-    pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self {
-        Parser {
-            lexer: Lexer::new(stream, machine_st),
-            tokens: vec![],
-            stack: vec![],
-            terms: vec![],
-            var_locs: VarLocs::default(),
-            inverse_var_locs: InverseVarLocs::default(),
-        }
-    }
-
-    pub fn from_lexer(lexer: Lexer<'a, R>) -> Self {
-        Parser {
-            lexer,
-            tokens: vec![],
-            stack: vec![],
-            terms: vec![],
-            var_locs: VarLocs::default(),
-            inverse_var_locs: InverseVarLocs::default(),
-        }
-    }
-
+impl<'a> Parser<'a> {
     fn get_term_name(&self, td: TokenDesc) -> Option<Atom> {
         match td.tt {
             TokenType::HeadTailSeparator => Some(atom!("|")),
             TokenType::Comma => Some(atom!(",")),
             TokenType::Term { heap_loc } => {
                 if heap_loc.is_ref() {
-                    term_name(&self.terms, heap_loc.get_value() as usize)
+                    term_predicate_key(&self.terms, heap_loc.get_value() as usize)
+                        .map(|key| key.0)
                 } else {
                     None
                 }
@@ -354,16 +316,6 @@ impl<'a, R: CharRead> Parser<'a, R> {
         }
     }
 
-    #[inline]
-    pub fn line_num(&self) -> usize {
-        self.lexer.line_num
-    }
-
-    #[inline]
-    pub fn col_num(&self) -> usize {
-        self.lexer.col_num
-    }
-
     fn push_binary_op(
         &mut self,
         op: TokenDesc,
@@ -382,13 +334,15 @@ impl<'a, R: CharRead> Parser<'a, R> {
             } = operand_1
             {
                 if let Some(name) = self.get_term_name(op) {
-                    let str_loc = self.terms.len();
+                    let str_loc = self.terms.cell_len();
 
-                    self.terms.push(atom_as_cell!(name, 2));
-                    self.terms.push(arg1);
-                    self.terms.push(arg2);
+                    self.terms.write_with(|section| {
+                        section.push_cell(atom_as_cell!(name, 2));
+                        section.push_cell(arg1);
+                        section.push_cell(arg2);
 
-                    self.terms.push(str_loc_as_cell!(str_loc));
+                        section.push_cell(str_loc_as_cell!(str_loc));
+                    });
 
                     self.stack.push(TokenDesc {
                         tt: TokenType::Term {
@@ -404,10 +358,6 @@ impl<'a, R: CharRead> Parser<'a, R> {
     }
 
     fn push_unary_op(&mut self, op: TokenDesc, operand: TokenDesc, spec: Specifier) {
-        // if is_postfix!(assoc) {
-        //     mem::swap(&mut op, &mut operand);
-        // }
-
         if let TokenDesc {
             tt: TokenType::Term { heap_loc: arg1 },
             ..
@@ -419,11 +369,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
             } = op
             {
                 if let Some(name) = self.get_term_name(op) {
-                    let str_loc = self.terms.len();
+                    let str_loc = self.terms.cell_len();
 
-                    self.terms.push(atom_as_cell!(name, 1));
-                    self.terms.push(arg1);
-                    self.terms.push(str_loc_as_cell!(str_loc));
+                    self.terms.write_with(|section| {
+                        section.push_cell(atom_as_cell!(name, 1));
+                        section.push_cell(arg1);
+                        section.push_cell(str_loc_as_cell!(str_loc));
+                    });
 
                     self.stack.push(TokenDesc {
                         tt: TokenType::Term {
@@ -439,8 +391,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
     }
 
     fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) {
-        let h = self.terms.len();
-        self.terms.push(atom_as_cell!(atom));
+        let h = self.terms.cell_len();
+        self.terms.write_with(|section| section.push_cell(atom_as_cell!(atom)));
         self.stack.push(TokenDesc {
             tt: TokenType::Term {
                 heap_loc: heap_loc_as_cell!(h),
@@ -452,51 +404,61 @@ impl<'a, R: CharRead> Parser<'a, R> {
     }
 
     fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
-        let heap_loc = heap_loc_as_cell!(self.terms.len());
+        let heap_loc = heap_loc_as_cell!(self.terms.cell_len());
 
         let tt = match token {
-            Token::Literal(Literal::String(s))
-                if self.lexer.machine_st.flags.double_quotes.is_codes() =>
-            {
+            Token::String(s) if self.flags.double_quotes.is_codes() => {
                 let mut list = empty_list_as_cell!();
 
-                for c in s.as_str().chars().rev() {
-                    let h = self.terms.len();
+                self.terms.write_with(|section| {
+                    for c in s.as_str().chars().rev() {
+                        let h = section.cell_len();
 
-                    self.terms
-                        .push(fixnum_as_cell!(Fixnum::build_with(c as i64)));
-                    self.terms.push(list);
+                        section.push_cell(fixnum_as_cell!(Fixnum::build_with(c as i64)));
+                        section.push_cell(list);
 
-                    list = list_loc_as_cell!(h);
-                }
+                        list = list_loc_as_cell!(h);
+                    }
 
-                self.terms.push(list);
+                    section.push_cell(list);
+                });
 
                 TokenType::Term { heap_loc: list }
             }
-            Token::Literal(Literal::String(s))
-                if self.lexer.machine_st.flags.double_quotes.is_chars() =>
-            {
-                if s.is_empty() {
-                    self.terms.push(empty_list_as_cell!());
-                } else {
-                    self.terms.push(string_as_cstr_cell!(s));
-                }
+            Token::String(s) => {
+                debug_assert!(self.flags.double_quotes.is_chars());
+                let mut pstr_cell = heap_loc;
 
-                TokenType::Term { heap_loc }
-            }
-            Token::Literal(Literal::Char(c)) => {
-                // soon this will be gone due to chars being folded
-                // into atoms
-                self.terms.push(atom_as_cell!(atomize_literal(
-                    &self.lexer.machine_st.atom_tbl,
-                    Literal::Char(c),
-                ).unwrap()));
+                if s == "\u{0}" {
+                    let h = self.terms.cell_len();
 
-                TokenType::Term { heap_loc }
+                    self.terms.write_with(|section| {
+                        section.push_cell(char_as_cell!('\u{0}'));
+                        section.push_cell(empty_list_as_cell!());
+                        section.push_cell(list_loc_as_cell!(h));
+                    });
+
+                    TokenType::Term { heap_loc: heap_loc_as_cell!(h + 2) }
+                } else {
+                    self.terms.write_with(|section| {
+                        match section.push_pstr(&s) {
+                            Some(pstr_loc_cell) => {
+                                section.push_cell(empty_list_as_cell!());
+                                let h = section.cell_len();
+                                section.push_cell(pstr_loc_cell);
+                                pstr_cell = heap_loc_as_cell!(h);
+                            }
+                            None => {
+                                section.push_cell(empty_list_as_cell!());
+                            }
+                        }
+                    });
+
+                    TokenType::Term { heap_loc: pstr_cell }
+                }
             }
             Token::Literal(c) => {
-                self.terms.push(HeapCellValue::from(c));
+                self.terms.write_with(|section| section.push_cell(c));
                 TokenType::Term { heap_loc }
             }
             Token::Var(var_string) => {
@@ -504,11 +466,11 @@ impl<'a, R: CharRead> Parser<'a, R> {
 
                 match self.var_locs.get(&var).cloned() {
                     Some(heap_loc) => {
-                        self.terms.push(heap_loc);
+                        self.terms.write_with(|section| section.push_cell(heap_loc));
                         TokenType::Term { heap_loc }
                     }
                     None => {
-                        self.terms.push(heap_loc);
+                        self.terms.write_with(|section| section.push_cell(heap_loc));
 
                         // if var_string == "_", it not being present
                         // as a key of self.var_locs means it is
@@ -649,23 +611,23 @@ impl<'a, R: CharRead> Parser<'a, R> {
             return false;
         }
 
-        if self.terms.len() < arity {
+        if self.terms.cell_len() < arity {
             return false;
         }
 
         let stack_len = self.stack.len() - 2 * arity - 1;
-        let term_idx = self.terms.len();
+        let term_idx = self.terms.cell_len();
 
         let push_structure = |parser: &mut Self, name: Atom| -> TokenType {
-            parser.terms.push(atom_as_cell!(name, arity));
+            parser.terms.write_with(|section| section.push_cell(atom_as_cell!(name, arity)));
 
             for idx in (stack_len + 2..parser.stack.len()).step_by(2) {
                 let subterm = parser.term_from_stack(idx).unwrap();
-                parser.terms.push(subterm);
+                parser.terms.write_with(|section| section.push_cell(subterm));
             }
 
-            let str_loc_idx = parser.terms.len();
-            parser.terms.push(str_loc_as_cell!(term_idx));
+            let str_loc_idx = parser.terms.cell_len();
+            parser.terms.write_with(|section| section.push_cell(str_loc_as_cell!(term_idx)));
 
             TokenType::Term {
                 heap_loc: heap_loc_as_cell!(str_loc_idx),
@@ -679,39 +641,38 @@ impl<'a, R: CharRead> Parser<'a, R> {
         {
             let idx = heap_loc.get_value() as usize;
 
-            if let Some(name) = term_name(&self.terms, idx) {
+            if let Some((name, arity)) = term_predicate_key(&self.terms, idx) {
                 // reduce the '.' functor to a cons cell if it applies.
                 let new_tt = if name == atom!(".") && arity == 2 {
                     let head = self.term_from_stack(stack_len + 2).unwrap();
                     let tail = self.term_from_stack(stack_len + 4).unwrap();
+                    let cell_len = self.terms.cell_len();
 
                     match as_partial_string(&self.terms, head, tail) {
-                        Some((string_buf, Some(tail))) => {
-                            let atom =
-                                AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
+                        Some((string_buf, tail_opt)) => {
+                            let bytes_written = self.terms.write_with(|section| {
+                                let pstr_cell = section.push_pstr(&string_buf).unwrap();
+                                section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!()));
+                                section.push_cell(pstr_cell);
+                            });
 
-                            self.terms.push(string_as_pstr_cell!(atom));
-                            self.terms.push(tail);
-                            self.terms.push(pstr_loc_as_cell!(term_idx));
+                            let heap_loc = cell_index!(bytes_written) - 1 + cell_len;
 
                             TokenType::Term {
-                                heap_loc: heap_loc_as_cell!(term_idx + 2),
-                            }
-                        }
-                        Some((string_buf, None)) => {
-                            let atom =
-                                AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
-                            TokenType::Term {
-                                heap_loc: string_as_cstr_cell!(atom),
+                                heap_loc: heap_loc_as_cell!(heap_loc),
                             }
                         }
                         None => {
-                            self.terms.push(head);
-                            self.terms.push(tail);
-                            self.terms.push(list_loc_as_cell!(term_idx));
+                            let bytes_written = self.terms.write_with(|section| {
+                                section.push_cell(head);
+                                section.push_cell(tail);
+                                section.push_cell(list_loc_as_cell!(term_idx));
+                            });
 
                             TokenType::Term {
-                                heap_loc: heap_loc_as_cell!(term_idx + 2),
+                                heap_loc: heap_loc_as_cell!(
+                                    cell_len + cell_index!(bytes_written) - 1
+                                ),
                             }
                         }
                     }
@@ -747,9 +708,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
         false
     }
 
-    pub fn reset(&mut self) {
-        self.stack.clear();
-        self.var_locs.clear();
+    fn loc_to_err_src(&self) -> ParserErrorSrc {
+        ParserErrorSrc { line_num: *self.line_num, col_num: *self.col_num }
     }
 
     fn expand_comma_compacted_terms(&mut self, index: usize) -> usize {
@@ -764,17 +724,17 @@ impl<'a, R: CharRead> Parser<'a, R> {
             );
 
             if term.is_ref() &&
-               0 < op_desc.priority && op_desc.priority < self.stack[index].priority
+               0 < op_desc.priority &&
+               op_desc.priority < self.stack[index].priority
             {
                 /* '|' is a head-tail separator here, not
                  * an operator, so expand the
                  * terms it compacted out again. */
 
                 let focus = term.get_value() as usize;
-                let name_opt = term_name(&self.terms, focus);
-                let arity = term_arity(&self.terms, focus);
+                let key_opt = term_predicate_key(&self.terms, focus);
 
-                if name_opt == Some(atom!(",")) && arity == 2 {
+                if key_opt == Some((atom!(","), 2)) {
                     let terms = if op_desc.unfold_bounds == 0 {
                         unfold_by_str(&mut self.terms, term, atom!(","))
                     } else {
@@ -855,8 +815,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
         if let Some(ref mut td) = self.stack.last_mut() {
             // parsed an empty list token
             if td.tt == TokenType::OpenList {
-                let h = self.terms.len();
-                self.terms.push(empty_list_as_cell!());
+                let h = self.terms.cell_len();
+                self.terms.write_with(|section| section.push_cell(empty_list_as_cell!()));
 
                 td.spec = TERM;
                 td.tt = TokenType::Term {
@@ -886,7 +846,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
                 Some(term) => term,
                 None => {
                     return Err(ParserError::IncompleteReduction(
-                        self.lexer.loc_to_err_src(),
+                        self.loc_to_err_src(),
                     ));
                 }
             };
@@ -902,13 +862,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
             tail_term
         };
 
-        if arity > self.terms.len() {
+        if arity > self.terms.cell_len() {
             return Err(ParserError::IncompleteReduction(
-                self.lexer.loc_to_err_src(),
+                self.loc_to_err_src(),
             ));
         }
 
-        let pre_terms_len = self.terms.len();
+        let pre_terms_len = self.terms.cell_len();
 
         while let Some(token_desc) = self.stack.pop() {
             let subterm = match token_desc.tt {
@@ -922,11 +882,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
 
             arity -= 1;
 
-            let link_cell = list_loc_as_cell!(self.terms.len() + 1);
+            let link_cell = list_loc_as_cell!(self.terms.cell_len() + 1);
 
-            self.terms.push(link_cell);
-            self.terms.push(subterm);
-            self.terms.push(tail_term);
+            self.terms.write_with(|section| {
+                section.push_cell(link_cell);
+                section.push_cell(subterm);
+                section.push_cell(tail_term);
+            });
 
             tail_term = link_cell;
 
@@ -939,29 +901,22 @@ impl<'a, R: CharRead> Parser<'a, R> {
 
         self.stack.truncate(list_start_idx);
 
-        let list_loc = self.terms.len() - 3;
+        let list_loc = self.terms.cell_len() - 3;
 
         let head_term = self.terms[list_loc + 1];
         let tail_term = self.terms[list_loc + 2];
 
         let heap_loc = match as_partial_string(&self.terms, head_term, tail_term) {
-            Some((string_buf, Some(tail))) => {
+            Some((string_buf, tail_opt)) => {
                 self.terms.truncate(pre_terms_len);
 
-                let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
-
-                self.terms.push(string_as_pstr_cell!(atom));
-                self.terms.push(tail);
-                self.terms.push(pstr_loc_as_cell!(pre_terms_len));
-
-                heap_loc_as_cell!(pre_terms_len + 2)
-            }
-            Some((string_buf, None)) => {
-                self.terms.truncate(pre_terms_len);
-                let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
-                self.terms.push(string_as_cstr_cell!(atom));
+                let bytes_written = self.terms.write_with(|section| {
+                    let pstr_cell = section.push_pstr(&string_buf).unwrap();
+                    section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!()));
+                    section.push_cell(pstr_cell);
+                });
 
-                heap_loc_as_cell!(pre_terms_len)
+                heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1)
             }
             None => {
                 heap_loc_as_cell!(list_loc) // head_term
@@ -975,22 +930,6 @@ impl<'a, R: CharRead> Parser<'a, R> {
             unfold_bounds: 0,
         });
 
-        /*
-        self.terms.push(match list {
-            Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) {
-                Ok((string_buf, Some(tail))) => {
-                    Term::PartialString(Cell::default(), string_buf, tail)
-                }
-                Ok((string_buf, None)) => {
-                    let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
-                    Term::CompleteString(Cell::default(), atom)
-                }
-                Err(term) => term,
-            },
-            term => term,
-        });
-        */
-
         Ok(true)
     }
 
@@ -1001,8 +940,9 @@ impl<'a, R: CharRead> Parser<'a, R> {
 
         if let Some(ref mut td) = self.stack.last_mut() {
             if td.tt == TokenType::OpenCurly {
-                let h = self.terms.len();
-                self.terms.push(atom_as_cell!(atom!("{}")));
+                let h = self.terms.cell_len();
+
+                self.terms.write_with(|section| section.push_cell(atom_as_cell!(atom!("{}"))));
 
                 td.tt = TokenType::Term {
                     heap_loc: heap_loc_as_cell!(h),
@@ -1025,7 +965,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
 
                     if oc.tt == TokenType::OpenCurly {
                         if let TokenType::Term { heap_loc } = td.tt {
-                            let curly_idx = self.terms.len();
+                            let curly_idx = self.terms.cell_len();
 
                             oc.tt = TokenType::Term {
                                 heap_loc: heap_loc_as_cell!(curly_idx + 2),
@@ -1033,9 +973,11 @@ impl<'a, R: CharRead> Parser<'a, R> {
                             oc.priority = 0;
                             oc.spec = TERM;
 
-                            self.terms.push(atom_as_cell!(atom!("{}"), 1));
-                            self.terms.push(heap_loc);
-                            self.terms.push(str_loc_as_cell!(curly_idx));
+                            self.terms.write_with(|section| {
+                                section.push_cell(atom_as_cell!(atom!("{}"), 1));
+                                section.push_cell(heap_loc);
+                                section.push_cell(str_loc_as_cell!(curly_idx));
+                            });
 
                             /*
                             let term = match self.terms.pop() {
@@ -1089,8 +1031,6 @@ impl<'a, R: CharRead> Parser<'a, R> {
 
                 let term = if self.stack[idx].tt.sep_to_atom().is_some() {
                     atom_as_cell!(atom!("|"))
-                    // self.terms
-                    //     .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
                 } else {
                     self.term_from_stack(idx).unwrap()
                 };
@@ -1117,7 +1057,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
                 match self
                     .tokens
                     .last()
-                    .ok_or(ParserError::unexpected_eof(self.lexer.loc_to_err_src()))?
+                    .ok_or(ParserError::unexpected_eof(self.loc_to_err_src()))?
                 {
                     // do this when layout hasn't been inserted,
                     // ie. why we don't match on Token::Open.
@@ -1173,7 +1113,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
     fn negate_number<N, Negator, ToLiteral>(&mut self, n: N, negator: Negator, constr: ToLiteral)
     where
         Negator: Fn(N, &mut Arena) -> N,
-        ToLiteral: Fn(N, &mut Arena) -> Literal,
+        ToLiteral: Fn(N, &mut Arena) -> HeapCellValue,
     {
         match self.stack.last().cloned() {
             Some(
@@ -1187,7 +1127,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
                     if name == atom!("-") && (is_prefix!(spec) || is_negate!(spec)) {
                         self.stack.pop();
 
-                        let arena = &mut self.lexer.machine_st.arena;
+                        let arena = &mut self.arena;
                         let literal = constr(negator(n, arena), arena);
 
                         self.shift(Token::Literal(literal), 0, TERM);
@@ -1199,7 +1139,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             _ => {}
         }
 
-        let literal = constr(n, &mut self.lexer.machine_st.arena);
+        let literal = constr(n, &mut self.arena);
         self.shift(Token::Literal(literal), 0, TERM);
     }
 
@@ -1217,29 +1157,38 @@ impl<'a, R: CharRead> Parser<'a, R> {
         }
 
         match token {
-            Token::Literal(Literal::Fixnum(n)) => {
-                self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n))
+            Token::String(string) => {
+                self.shift(Token::String(string), 0, TERM);
             }
-            Token::Literal(Literal::Integer(n)) => {
-                self.negate_number(n, negate_int_rc, |n, _| Literal::Integer(n))
-            }
-            Token::Literal(Literal::Rational(n)) => {
-                self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r))
-            }
-            Token::Literal(Literal::Float(n)) => self.negate_number(
-                **n.as_ptr(),
-                |n, _| -n,
-                |n, arena| Literal::from(float_alloc!(n, arena)),
-            ),
             Token::Literal(c) => {
-                let atomized = atomize_literal(&self.lexer.machine_st.atom_tbl, c);
-
-                if let Some(name) = atomized {
-                    if !self.shift_op(name, op_dir)? {
-                        self.shift(Token::Literal(c), 0, TERM);
+                match Number::try_from(c) {
+                    Ok(Number::Integer(n)) => {
+                        self.negate_number(n, negate_int_rc, |n, _| typed_arena_ptr_as_cell!(n))
+                    }
+                    Ok(Number::Rational(n)) => {
+                        self.negate_number(n, negate_rat_rc, |r, _| typed_arena_ptr_as_cell!(r))
+                    }
+                    Ok(Number::Float(n)) => {
+                        use ordered_float::OrderedFloat;
+
+                        self.negate_number(
+                            n,
+                            |n, _| -n,
+                            |OrderedFloat(n), arena| HeapCellValue::from(float_alloc!(n, arena)),
+                        )
+                    }
+                    Ok(Number::Fixnum(n)) => {
+                        self.negate_number(n, |n, _| -n, |n, _| fixnum_as_cell!(n))
+                    }
+                    Err(_) => {
+                        if let Some(name) = c.to_atom() {
+                            if !self.shift_op(name, op_dir)? {
+                                self.shift(Token::Literal(c), 0, TERM);
+                            }
+                        } else {
+                            self.shift(Token::Literal(c), 0, TERM);
+                        }
                     }
-                } else {
-                    self.shift(Token::Literal(c), 0, TERM);
                 }
             }
             Token::Var(v) => self.shift(Token::Var(v), 0, TERM),
@@ -1248,7 +1197,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             Token::Close => {
                 if !self.reduce_term() && !self.reduce_brackets() {
                     return Err(ParserError::IncompleteReduction(
-                        self.lexer.loc_to_err_src(),
+                        self.loc_to_err_src(),
                     ));
                 }
             }
@@ -1256,7 +1205,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             Token::CloseList => {
                 if !self.reduce_list()? {
                     return Err(ParserError::IncompleteReduction(
-                        self.lexer.loc_to_err_src(),
+                        self.loc_to_err_src(),
                     ));
                 }
             }
@@ -1264,7 +1213,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             Token::CloseCurly => {
                 if !self.reduce_curly()? {
                     return Err(ParserError::IncompleteReduction(
-                        self.lexer.loc_to_err_src(),
+                        self.loc_to_err_src(),
                     ));
                 }
             }
@@ -1300,7 +1249,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
                 | Some(TokenType::HeadTailSeparator)
                 | Some(TokenType::Comma) => {
                     return Err(ParserError::IncompleteReduction(
-                        self.lexer.loc_to_err_src(),
+                        self.loc_to_err_src(),
                     ))
                 }
                 _ => {}
@@ -1309,10 +1258,16 @@ impl<'a, R: CharRead> Parser<'a, R> {
 
         Ok(())
     }
+}
 
+impl<'a, R: CharRead> LexerParser<'a, R> {
     #[inline]
-    pub fn lines_read(&self) -> usize {
-        self.lexer.line_num
+    pub fn line_num(&self) -> usize {
+        self.line_num
+    }
+
+    pub fn loc_to_err_src(&self) -> ParserErrorSrc {
+        ParserErrorSrc { line_num: self.line_num, col_num: self.col_num }
     }
 
     // on success, returns the parsed term and the number of lines read.
@@ -1320,35 +1275,62 @@ impl<'a, R: CharRead> Parser<'a, R> {
         &mut self,
         op_dir: &CompositeOpDir,
         tokens: Tokens,
-    ) -> Result<FocusedHeap, ParserError> {
-        self.tokens = match tokens {
-            Tokens::Default => read_tokens(&mut self.lexer)?,
-            Tokens::Provided(tokens) => tokens,
+    ) -> Result<TermWriteResult, ParserError> {
+        let (tokens, term_byte_size) = match tokens {
+            Tokens::Default => read_tokens(self)?,
+            Tokens::Provided(tokens, size) => (tokens, size),
+        };
+
+        // the parser uses conditional indirection in many places so
+        // the reserved size should be at least 3 * term_byte_size
+        // so all cells are accounted for.
+        let writer = match self.machine_st.heap.reserve(cell_index!(3 * term_byte_size)) {
+            Ok(term) => term,
+            Err(_err_loc) => {
+                return Err(ParserError::ResourceError(self.loc_to_err_src()));
+            }
         };
 
-        while let Some(token) = self.tokens.pop() {
-            self.shift_token(token, op_dir)?;
+        let before_len = writer.cell_len();
+
+        let mut parser_impl = Parser {
+            tokens,
+            stack: vec![],
+            terms: writer,
+            arena: &mut self.machine_st.arena,
+            flags: self.machine_st.flags,
+            line_num: &mut self.line_num,
+            col_num: &mut self.col_num,
+            var_locs: VarLocs::default(),
+            inverse_var_locs: InverseVarLocs::default(),
+        };
+
+        while let Some(token) = parser_impl.tokens.pop() {
+            parser_impl.shift_token(token, op_dir)?;
         }
 
-        self.reduce_op(1400);
+        parser_impl.reduce_op(1400);
+
+        let after_len = parser_impl.terms.cell_len();
+
+        debug_assert!(after_len - before_len <= cell_index!(3 * term_byte_size));
 
-        if self.stack.len() > 1 || self.terms.is_empty() {
+        if parser_impl.stack.len() > 1 || parser_impl.terms.is_empty() {
             return Err(ParserError::IncompleteReduction(
-                self.lexer.loc_to_err_src(),
+                parser_impl.loc_to_err_src(),
             ));
         }
 
-        match self.stack.pop() {
+        match parser_impl.stack.pop() {
             Some(TokenDesc {
                 tt: TokenType::Term { heap_loc },
                 ..
-            }) => Ok(FocusedHeap {
-                heap: mem::replace(&mut self.terms, vec![]),
+            }) => Ok(TermWriteResult {
                 focus: heap_loc.get_value() as usize,
-                inverse_var_locs: mem::replace(&mut self.inverse_var_locs, InverseVarLocs::default()),
+                inverse_var_locs: parser_impl.inverse_var_locs,
             }),
             _ => Err(ParserError::IncompleteReduction(
-                self.lexer.loc_to_err_src(),
+                parser_impl.loc_to_err_src(),
             )),
         }
     }
index e2fcfa0c4b41e978749198fb76ce264fd98a0809..e0b5d7d924e3d953a3a0b4aac336b5c7012461e4 100644 (file)
@@ -3,9 +3,10 @@ use crate::parser::parser::*;
 
 use crate::atom_table::*;
 use crate::machine::machine_errors::*;
-use crate::machine::machine_state::{MachineState, copy_and_align_iter};
+use crate::machine::machine_state::MachineState;
 use crate::machine::streams::*;
 use crate::parser::char_reader::*;
+use crate::parser::lexer::LexerParser;
 #[cfg(feature = "repl")]
 use crate::repl_helper::Helper;
 
@@ -22,9 +23,9 @@ use std::io::{Error, ErrorKind};
 use std::sync::Arc;
 
 pub(crate) fn devour_whitespace<R: CharRead>(
-    parser: &mut Parser<'_, R>,
+    lexer: &mut LexerParser<'_, R>,
 ) -> 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) => Err(e),
         Ok(_) => Ok(false),
@@ -47,35 +48,17 @@ pub(crate) fn error_after_read_term(
     CompilationError::from(err)
 }
 
-impl FocusedHeap {
-    pub fn to_machine_heap(mut self, machine_st: &mut MachineState) -> TermWriteResult {
-        let heap_len = machine_st.heap.len();
-        machine_st.heap.extend(copy_and_align_iter(self.heap.drain(..), 0, heap_len as i64));
-
-        let mut inverse_var_locs = InverseVarLocs::default();
-
-        for (var_loc, var_name) in self.inverse_var_locs.drain(..) {
-            inverse_var_locs.insert(var_loc + heap_len, var_name);
-        }
-
-        TermWriteResult {
-            heap_loc: self.focus + heap_len,
-            inverse_var_locs,
-        }
-    }
-}
-
 impl MachineState {
     pub(crate) fn read<R: CharRead>(
         &mut self,
         inner: R,
         op_dir: &OpDir,
-    ) -> Result<(FocusedHeap, usize), ParserError> {
-        let mut parser = Parser::new(inner, self);
+    ) -> Result<(TermWriteResult, usize), ParserError> {
+        let mut lexer_parser = LexerParser::new(inner, self);
         let op_dir = CompositeOpDir::new(op_dir, None);
 
-        let term_result = parser.read_term(&op_dir, Tokens::Default);
-        let lines_read  = parser.lines_read();
+        let term_result = lexer_parser.read_term(&op_dir, Tokens::Default);
+        let lines_read  = lexer_parser.line_num();
 
         term_result.map(|term| (term, lines_read))
     }
@@ -96,7 +79,7 @@ impl MachineState {
             }
         };
 
-        Ok(term.to_machine_heap(self))
+        Ok(term)
     }
 }
 
@@ -305,9 +288,3 @@ impl CharRead for ReadlineStream {
         self.pending_input.put_back_char(c);
     }
 }
-
-#[derive(Debug)]
-pub struct TermWriteResult {
-    pub heap_loc: usize,
-    pub inverse_var_locs: InverseVarLocs,
-}
index afec4fd235135418f31fb5355f233c022722554d..26199c22173e09427b00deb93e1a973f2e6ccb66 100644 (file)
@@ -6,7 +6,7 @@ use rustyline::{Context, Helper as RlHelper, Result};
 
 use std::sync::Weak;
 
-use crate::atom_table::{AtomString, AtomTable, STATIC_ATOMS_MAP};
+use crate::atom_table::{AtomString, AtomTable}; //, STATIC_ATOMS_MAP};
 
 // TODO: Maybe add validation to the helper
 pub struct Helper {
@@ -74,7 +74,7 @@ impl Completer for Helper {
 
             let mut matching = index_set
                 .iter()
-                .chain(STATIC_ATOMS_MAP.values())
+                // .chain(STATIC_ATOMS_MAP.values())
                 .map(|a| a.as_str())
                 .filter(|a| a.starts_with(sub_str))
                 .collect::<Vec<_>>();
index c2d7cde93b1b62e2a8894b3a73a890a059d8f003..bea12f5c8c28bae03070f98dbb2ee4f043d1086b 100644 (file)
@@ -5,22 +5,24 @@ use crate::forms::*;
 use crate::instructions::*;
 use crate::types::*;
 
+use std::rc::Rc;
+
 pub(crate) struct FactInstruction;
 pub(crate) struct QueryInstruction;
 
 pub(crate) trait CompilationTarget<'a> {
-    fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
+    fn to_constant(lvl: Level, cell: HeapCellValue, 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_void(num_subterms: usize) -> Instruction;
     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 constant_subterm(literal: Literal) -> Instruction;
+    fn constant_subterm(literal: HeapCellValue) -> Instruction;
 
     fn argument_to_variable(r: RegType, r: usize) -> Instruction;
     fn argument_to_value(r: RegType, val: usize) -> Instruction;
@@ -36,8 +38,8 @@ pub(crate) trait CompilationTarget<'a> {
 }
 
 impl<'a> CompilationTarget<'a> for FactInstruction {
-    fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
-        Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
+    fn to_constant(lvl: Level, cell: HeapCellValue, reg: RegType) -> Instruction {
+        Instruction::GetConstant(lvl, cell, reg)
     }
 
     fn to_structure(lvl: Level, name: Atom, arity: usize, reg: RegType) -> Instruction {
@@ -56,8 +58,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
         matches!(instr, &Instruction::UnifyVoid(_))
     }
 
-    fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
-        Instruction::GetPartialString(lvl, string, r, has_tail)
+    fn to_pstr(lvl: Level, string: Rc<String>, r: RegType) -> Instruction {
+        Instruction::GetPartialString(lvl, string, r)
     }
 
     fn incr_void_instr(instr: &mut Instruction) {
@@ -66,8 +68,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
         }
     }
 
-    fn constant_subterm(constant: Literal) -> Instruction {
-        Instruction::UnifyConstant(HeapCellValue::from(constant))
+    fn constant_subterm(constant: HeapCellValue) -> Instruction {
+        Instruction::UnifyConstant(constant)
     }
 
     fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
@@ -104,20 +106,20 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
 }
 
 impl<'a> CompilationTarget<'a> for QueryInstruction {
-    fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction {
-        Instruction::PutStructure(name, arity, r)
+    fn to_constant(lvl: Level, constant: HeapCellValue, reg: RegType) -> Instruction {
+        Instruction::PutConstant(lvl, constant, reg)
     }
 
-    fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
-        Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
+    fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction {
+        Instruction::PutStructure(name, arity, r)
     }
 
     fn to_list(lvl: Level, reg: RegType) -> Instruction {
         Instruction::PutList(lvl, reg)
     }
 
-    fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
-        Instruction::PutPartialString(lvl, string, r, has_tail)
+    fn to_pstr(lvl: Level, string: Rc<String>, r: RegType) -> Instruction {
+        Instruction::PutPartialString(lvl, string, r)
     }
 
     fn to_void(subterms: usize) -> Instruction {
@@ -134,8 +136,8 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
         }
     }
 
-    fn constant_subterm(constant: Literal) -> Instruction {
-        Instruction::SetConstant(HeapCellValue::from(constant))
+    fn constant_subterm(constant: HeapCellValue) -> Instruction {
+        Instruction::SetConstant(constant)
     }
 
     fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
index 84b78a752313901c352d1c2b0500658cfc00d3e0..7a0930196638e6a9690690b907977960f2263b21 100644 (file)
@@ -14,7 +14,7 @@ test_queries_on_call_with_inference_limit :-
          error,
          true),
     \+ call_with_inference_limit(g(X), 5, R),
-    maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), % TODO this line fails!
+    maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]),
     findall([R,X],
            call_with_inference_limit(g(X), 11, R),
            [[true, 1],
index 49ff0a6e95dc053ce76547a7c9df743e6559935b..e9caa4a73e748e550b82cc09cd2056df80b5144b 100644 (file)
@@ -3,8 +3,8 @@
 use crate::arena::*;
 use crate::atom_table::*;
 use crate::forms::*;
+use crate::machine::heap::*;
 use crate::machine::machine_indices::*;
-use crate::machine::partial_string::PartialString;
 use crate::machine::streams::*;
 use crate::parser::ast::Fixnum;
 
@@ -15,59 +15,64 @@ use std::mem;
 use std::ops::{Add, Sub, SubAssign};
 
 #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(u8)]
 #[bits = 6]
 pub enum HeapCellValueTag {
-    Str = 0b000011,
+    Str = 0b000001,
     Lis = 0b000101,
-    Var = 0b000111,
-    StackVar = 0b001001,
-    AttrVar = 0b001011,
-    PStrLoc = 0b001101,
-    PStrOffset = 0b001111,
+    Var = 0b001011,
+    StackVar = 0b001101,
+    AttrVar = 0b010001,
+    PStrLoc = 0b010011,
     // constants.
     Cons = 0b0,
-    F64 = 0b010001,
-    Fixnum = 0b010011,
-    Char = 0b010101,
-    Atom = 0b010111,
-    PStr = 0b011001,
-    CStr = 0b011011,
-    CutPoint = 0b011111,
+    F64 = 0b010101,
+    Fixnum = 0b011001,
+    // Char = 0b011011,
+    Atom = 0b011111,
+    CutPoint = 0b011101,
+    // trail elements.
+    TrailedHeapVar = 0b100001,
+    TrailedStackVar = 0b100011,
+    TrailedAttrVar = 0b100101,
+    TrailedAttrVarListLink = 0b101001,
+    TrailedAttachedValue = 0b101011,
+    TrailedBlackboardEntry = 0b101101,
+    TrailedBlackboardOffset = 0b110001,
 }
 
 #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(u8)]
 #[bits = 6]
 pub enum HeapCellValueView {
-    Str = 0b000011,
+    Str = 0b000001,
     Lis = 0b000101,
-    Var = 0b000111,
-    StackVar = 0b001001,
-    AttrVar = 0b001011,
-    PStrLoc = 0b001101,
-    PStrOffset = 0b001111,
+    Var = 0b001011,
+    StackVar = 0b001101,
+    AttrVar = 0b010001,
+    PStrLoc = 0b010011,
     // constants.
     Cons = 0b0,
-    F64 = 0b010001,
-    Fixnum = 0b010011,
-    Char = 0b010101,
-    Atom = 0b010111,
-    PStr = 0b011001,
-    CStr = 0b011011,
-    CutPoint = 0b011111,
+    F64 = 0b010101,
+    Fixnum = 0b011001,
+    Char = 0b011011,
+    Atom = 0b011111,
+    CutPoint = 0b011101,
     // trail elements.
-    TrailedHeapVar = 0b101111,
-    TrailedStackVar = 0b101011,
-    TrailedAttrVar = 0b100001,
-    TrailedAttrVarListLink = 0b100011,
-    TrailedAttachedValue = 0b100101,
-    TrailedBlackboardEntry = 0b100111,
-    TrailedBlackboardOffset = 0b110011,
+    TrailedHeapVar = 0b100001,
+    TrailedStackVar = 0b100011,
+    TrailedAttrVar = 0b100101,
+    TrailedAttrVarListLink = 0b101001,
+    TrailedAttachedValue = 0b101011,
+    TrailedBlackboardEntry = 0b101101,
+    TrailedBlackboardOffset = 0b110001,
 }
 
 #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 #[bits = 1]
 pub enum ConsPtrMaskTag {
     Cons = 0b0,
+    Atom = 0b1,
 }
 
 #[bitfield]
@@ -105,9 +110,9 @@ impl ConsPtr {
 #[derive(BitfieldSpecifier, Copy, Clone, Debug)]
 #[bits = 6]
 pub(crate) enum RefTag {
-    HeapCell = 0b000111,
-    StackCell = 0b001001,
-    AttrVar = 0b001011,
+    HeapCell = 0b001011,
+    StackCell = 0b001101,
+    AttrVar = 0b010001,
 }
 
 #[bitfield]
@@ -245,6 +250,7 @@ pub struct HeapCellValue {
     val: B56,
     f: bool,
     m: bool,
+    #[allow(dead_code)]
     tag: HeapCellValueTag,
 }
 
@@ -279,6 +285,7 @@ impl fmt::Debug for HeapCellValue {
                     .field("f", &self.f())
                     .finish()
             }
+            /*
             HeapCellValueTag::PStr => {
                 let (name, _) = cell_as_atom_cell!(self).get_name_and_arity();
 
@@ -289,6 +296,7 @@ impl fmt::Debug for HeapCellValue {
                     .field("f", &self.f())
                     .finish()
             }
+            */
             tag => f
                 .debug_struct("HeapCellValue")
                 .field("tag", &tag)
@@ -354,19 +362,15 @@ impl HeapCellValue {
     }
 
     #[inline]
-    pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool {
-        use crate::machine::heap::*;
-
+    pub fn is_string_terminator(mut self, heap: &impl SizedHeap) -> bool {
         loop {
             return read_heap_cell!(self,
                 (HeapCellValueTag::Atom, (name, arity)) => {
                     name == atom!("[]") && arity == 0
                 }
-                (HeapCellValueTag::CStr) => {
-                    true
-                }
                 (HeapCellValueTag::PStrLoc, h) => {
-                    self = heap[h];
+                    let (_s, tail_loc) = heap.scan_slice_to_str(h);
+                    self = heap[tail_loc];
                     continue;
                 }
                 (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
@@ -379,9 +383,6 @@ impl HeapCellValue {
                     self = cell;
                     continue;
                 }
-                (HeapCellValueTag::PStrOffset, pstr_offset) => {
-                    heap[pstr_offset].get_tag() == HeapCellValueTag::CStr
-                }
                 _ => {
                     false
                 }
@@ -399,16 +400,13 @@ impl HeapCellValue {
                 | HeapCellValueTag::StackVar
                 | HeapCellValueTag::AttrVar
                 | HeapCellValueTag::PStrLoc
-                | HeapCellValueTag::PStrOffset
+                // | HeapCellValueTag::PStrOffset
         )
     }
 
     #[inline]
     pub fn as_char(self) -> Option<char> {
         read_heap_cell!(self,
-            (HeapCellValueTag::Char, c) => {
-                Some(c)
-            }
             (HeapCellValueTag::Atom, (name, arity)) => {
                 if arity > 0 {
                     return None;
@@ -428,9 +426,7 @@ impl HeapCellValue {
             HeapCellValueTag::Cons
             | HeapCellValueTag::F64
             | HeapCellValueTag::Fixnum
-            | HeapCellValueTag::CutPoint
-            | HeapCellValueTag::Char
-            | HeapCellValueTag::CStr => true,
+            | HeapCellValueTag::CutPoint => true,
             HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0,
             _ => false,
         }
@@ -442,16 +438,12 @@ impl HeapCellValue {
     }
 
     #[inline]
-    pub fn is_compound(self, heap: &[HeapCellValue]) -> bool {
+    pub fn is_compound(self, heap: &Heap) -> bool {
         match self.get_tag() {
             HeapCellValueTag::Str => {
                 cell_as_atom_cell!(heap[self.get_value() as usize]).get_arity() > 0
             }
-            HeapCellValueTag::Lis
-            | HeapCellValueTag::CStr
-            | HeapCellValueTag::PStr
-            | HeapCellValueTag::PStrLoc
-            | HeapCellValueTag::PStrOffset => true,
+            HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => true,
             HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() > 0,
             _ => false,
         }
@@ -502,6 +494,7 @@ impl HeapCellValue {
         match self.tag_or_err() {
             Ok(tag) => tag,
             Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
+                ConsPtrMaskTag::Atom => HeapCellValueTag::Atom,
                 ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
             },
         }
@@ -509,16 +502,10 @@ impl HeapCellValue {
 
     #[inline]
     pub fn to_atom(self) -> Option<Atom> {
-        match self.tag() {
-            HeapCellValueTag::Atom => Some(Atom::from(self.val() << 3)),
-            _ => None,
-        }
-    }
-
-    #[inline]
-    pub fn to_pstr(self) -> Option<PartialString> {
-        match self.tag() {
-            HeapCellValueTag::PStr => Some(PartialString::from(Atom::from(self.val() << 3))),
+        match self.get_tag() {
+            HeapCellValueTag::Atom => {
+                Some(AtomCell::from_bytes(self.into_bytes()).get_name())
+            }
             _ => None,
         }
     }
@@ -593,7 +580,7 @@ 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() {
             Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
                 Some(TermOrderCategory::Integer)
@@ -603,13 +590,14 @@ impl HeapCellValue {
                 HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => {
                     Some(TermOrderCategory::Variable)
                 }
-                HeapCellValueTag::Char => Some(TermOrderCategory::Atom),
+                // HeapCellValueTag::Char => Some(TermOrderCategory::Atom),
                 HeapCellValueTag::Atom => Some(if cell_as_atom_cell!(self).get_arity() > 0 {
                     TermOrderCategory::Compound
                 } else {
                     TermOrderCategory::Atom
                 }),
-                HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr => {
+                HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => {
+                    // | HeapCellValueTag::CStr => {
                     Some(TermOrderCategory::Compound)
                 }
                 HeapCellValueTag::Str => {
@@ -732,12 +720,14 @@ impl Add<usize> for HeapCellValue {
         match self.get_tag() {
             tag @ HeapCellValueTag::Str
             | tag @ HeapCellValueTag::Lis
-            | tag @ HeapCellValueTag::PStrOffset
-            | tag @ HeapCellValueTag::PStrLoc
             | tag @ HeapCellValueTag::Var
             | tag @ HeapCellValueTag::AttrVar => {
                 HeapCellValue::build_with(tag, (self.get_value() 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,
         }
     }
@@ -750,12 +740,14 @@ impl Sub<usize> for HeapCellValue {
         match self.get_tag() {
             tag @ HeapCellValueTag::Str
             | tag @ HeapCellValueTag::Lis
-            | tag @ HeapCellValueTag::PStrOffset
-            | tag @ HeapCellValueTag::PStrLoc
             | tag @ HeapCellValueTag::Var
             | tag @ HeapCellValueTag::AttrVar => {
                 HeapCellValue::build_with(tag, (self.get_value() 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,
         }
     }
@@ -776,12 +768,14 @@ impl Sub<i64> for HeapCellValue {
             match self.get_tag() {
                 tag @ HeapCellValueTag::Str
                 | tag @ HeapCellValueTag::Lis
-                | tag @ HeapCellValueTag::PStrOffset
-                | tag @ HeapCellValueTag::PStrLoc
                 | tag @ HeapCellValueTag::Var
                 | tag @ HeapCellValueTag::AttrVar => {
                     HeapCellValue::build_with(tag, self.get_value() + rhs.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,
             }
         } else {
index 9d4c619305fcaf563f0114ad3e14121fa5005932..d099faff7fd3571e1ea9d8709000364ee5cd50b9 100644 (file)
@@ -1 +1 @@
-:- op(10, xf, [example, Var]).
\ No newline at end of file
+:- op(10, xf, [example, Var]).
index 4e87a39a32ab77e220f60e4022044d78119eb259..dbea342e809b5eb25f68eac0b5c49793f096976e 100644 (file)
@@ -2,4 +2,4 @@
 
 test :- load_html("<html><head><title>Hello!</title></head></html>", Es, []), write(Es).
 
-:- initialization(test).
\ No newline at end of file
+:- initialization(test).