]> Repositorios git - scryer-prolog.git/commitdiff
Revert "remove Term"
authorMark Thom <[email protected]>
Sat, 15 Mar 2025 20:19:26 +0000 (13:19 -0700)
committerMark Thom <[email protected]>
Tue, 8 Jul 2025 05:38:10 +0000 (22:38 -0700)
This reverts commit 3b5879841aedecba5057c70c71da0ba23e5cd84a.

53 files changed:
build/instructions_template.rs
src/allocator.rs
src/arithmetic.rs
src/atom_table.rs
src/codegen.rs
src/debray_allocator.rs
src/forms.rs
src/functor_macro.rs
src/heap_iter.rs
src/heap_print.rs
src/indexing.rs
src/iterators.rs
src/lib/atts.pl
src/lib/builtins.pl
src/lib/si.pl
src/loader.pl
src/machine/arithmetic_ops.rs
src/machine/attributed_variables.rs
src/machine/compile.rs
src/machine/disjuncts.rs
src/machine/dispatch.rs
src/machine/gc.rs
src/machine/heap.rs
src/machine/lib_machine/mod.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/partial_string.rs
src/machine/preprocessor.rs
src/machine/raw_block.rs
src/machine/stack.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/raw_block.rs
src/read.rs
src/targets.rs
src/tests/builtins.pl
src/tests/call_with_inference_limit.pl
src/types.rs
src/variable_records.rs
tests-pl/iso-conformity-tests.pl
tests/scryer/src_tests.rs

index 18102af840aa057f054cda0c9ace28367a48ee99..baa596268c8adf76e3c30304b30db9a021506921 100644 (file)
@@ -194,9 +194,9 @@ enum ReplCodePtr {
     DynamicProperty,
     #[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
     AbolishClause,
-    #[strum_discriminants(strum(props(Arity = "2", Name = "$asserta")))]
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))]
     Asserta,
-    #[strum_discriminants(strum(props(Arity = "2", Name = "$assertz")))]
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))]
     Assertz,
     #[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
     Retract,
@@ -3126,6 +3126,14 @@ pub fn generate_instructions_rs() -> TokenStream {
                 }
             }
 
+            pub fn name(&self) -> Atom {
+                match self {
+                    #(
+                        #clause_type_name_arms,
+                    )*
+                }
+            }
+
             pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
                 matches!((name, arity),
                     #(#is_inbuilt_arms)|*
index 735b013f53ddeac25545c016e2621650f508dda7..b4529d820facfc3cb32b82cf02c41696a6e51735 100644 (file)
@@ -2,9 +2,10 @@ use crate::parser::ast::*;
 
 use crate::forms::*;
 use crate::instructions::*;
-use crate::machine::heap::Heap;
 use crate::targets::*;
 
+use std::cell::Cell;
+
 pub(crate) trait Allocator {
     fn new() -> Self;
 
@@ -18,21 +19,22 @@ pub(crate) trait Allocator {
     fn mark_non_var<'a, Target: CompilationTarget<'a>>(
         &mut self,
         lvl: Level,
-        heap_loc: usize,
         context: GenContext,
+        cell: &'a Cell<RegType>,
         code: &mut CodeDeque,
-    ) -> RegType;
+    );
 
     #[allow(clippy::too_many_arguments)]
     fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
         &mut self,
         var_num: usize,
         lvl: Level,
-        context: GenContext,
+        cell: &Cell<VarReg>,
+        term_loc: GenContext,
         code: &mut CodeDeque,
         r: RegType,
         is_new_var: bool,
-    ) -> RegType;
+    );
 
     fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType;
 
@@ -40,13 +42,14 @@ pub(crate) trait Allocator {
         &mut self,
         var_num: usize,
         lvl: Level,
+        cell: &Cell<VarReg>,
         context: GenContext,
         code: &mut CodeDeque,
-    ) -> RegType;
+    );
 
     fn reset(&mut self);
     fn reset_arg(&mut self, arg_num: usize);
-    fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize);
+    fn reset_at_head(&mut self, args: &[Term]);
     fn reset_contents(&mut self);
 
     fn advance_arg(&mut self);
index dc03c8db8a66f7e5787a4e8ffbe4c704f62d53df..4863932a5558644de821bcc8bd0b78097b7b3f51 100644 (file)
@@ -7,8 +7,6 @@ use crate::debray_allocator::*;
 use crate::forms::*;
 use crate::instructions::*;
 use crate::iterators::*;
-use crate::machine::disjuncts::*;
-use crate::machine::stack::Stack;
 use crate::targets::QueryInstruction;
 use crate::types::*;
 
@@ -22,6 +20,7 @@ use dashu::base::BitTest;
 use num_order::NumOrd;
 use ordered_float::{Float, OrderedFloat};
 
+use std::cell::Cell;
 use std::cmp::{max, min, Ordering};
 use std::convert::TryFrom;
 use std::f64;
@@ -52,8 +51,89 @@ impl Default for ArithmeticTerm {
     }
 }
 
+#[derive(Debug)]
+pub(crate) struct ArithInstructionIterator<'a> {
+    state_stack: Vec<TermIterState<'a>>,
+}
+
 pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
 
+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(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
+    }
+}
+
 #[derive(Debug)]
 pub(crate) struct ArithmeticEvaluator<'a> {
     marker: &'a mut DebrayAllocator,
@@ -61,47 +141,37 @@ pub(crate) struct ArithmeticEvaluator<'a> {
     interm_c: usize,
 }
 
-fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: HeapCellValue) -> Result<(), ArithmeticError> {
-    let c = unmark_cell_bits!(c);
+pub(crate) trait ArithmeticTermIter<'a> {
+    type Iter: Iterator<Item = Result<ArithTermRef<'a>, 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));
-        }
-    );
+    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)
+    }
+}
+
+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(*c, 0)),
+    }
 
     Ok(())
 }
@@ -143,7 +213,7 @@ impl<'a> ArithmeticEvaluator<'a> {
             atom!("float_fractional_part") => Ok(Instruction::FloatFractionalPart(a1, t)),
             atom!("sign") => Ok(Instruction::Sign(a1, t)),
             atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
-            _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 1)),
+            _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
         }
     }
 
@@ -175,7 +245,7 @@ impl<'a> ArithmeticEvaluator<'a> {
             atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
             atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
             atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)),
-            _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 2)),
+            _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
         }
     }
 
@@ -231,7 +301,7 @@ impl<'a> ArithmeticEvaluator<'a> {
                 self.get_binary_instr(name, a1, a2, ninterm)
             }
             _ => Err(ArithmeticError::NonEvaluableFunctor(
-                atom_as_cell!(name),
+                Literal::Atom(name),
                 arity,
             )),
         }
@@ -239,62 +309,44 @@ impl<'a> ArithmeticEvaluator<'a> {
 
     pub(crate) fn compile_is(
         &mut self,
-        src: &mut FocusedHeapRefMut,
-        term_loc: usize,
-        context: GenContext,
+        src: &'a Term,
+        term_loc: GenContext,
         arg: usize,
     ) -> Result<ArithCont, ArithmeticError> {
         let mut code = CodeDeque::new();
-        let mut stack = Stack::uninitialized();
-        let mut iter = query_iterator::<false>(&mut src.heap, &mut stack, term_loc);
-
-        let chunk_num = context.chunk_num();
-
-        while let Some(term) = iter.next() {
-            read_heap_cell!(term,
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
-                    let lvl = iter.level();
-
-                    let r = match self.marker.var_data.var_locs_to_nums.get(VarPtrIndex { chunk_num, term_loc }) {
-                        VarPtr::Numbered(var_num) => {
-                            let old_r = self.marker.get_var_binding(var_num);
-
-                            if lvl == Level::Root {
-                                self.marker.mark_non_callable(var_num, arg, context, &mut code)
-                            } else if context.is_last() || old_r.reg_num() == 0 {
-                                let r = old_r;
-
-                                if r.reg_num() == 0 {
-                                    self.marker.mark_var::<QueryInstruction>(
-                                        var_num, lvl, context, &mut code,
-                                    )
-                                } else {
-                                    self.marker.increment_running_count(var_num);
-                                    r
-                                }
-                            } else {
-                                self.marker.increment_running_count(var_num);
-                                old_r
-                            }
-                        }
-                        VarPtr::Anon => {
-                            self.marker.mark_anon_var::<QueryInstruction>(lvl, context, &mut code)
+
+        for term_ref in src.iter()? {
+            match term_ref? {
+                ArithTermRef::Literal(c) => push_literal(&mut self.interm, &c)?,
+                ArithTermRef::Var(lvl, cell, name) => {
+                    let var_num = name.to_var_num().unwrap();
+
+                    let r = if lvl == Level::Shallow {
+                        self.marker
+                            .mark_non_callable(var_num, arg, term_loc, cell, &mut code)
+                    } else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
+                        let r = self.marker.get_binding(var_num);
+
+                        if r.reg_num() == 0 {
+                            self.marker.mark_var::<QueryInstruction>(
+                                var_num, lvl, cell, term_loc, &mut code,
+                            );
+                            cell.get().norm()
+                        } else {
+                            self.marker.increment_running_count(var_num);
+                            r
                         }
+                    } else {
+                        self.marker.increment_running_count(var_num);
+                        cell.get().norm()
                     };
 
                     self.interm.push(ArithmeticTerm::Reg(r));
                 }
-                (HeapCellValueTag::Atom, (name, arity)) => {
-                    if arity == 0 {
-                        push_literal(&mut self.interm, atom_as_cell!(name))?;
-                    } else {
-                        code.push_back(self.instr_from_clause(name, arity)?);
-                    }
-                }
-                _ => {
-                    push_literal(&mut self.interm, term)?;
+                ArithTermRef::Op(name, arity) => {
+                    code.push_back(self.instr_from_clause(name, arity)?);
                 }
-            );
+            }
         }
 
         Ok((code, self.interm.pop()))
index 67aaa966c785c292c6510c982c1bbc7c0372ee91..09922b1729b1165db1ba31fec0eda34a5be10972 100644 (file)
@@ -222,7 +222,7 @@ pub enum AtomString<'a> {
     Dynamic(AtomTableRef<str>),
 }
 
-fn inlined_to_str<'a>(bytes: &'a [u8; 8]) -> &'a str {
+fn inlined_to_str(bytes: &[u8; 8]) -> &str {
     // allow the '\0\' atom to be represented as the 0-valued inlined atom
     let slice_len = if bytes[0] == 0 {
         1
@@ -543,61 +543,3 @@ impl AtomTable {
 
 unsafe impl Send for AtomTable {}
 unsafe impl Sync for AtomTable {}
-
-/*
-#[bitfield]
-#[repr(u64)]
-#[derive(Copy, Clone, Debug)]
-pub struct AtomCell {
-    name: B48,
-    arity: B10,
-    #[allow(unused)]
-    f: bool,
-    #[allow(unused)]
-    m: bool,
-    #[allow(unused)]
-    inlined: bool,
-    #[allow(unused)]
-    tag: B3,
-}
-
-impl AtomCell {
-    #[inline]
-    pub fn build_with(name: u64, arity: u16, tag: HeapCellValueTag) -> Self {
-        if arity > 0 {
-            debug_assert!(arity as usize <= MAX_ARITY);
-
-            AtomCell::new()
-                .with_name(name)
-                .with_arity(arity)
-                .with_f(false)
-                .with_tag(tag as u8)
-        } else {
-            AtomCell::new()
-                .with_name(name)
-                .with_f(false)
-                .with_tag(tag as u8)
-        }
-    }
-
-    #[inline]
-    pub fn get_index(self) -> usize {
-        self.name() as usize
-    }
-
-    #[inline]
-    pub fn get_name(self) -> Atom {
-        Atom::from((self.get_index() as u64) << 3)
-    }
-
-    #[inline]
-    pub fn get_arity(self) -> usize {
-        self.arity() as usize
-    }
-
-    #[inline]
-    pub fn get_name_and_arity(self) -> (Atom, usize) {
-        (Atom::from((self.get_index() as u64) << 3), self.get_arity())
-    }
-}
-*/
index 3118d6491c975480997af856a1d6b87042f7a5fb..4145865328ef4ad884d52dbd2c3cd7cfc7fe040a 100644 (file)
@@ -1,5 +1,4 @@
 use crate::allocator::*;
-use crate::arena::ArenaHeaderTag;
 use crate::arithmetic::*;
 use crate::atom_table::*;
 use crate::debray_allocator::*;
@@ -7,7 +6,6 @@ use crate::forms::*;
 use crate::indexing::*;
 use crate::instructions::*;
 use crate::iterators::*;
-use crate::machine::heap::*;
 use crate::parser::ast::*;
 use crate::targets::*;
 use crate::types::*;
@@ -15,15 +13,12 @@ use crate::variable_records::*;
 
 use crate::machine::disjuncts::*;
 use crate::machine::machine_errors::*;
-use crate::machine::machine_indices::CodeIndex;
-use crate::machine::stack::Stack;
 
 use fxhash::FxBuildHasher;
-use indexmap::IndexMap;
 use indexmap::IndexSet;
 
+use std::cell::Cell;
 use std::collections::VecDeque;
-use std::rc::Rc;
 
 #[derive(Debug)]
 pub struct BranchCodeStack {
@@ -281,26 +276,36 @@ pub(crate) struct CodeGenerator {
 }
 
 impl DebrayAllocator {
+    fn mark_var_in_non_callable(
+        &mut self,
+        var_num: usize,
+        term_loc: GenContext,
+        vr: &Cell<VarReg>,
+        code: &mut CodeDeque,
+    ) -> RegType {
+        self.mark_var::<QueryInstruction>(var_num, Level::Shallow, vr, term_loc, code);
+        vr.get().norm()
+    }
+
     pub(crate) fn mark_non_callable(
         &mut self,
         var_num: usize,
         arg: usize,
-        context: GenContext,
+        term_loc: GenContext,
+        vr: &Cell<VarReg>,
         code: &mut CodeDeque,
     ) -> RegType {
-        match self.get_var_binding(var_num) {
+        match self.get_binding(var_num) {
             RegType::Temp(t) if t != 0 => RegType::Temp(t),
             RegType::Perm(p) if p != 0 => {
-                if let GenContext::Last(_) = context {
-                    self.mark_var::<QueryInstruction>(var_num, Level::Shallow, context, code);
+                if let GenContext::Last(_) = term_loc {
+                    self.mark_var_in_non_callable(var_num, term_loc, vr, code);
                     temp_v!(arg)
                 } else {
-                    if let VarAlloc::Perm {
-                        allocation: PermVarAllocation::Pending,
-                        ..
-                    } = &self.var_data.records[var_num].allocation
+                    if let VarAlloc::Perm(_, PermVarAllocation::Pending) =
+                        &self.var_data.records[var_num].allocation
                     {
-                        self.mark_var::<QueryInstruction>(var_num, Level::Shallow, context, code);
+                        self.mark_var_in_non_callable(var_num, term_loc, vr, code);
                     } else {
                         self.increment_running_count(var_num);
                     }
@@ -308,14 +313,14 @@ impl DebrayAllocator {
                     RegType::Perm(p)
                 }
             }
-            _ => self.mark_var::<QueryInstruction>(var_num, Level::Shallow, context, code),
+            _ => self.mark_var_in_non_callable(var_num, term_loc, vr, code),
         }
     }
 }
 
 trait AddToFreeList<'a, Target: CompilationTarget<'a>> {
     fn add_term_to_free_list(&mut self, r: RegType);
-    fn add_subterm_to_free_list(&mut self, r: RegType);
+    fn add_subterm_to_free_list(&mut self, term: &Term);
 }
 
 impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator {
@@ -323,7 +328,7 @@ impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator {
         self.marker.add_reg_to_free_list(r);
     }
 
-    fn add_subterm_to_free_list(&mut self, _r: RegType) {}
+    fn add_subterm_to_free_list(&mut self, _term: &Term) {}
 }
 
 impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator {
@@ -331,27 +336,21 @@ impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator {
     fn add_term_to_free_list(&mut self, _r: RegType) {}
 
     #[inline(always)]
-    fn add_subterm_to_free_list(&mut self, r: RegType) {
-        self.marker.add_reg_to_free_list(r);
+    fn add_subterm_to_free_list(&mut self, term: &Term) {
+        if let Some(cell) = structure_cell(term) {
+            self.marker.add_reg_to_free_list(cell.get());
+        }
     }
 }
 
-fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>(
-    index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
-    heap: &Heap,
-    heap_loc: usize,
-) -> Option<Instruction> {
-    if let Some(index_ptr) = index_ptrs.get(&heap_loc) {
-        let subterm = HeapCellValue::from(*index_ptr);
-        return Some(Target::constant_subterm(subterm));
-    } else if !heap[heap_loc.saturating_sub(1)].get_mark_bit() {
-        if let Some(index_ptr) = fetch_index_ptr(heap, heap_loc) {
-            let subterm = HeapCellValue::from(index_ptr);
-            return Some(Target::constant_subterm(subterm));
-        }
+fn structure_cell(term: &Term) -> Option<&Cell<RegType>> {
+    match term {
+        &Term::Cons(ref cell, ..)
+        | &Term::Clause(ref cell, ..)
+        | Term::PartialString(ref cell, ..)
+        | Term::CompleteString(ref cell, ..) => Some(cell),
+        _ => None,
     }
-
-    None
 }
 
 impl CodeGenerator {
@@ -379,13 +378,14 @@ impl CodeGenerator {
 
     fn deep_var_instr<'a, Target: crate::targets::CompilationTarget<'a>>(
         &mut self,
+        cell: &'a Cell<VarReg>,
         var_num: usize,
-        context: GenContext,
+        term_loc: GenContext,
         target: &mut CodeDeque,
     ) {
         if self.marker.var_data.records[var_num].num_occurrences > 1 {
             self.marker
-                .mark_var::<Target>(var_num, Level::Deep, context, target);
+                .mark_var::<Target>(var_num, Level::Deep, cell, term_loc, target);
         } else {
             Self::add_or_increment_void_instr::<Target>(target);
         }
@@ -393,212 +393,134 @@ impl CodeGenerator {
 
     fn subterm_to_instr<'a, Target: crate::targets::CompilationTarget<'a>>(
         &mut self,
-        subterm: HeapCellValue,
-        heap_loc: usize,
-        context: GenContext,
-        index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
+        subterm: &'a Term,
+        term_loc: GenContext,
         target: &mut CodeDeque,
-    ) -> Option<RegType> {
-        let subterm = unmark_cell_bits!(subterm);
-        let chunk_num = context.chunk_num();
-
-        read_heap_cell!(subterm,
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
-                match self.marker.var_data.var_locs_to_nums.get(VarPtrIndex { chunk_num, term_loc }) {
-                    VarPtr::Numbered(var_num) => {
-                        self.deep_var_instr::<Target>(
-                            var_num,
-                            context,
-                            target,
-                        );
-                    }
-                    VarPtr::Anon => {
-                        Self::add_or_increment_void_instr::<Target>(target);
-                    }
-                }
-
-                None
+    ) {
+        match subterm {
+            &Term::AnonVar => {
+                Self::add_or_increment_void_instr::<Target>(target);
             }
-            (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(atom_as_cell!(name)));
-                }
-
-                None
+            &Term::Cons(ref cell, ..)
+            | &Term::Clause(ref cell, ..)
+            | Term::PartialString(ref cell, ..)
+            | Term::CompleteString(ref cell, ..) => {
+                self.marker
+                    .mark_non_var::<Target>(Level::Deep, term_loc, cell, target);
+                target.push_back(Target::clause_arg_to_instr(cell.get()));
             }
-            (HeapCellValueTag::Str
-             | HeapCellValueTag::Lis
-             | 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);
+            Term::Literal(_, ref constant) => {
+                target.push_back(Target::constant_subterm(*constant));
             }
-            _ => {
-                target.push_back(Target::constant_subterm(subterm));
-                None
+            Term::Var(ref cell, ref var_ptr) => {
+                self.deep_var_instr::<Target>(
+                    cell,
+                    var_ptr.to_var_num().unwrap(),
+                    term_loc,
+                    target,
+                );
             }
-        )
+        };
     }
 
-    fn compile_target<'a, Target, Iter>(
-        &mut self,
-        mut iter: Iter,
-        index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
-        context: GenContext,
-    ) -> CodeDeque
+    fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, context: GenContext) -> CodeDeque
     where
         Target: crate::targets::CompilationTarget<'a>,
-        Iter: TermIterator,
+        Iter: Iterator<Item = TermRef<'a>>,
         CodeGenerator: AddToFreeList<'a, Target>,
     {
         let mut target = CodeDeque::new();
-        let chunk_num = context.chunk_num();
-
-        while let Some(term) = iter.next() {
-            let lvl = iter.level();
-            let term = unmark_cell_bits!(term);
-
-            read_heap_cell!(term,
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
-                    if lvl == Level::Shallow {
-                        match self.marker.var_data.var_locs_to_nums.get(
-                            VarPtrIndex { chunk_num, term_loc }
-                        ) {
-                            VarPtr::Numbered(var_num) => {
-                                self.marker.mark_var::<Target>(
-                                    var_num,
-                                    lvl,
-                                    context,
-                                    &mut target,
-                                );
-                            }
-                            VarPtr::Anon => {
-                                if let GenContext::Head = context {
-                                    self.marker.advance_arg();
-                                } else {
-                                    self.marker.mark_anon_var::<Target>(lvl, context, &mut target);
-                                }
-                            }
-                        }
+
+        for term in iter {
+            match term {
+                TermRef::AnonVar(lvl @ Level::Shallow) => {
+                    if let GenContext::Head = context {
+                        self.marker.advance_arg();
+                    } else {
+                        self.marker
+                            .mark_anon_var::<Target>(lvl, context, &mut target);
                     }
                 }
-                (HeapCellValueTag::Atom, (name, arity)) => {
-                    let heap_loc = iter.focus().value() as usize;
-                    let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
-
-                    if arity == 0 {
-                        if let Some(instr) = add_index_ptr::<Target>(index_ptrs, &iter, heap_loc) {
-                            let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
-                            target.push_back(instr);
-                            target.push_back(Target::to_structure(lvl, name, 0, r));
-                        } 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, atom_as_cell!(name), r));
-                        }
-                    } else {
-                        let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
-
-                        <CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
-                            self,
-                            r,
-                        );
-
-                        if let Some(instr) = add_index_ptr::<Target>(index_ptrs, &iter, heap_loc) {
-                            target.push_back(instr);
-                        }
+                TermRef::Clause(lvl, cell, name, terms) => {
+                    let terms_range =
+                        if let Some(subterm @ Term::Literal(_, Literal::CodeIndex(_))) =
+                            terms.last()
+                        {
+                            self.subterm_to_instr::<Target>(subterm, context, &mut target);
+                            0..terms.len() - 1
+                        } else {
+                            0..terms.len()
+                        };
 
-                        target.push_back(Target::to_structure(lvl, name, arity, r));
+                    self.marker
+                        .mark_non_var::<Target>(lvl, context, cell, &mut target);
+                    target.push_back(Target::to_structure(lvl, name, terms_range.end, cell.get()));
 
-                        let free_list_regs: Vec<_> = (heap_loc + 1 ..= heap_loc + arity)
-                            .map(|subterm_loc| {
-                                let (subterm_loc, subterm) = subterm_index(iter.deref(), subterm_loc);
+                    <CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
+                        self,
+                        cell.get(),
+                    );
 
-                                self.subterm_to_instr::<Target>(
-                                    subterm, subterm_loc, context, index_ptrs, &mut target,
-                                )
-                            })
-                            .collect();
+                    for subterm in &terms[terms_range.clone()] {
+                        self.subterm_to_instr::<Target>(subterm, context, &mut target);
+                    }
 
-                        for r_opt in free_list_regs {
-                            if let Some(r) = r_opt {
-                                <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
-                                    self, r,
-                                );
-                            }
-                        }
+                    for subterm in &terms[terms_range] {
+                        <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+                            self, subterm,
+                        );
                     }
                 }
-                (HeapCellValueTag::Lis, l) => {
-                    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_list(lvl, r));
+                TermRef::Cons(lvl, cell, head, tail) => {
+                    self.marker
+                        .mark_non_var::<Target>(lvl, context, cell, &mut target);
+                    target.push_back(Target::to_list(lvl, cell.get()));
 
                     <CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
                         self,
-                        r,
+                        cell.get(),
                     );
 
-                    let (head_loc, head) = subterm_index(iter.deref(), l);
-                    let (tail_loc, tail) = subterm_index(iter.deref(), l+1);
+                    self.subterm_to_instr::<Target>(head, context, &mut target);
+                    self.subterm_to_instr::<Target>(tail, context, &mut target);
 
-                    let head_r_opt = self.subterm_to_instr::<Target>(
-                        head,
-                        head_loc,
-                        context,
-                        index_ptrs,
-                        &mut target,
+                    <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+                        self, head,
                     );
-
-                    let tail_r_opt = self.subterm_to_instr::<Target>(
-                        tail,
-                        tail_loc,
-                        context,
-                        index_ptrs,
-                        &mut target,
+                    <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+                        self, tail,
                     );
-
-                    if let Some(r) = head_r_opt {
-                        <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
-                            self, r,
-                        );
-                    }
-
-                    if let Some(r) = tail_r_opt {
-                        <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
-                            self, r,
-                        );
-                    }
                 }
-                (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 HeapStringScan { string, tail_idx } = iter.scan_slice_to_str(pstr_loc);
+                TermRef::Literal(lvl @ Level::Shallow, cell, constant) => {
+                    self.marker
+                        .mark_non_var::<Target>(lvl, context, cell, &mut target);
+                    target.push_back(Target::to_constant(lvl, *constant, cell.get()));
+                }
+                TermRef::PartialString(lvl, cell, string, tail) => {
+                    self.marker
+                        .mark_non_var::<Target>(lvl, context, cell, &mut target);
 
-                    target.push_back(Target::to_pstr(lvl, Rc::new(string.to_owned()), r));
+                    target.push_back(Target::to_pstr(lvl, string.clone(), cell.get()));
+                    self.subterm_to_instr::<Target>(tail, context, &mut target);
+                }
+                TermRef::CompleteString(lvl, cell, string) => {
+                    self.marker
+                        .mark_non_var::<Target>(lvl, context, cell, &mut target);
 
-                    let (tail_loc, tail) = subterm_index(iter.deref(), tail_idx);
-                    self.subterm_to_instr::<Target>(
-                        tail, tail_loc, context, index_ptrs, &mut target,
-                    );
+                    target.push_back(Target::to_pstr(lvl, string.clone(), cell.get()));
+                    target.push_back(Target::constant_subterm(Literal::Atom(atom!("[]"))));
                 }
-                _ if lvl == Level::Shallow => {
-                    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, term, r));
-                    }
+                TermRef::Var(lvl @ Level::Shallow, cell, var) => {
+                    self.marker.mark_var::<Target>(
+                        var.to_var_num().unwrap(),
+                        lvl,
+                        cell,
+                        context,
+                        &mut target,
+                    );
                 }
                 _ => {}
-            );
+            };
         }
 
         target
@@ -630,57 +552,21 @@ impl CodeGenerator {
     fn compile_inlined(
         &mut self,
         ct: &InlinedClauseType,
-        terms: &mut FocusedHeapRefMut,
-        term_loc: usize,
-        context: GenContext,
+        terms: &'_ [Term],
+        term_loc: GenContext,
         code: &mut CodeDeque,
     ) -> Result<(), CompilationError> {
-        let first_arg_loc = terms.nth_arg(term_loc, 1).unwrap();
-        let first_arg = terms.deref_loc(first_arg_loc);
-
-        let chunk_num = context.chunk_num();
-        let mut variable_marker = |marker: &mut DebrayAllocator| {
-            read_heap_cell!(first_arg,
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, first_arg_loc) => {
-                    match marker.var_data.var_locs_to_nums.get(
-                        VarPtrIndex { chunk_num, term_loc: first_arg_loc },
-                    ) {
-                        VarPtr::Numbered(var_num) => {
-                            Some(marker.mark_non_callable(
-                                var_num,
-                                1,
-                                context,
-                                code,
-                            ))
-                        }
-                        VarPtr::Anon => {
-                            Some(marker.mark_anon_var::<QueryInstruction>(
-                                Level::Shallow,
-                                context,
-                                code,
-                            ))
-                        }
-                    }
-                }
-                _ => {
-                    marker.advance_arg();
-                    None
-                }
-            )
-        };
-
         let call_instr = match ct {
             &InlinedClauseType::CompareNumber(mut cmp) => {
                 self.marker.reset_arg(2);
 
-                let (mut lcode, at_1) = if let Some(r) = variable_marker(&mut self.marker) {
-                    (CodeDeque::default(), Some(ArithmeticTerm::Reg(r)))
-                } else {
-                    self.compile_arith_expr(terms, first_arg_loc, 1, context, 1)?
-                };
+                let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc, 1)?;
 
-                let (mut rcode, at_2) =
-                    self.compile_arith_expr(terms, first_arg_loc + 1, 2, context, 2)?;
+                if !matches!(terms[0], Term::Var(..)) {
+                    self.marker.advance_arg();
+                }
+
+                let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc, 2)?;
 
                 code.append(&mut lcode);
                 code.append(&mut rcode);
@@ -690,184 +576,207 @@ impl CodeGenerator {
 
                 compare_number_instr!(cmp, at_1, at_2)
             }
-            InlinedClauseType::IsAtom(..) => {
-                self.marker.reset_arg(1);
+            InlinedClauseType::IsAtom(..) => match &terms[0] {
+                Term::Literal(_, Literal::Atom(..)) => {
+                    instr!("$succeed")
+                }
+                Term::Var(ref vr, ref name) => {
+                    self.marker.reset_arg(1);
+
+                    let r = self.marker.mark_non_callable(
+                        name.to_var_num().unwrap(),
+                        1,
+                        term_loc,
+                        vr,
+                        code,
+                    );
 
-                if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("atom", r)
-                } else {
-                    read_heap_cell!(first_arg,
-                        (HeapCellValueTag::Atom, (_name, arity)) => {
-                            if arity == 0 {
-                                instr!("$succeed")
-                            } else {
-                                instr!("$fail")
-                            }
-                        }
-                        _ => {
-                            instr!("$fail")
-                        }
-                    )
                 }
-            }
-            InlinedClauseType::IsAtomic(..) => {
-                self.marker.reset_arg(1);
+                _ => {
+                    instr!("$fail")
+                }
+            },
+            InlinedClauseType::IsAtomic(..) => match &terms[0] {
+                Term::AnonVar
+                | Term::Clause(..)
+                | Term::Cons(..)
+                | Term::PartialString(..)
+                | Term::CompleteString(..) => {
+                    instr!("$fail")
+                }
+                Term::Literal(..) => {
+                    instr!("$succeed")
+                }
+                Term::Var(ref vr, ref name) => {
+                    self.marker.reset_arg(1);
+
+                    let r = self.marker.mark_non_callable(
+                        name.to_var_num().unwrap(),
+                        1,
+                        term_loc,
+                        vr,
+                        code,
+                    );
 
-                if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("atomic", r)
-                } else {
-                    read_heap_cell!(first_arg,
-                        (HeapCellValueTag::Fixnum |
-                         HeapCellValueTag::F64) => {
-                            instr!("$succeed")
-                        }
-                        (HeapCellValueTag::Cons, cons_ptr) => {
-                            match cons_ptr.get_tag() {
-                                ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => {
-                                    instr!("$succeed")
-                                }
-                                _ => {
-                                    instr!("$fail")
-                                }
-                            }
-                        }
-                        (HeapCellValueTag::Atom, (_name, arity)) => {
-                            if arity == 0 {
-                                instr!("$succeed")
-                            } else {
-                                instr!("$fail")
-                            }
-                        }
-                        (HeapCellValueTag::Lis
-                         | HeapCellValueTag::Str
-                         | HeapCellValueTag::PStrLoc) => {
-                            instr!("$fail")
-                        }
-                        _ => {
-                            if first_arg.is_constant() {
-                                instr!("$succeed")
-                            } else {
-                                instr!("$fail")
-                            }
-                        }
-                    )
                 }
-            }
-            InlinedClauseType::IsCompound(..) => {
-                self.marker.reset_arg(1);
+            },
+            InlinedClauseType::IsCompound(..) => match &terms[0] {
+                Term::Clause(..)
+                | Term::Cons(..)
+                | Term::PartialString(..)
+                | Term::CompleteString(..) => {
+                    instr!("$succeed")
+                }
+                Term::Var(ref vr, ref name) => {
+                    self.marker.reset_arg(1);
+
+                    let r = self.marker.mark_non_callable(
+                        name.to_var_num().unwrap(),
+                        1,
+                        term_loc,
+                        vr,
+                        code,
+                    );
 
-                if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("compound", r)
-                } else {
-                    read_heap_cell!(first_arg,
-                        (HeapCellValueTag::Atom, (_, arity)) => {
-                            if arity > 0 {
-                                instr!("$succeed")
-                            } else {
-                                instr!("$fail")
-                            }
-                        }
-                        (HeapCellValueTag::Lis
-                         | HeapCellValueTag::Str
-                         | HeapCellValueTag::PStrLoc) => {
-                            instr!("$succeed")
-                        }
-                        _ => {
-                            instr!("$fail")
-                        }
-                    )
                 }
-            }
-            InlinedClauseType::IsRational(..) => {
-                self.marker.reset_arg(1);
-
-                if let Some(r) = variable_marker(&mut self.marker) {
+                _ => {
+                    instr!("$fail")
+                }
+            },
+            InlinedClauseType::IsRational(..) => match terms[0] {
+                Term::Literal(_, Literal::Rational(_)) => {
+                    instr!("$succeed")
+                }
+                Term::Var(ref vr, ref name) => {
+                    self.marker.reset_arg(1);
+                    let r = self.marker.mark_non_callable(
+                        name.to_var_num().unwrap(),
+                        1,
+                        term_loc,
+                        vr,
+                        code,
+                    );
                     instr!("rational", r)
-                } else {
-                    read_heap_cell!(first_arg,
-                        (HeapCellValueTag::Cons, cons_ptr) => {
-                            match cons_ptr.get_tag() {
-                                ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => {
-                                    instr!("$succeed")
-                                }
-                                _ => {
-                                    instr!("$fail")
-                                }
-                            }
-                        }
-                        (HeapCellValueTag::Fixnum) => {
-                            instr!("$succeed")
-                        }
-                        _ => {
-                            instr!("$fail")
-                        }
-                    )
                 }
-            }
-            InlinedClauseType::IsFloat(..) => {
-                self.marker.reset_arg(1);
+                _ => {
+                    instr!("$fail")
+                }
+            },
+            InlinedClauseType::IsFloat(..) => match terms[0] {
+                Term::Literal(_, Literal::Float(_)) => {
+                    instr!("$succeed")
+                }
+                Term::Var(ref vr, ref name) => {
+                    self.marker.reset_arg(1);
+
+                    let r = self.marker.mark_non_callable(
+                        name.to_var_num().unwrap(),
+                        1,
+                        term_loc,
+                        vr,
+                        code,
+                    );
 
-                if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("float", r)
-                } else {
-                    read_heap_cell!(first_arg,
-                        (HeapCellValueTag::F64) => {
-                            instr!("$succeed")
-                        }
-                        _ => {
-                            instr!("$fail")
-                        }
-                    )
                 }
-            }
-            InlinedClauseType::IsNumber(..) => {
-                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!("$fail")
+                }
+            },
+            InlinedClauseType::IsNumber(..) => match terms[0] {
+                Term::Literal(_, Literal::Float(_))
+                | Term::Literal(_, Literal::Rational(_))
+                | Term::Literal(_, Literal::Integer(_))
+                | Term::Literal(_, Literal::Fixnum(_)) => {
                     instr!("$succeed")
-                } else {
+                }
+                Term::Var(ref vr, ref name) => {
+                    self.marker.reset_arg(1);
+
+                    let r = self.marker.mark_non_callable(
+                        name.to_var_num().unwrap(),
+                        1,
+                        term_loc,
+                        vr,
+                        code,
+                    );
+
+                    instr!("number", r)
+                }
+                _ => {
                     instr!("$fail")
                 }
-            }
-            InlinedClauseType::IsNonVar(..) => {
-                self.marker.reset_arg(1);
+            },
+            InlinedClauseType::IsNonVar(..) => match terms[0] {
+                Term::AnonVar => {
+                    instr!("$fail")
+                }
+                Term::Var(ref vr, ref name) => {
+                    self.marker.reset_arg(1);
+
+                    let r = self.marker.mark_non_callable(
+                        name.to_var_num().unwrap(),
+                        1,
+                        term_loc,
+                        vr,
+                        code,
+                    );
 
-                if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("nonvar", r)
-                } else if first_arg.is_var() {
-                    instr!("$fail")
-                } else {
+                }
+                _ => {
                     instr!("$succeed")
                 }
-            }
-            InlinedClauseType::IsInteger(..) => {
-                self.marker.reset_arg(1);
+            },
+            InlinedClauseType::IsInteger(..) => match &terms[0] {
+                Term::Literal(_, Literal::Integer(_)) | Term::Literal(_, Literal::Fixnum(_)) => {
+                    instr!("$succeed")
+                }
+                Term::Var(ref vr, name) => {
+                    self.marker.reset_arg(1);
+
+                    let r = self.marker.mark_non_callable(
+                        name.to_var_num().unwrap(),
+                        1,
+                        term_loc,
+                        vr,
+                        code,
+                    );
 
-                if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("integer", r)
-                } else {
-                    match Number::try_from(first_arg) {
-                        Ok(Number::Integer(_) | Number::Fixnum(_)) => {
-                            instr!("$succeed")
-                        }
-                        _ => {
-                            instr!("$fail")
-                        }
-                    }
                 }
-            }
-            InlinedClauseType::IsVar(..) => {
-                self.marker.reset_arg(1);
+                _ => {
+                    instr!("$fail")
+                }
+            },
+            InlinedClauseType::IsVar(..) => match terms[0] {
+                Term::Literal(..)
+                | Term::Clause(..)
+                | Term::Cons(..)
+                | Term::PartialString(..)
+                | Term::CompleteString(..) => {
+                    instr!("$fail")
+                }
+                Term::AnonVar => {
+                    instr!("$succeed")
+                }
+                Term::Var(ref vr, ref name) => {
+                    self.marker.reset_arg(1);
+
+                    let r = self.marker.mark_non_callable(
+                        name.to_var_num().unwrap(),
+                        1,
+                        term_loc,
+                        vr,
+                        code,
+                    );
 
-                if let Some(r) = variable_marker(&mut self.marker) {
                     instr!("var", r)
-                } else if first_arg.is_var() {
-                    instr!("$succeed")
-                } else {
-                    instr!("$fail")
                 }
-            }
+            },
         };
 
         // inlined predicates are never counted, so this overrides nothing.
@@ -877,27 +786,25 @@ impl CodeGenerator {
 
     fn compile_arith_expr(
         &mut self,
-        terms: &mut FocusedHeapRefMut,
-        term_loc: usize,
+        term: &Term,
         target_int: usize,
-        context: GenContext,
+        term_loc: GenContext,
         arg: usize,
     ) -> Result<ArithCont, ArithmeticError> {
         let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int);
-        evaluator.compile_is(terms, term_loc, context, arg)
+        evaluator.compile_is(term, term_loc, arg)
     }
 
     fn compile_is_call(
         &mut self,
-        terms: &mut FocusedHeapRefMut,
-        term_loc: usize,
+        terms: &[Term],
         code: &mut CodeDeque,
-        context: GenContext,
+        term_loc: GenContext,
         call_policy: CallPolicy,
     ) -> Result<(), CompilationError> {
         macro_rules! compile_expr {
-            ($self:expr, $terms:expr, $context:expr, $code:expr) => {{
-                let (acode, at) = $self.compile_arith_expr($terms, term_loc + 2, 1, $context, 2)?;
+            ($self:expr, $terms:expr, $term_loc:expr, $code:expr) => {{
+                let (acode, at) = $self.compile_arith_expr($terms, 1, $term_loc, 2)?;
                 $code.extend(acode.into_iter());
                 at
             }};
@@ -905,48 +812,70 @@ impl CodeGenerator {
 
         self.marker.reset_arg(2);
 
-        let var = heap_bound_store(
-            terms.heap,
-            heap_bound_deref(terms.heap, heap_loc_as_cell!(term_loc + 1)),
-        );
+        let at = match terms[0] {
+            Term::Var(ref vr, ref name) => {
+                let var_num = name.to_var_num().unwrap();
+
+                if self.marker.var_data.records[var_num].num_occurrences > 1 {
+                    self.marker.mark_var::<QueryInstruction>(
+                        var_num,
+                        Level::Shallow,
+                        vr,
+                        term_loc,
+                        code,
+                    );
+
+                    self.marker.mark_safe_var_unconditionally(var_num);
+                    compile_expr!(self, &terms[1], term_loc, code)
+                } else {
+                    self.marker
+                        .mark_anon_var::<QueryInstruction>(Level::Shallow, term_loc, code);
 
-        let at = read_heap_cell!(var,
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
-                let chunk_num = context.chunk_num();
+                    if let Term::Var(ref vr, ref var) = &terms[1] {
+                        let var_num = var.to_var_num().unwrap();
 
-                match self.marker.var_data.var_locs_to_nums.get(
-                    VarPtrIndex { chunk_num, term_loc },
-                ) {
-                    VarPtr::Numbered(var_num) => {
+                        // if var is an anonymous variable, insert
+                        // is/2 call so that an instantiation error is
+                        // thrown when the predicate is run.
                         if self.marker.var_data.records[var_num].num_occurrences > 1 {
                             self.marker.mark_var::<QueryInstruction>(
                                 var_num,
                                 Level::Shallow,
-                                context,
+                                vr,
+                                term_loc,
                                 code,
                             );
 
                             self.marker.mark_safe_var_unconditionally(var_num);
+
+                            let at = ArithmeticTerm::Reg(vr.get().norm());
+                            self.add_call(code, instr!("$get_number", at), call_policy);
+
+                            return Ok(());
                         }
                     }
-                    VarPtr::Anon => {}
-                };
 
-                compile_expr!(self, terms, context, code)
+                    compile_expr!(self, &terms[1], term_loc, code)
+                }
+            }
+            Term::Literal(
+                _,
+                c @ Literal::Integer(_)
+                | c @ Literal::Float(_)
+                | c @ Literal::Rational(_)
+                | c @ Literal::Fixnum(_),
+            ) => {
+                let v = HeapCellValue::from(c);
+                code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
+
+                self.marker.advance_arg();
+                compile_expr!(self, &terms[1], term_loc, code)
             }
             _ => {
-                if Number::try_from(var).is_ok() {
-                    let v = HeapCellValue::from(var);
-                    code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
-
-                    self.marker.advance_arg();
-                    compile_expr!(self, terms, context, code)
-                } else {
-                    code.push_back(instr!("$fail"));
-                    return Ok(());
-                }
+                code.push_back(instr!("$fail"));
+                return Ok(());
             }
-        );
+        };
 
         let at = at.unwrap_or(interm!(1));
         self.add_call(code, instr!("is", temp_v!(1), at), call_policy);
@@ -955,18 +884,18 @@ impl CodeGenerator {
 
     fn compile_seq(
         &mut self,
-        mut focused_heap: FocusedHeapRefMut,
         clauses: &ChunkedTermVec,
         code: &mut CodeDeque,
     ) -> Result<(), CompilationError> {
+        let mut chunk_num = 0;
         let mut branch_code_stack = BranchCodeStack::new();
         let mut clause_iter = ClauseIterator::new(clauses);
 
         while let Some(clause_item) = clause_iter.next() {
             match clause_item {
-                ClauseItem::Chunk { chunk_num, terms } => {
+                ClauseItem::Chunk { terms } => {
                     for (idx, term) in terms.iter().enumerate() {
-                        let context = if idx + 1 < terms.len() {
+                        let term_loc = if idx + 1 < terms.len() {
                             GenContext::Mid(chunk_num)
                         } else {
                             self.marker.in_tail_position = clause_iter.in_tail_position();
@@ -995,7 +924,7 @@ impl CodeGenerator {
                                 if chunk_num == 0 {
                                     code.push_back(instr!("neck_cut"));
                                 } else {
-                                    let r = self.marker.get_var_binding(var_num);
+                                    let r = self.marker.get_binding(var_num);
                                     code.push_back(instr!("cut", r));
                                 }
 
@@ -1009,7 +938,7 @@ impl CodeGenerator {
                             }
                             &QueryTerm::LocalCut { var_num, cut_prev } => {
                                 let code = branch_code_stack.code(code);
-                                let r = self.marker.get_var_binding(var_num);
+                                let r = self.marker.get_binding(var_num);
 
                                 code.push_back(if cut_prev {
                                     instr!("cut_prev", r)
@@ -1028,51 +957,31 @@ impl CodeGenerator {
                                 }
                             }
                             &QueryTerm::Clause(
-                                ref clause @ QueryClause {
-                                    ct: ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
-                                    call_policy,
-                                    ..
-                                },
+                                _,
+                                ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
+                                ref terms,
+                                call_policy,
                             ) => self.compile_is_call(
-                                &mut focused_heap,
-                                clause.term_loc(),
+                                terms,
                                 branch_code_stack.code(code),
-                                context,
+                                term_loc,
                                 call_policy,
                             )?,
-                            &QueryTerm::Clause(
-                                ref clause @ QueryClause {
-                                    ct: ClauseType::Inlined(ref ct),
-                                    ..
-                                },
-                            ) => self.compile_inlined(
-                                ct,
-                                &mut focused_heap,
-                                clause.term_loc(),
-                                context,
-                                branch_code_stack.code(code),
-                            )?,
+                            &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => {
+                                self.compile_inlined(
+                                    ct,
+                                    terms,
+                                    term_loc,
+                                    branch_code_stack.code(code),
+                                )?
+                            }
                             &QueryTerm::Fail => {
                                 branch_code_stack.code(code).push_back(instr!("$fail"));
                             }
-                            &QueryTerm::Succeed => {
-                                let code = branch_code_stack.code(code);
-
-                                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").into_execute()
-                                } else {
-                                    instr!("$succeed")
-                                });
-                            }
-                            QueryTerm::Clause(clause) => {
+                            term @ &QueryTerm::Clause(..) => {
                                 self.compile_query_line(
-                                    &mut focused_heap,
-                                    clause,
-                                    context,
+                                    term,
+                                    term_loc,
                                     branch_code_stack.code(code),
                                 );
 
@@ -1083,6 +992,7 @@ impl CodeGenerator {
                         }
                     }
 
+                    chunk_num += 1;
                     self.marker.in_tail_position = false;
                     self.marker.reset_contents();
                 }
@@ -1130,32 +1040,20 @@ impl CodeGenerator {
 
     pub(crate) fn compile_rule(
         &mut self,
-        heap: &mut Heap,
-        rule: &mut Rule,
+        rule: &Rule,
         var_data: VarData,
     ) -> Result<Code, CompilationError> {
-        let Rule { term_loc, clauses } = rule;
-
+        let Rule {
+            head: (_, args),
+            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(args);
 
-        self.marker.reset_at_head(term.heap, head_loc);
-
-        let mut stack = Stack::uninitialized();
-        let iter = fact_iterator::<true>(term.heap, &mut stack, head_loc);
-
-        let fact = self.compile_target::<FactInstruction, _>(
-            iter,
-            &IndexMap::with_hasher(FxBuildHasher::default()),
-            GenContext::Head,
-        );
+        let iter = FactIterator::from_rule_head_clause(args);
+        let fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head);
 
         if self.marker.max_reg_allocated() > MAX_ARITY {
             return Err(CompilationError::ExceededMaxArity);
@@ -1164,72 +1062,61 @@ impl CodeGenerator {
         self.marker.reset_free_list();
         code.extend(fact);
 
-        self.compile_seq(term, &clauses, &mut code)?;
+        self.compile_seq(clauses, &mut code)?;
 
         Ok(Vec::from(code))
     }
 
     pub(crate) fn compile_fact(
         &mut self,
-        heap: &mut Heap,
-        fact: &mut Fact,
+        fact: &Fact,
         var_data: VarData,
     ) -> Result<Code, CompilationError> {
         let mut code = Vec::new();
-
-        let mut stack = Stack::uninitialized();
-
         self.marker.var_data = var_data;
-        self.marker.reset_at_head(heap, fact.term_loc);
 
-        let iter = fact_iterator::<true>(heap, &mut stack, fact.term_loc);
+        if let Term::Clause(_, _, args) = &fact.head {
+            self.marker.reset_at_head(args);
 
-        let compiled_fact = self.compile_target::<FactInstruction, _>(
-            iter,
-            &IndexMap::with_hasher(FxBuildHasher::default()),
-            GenContext::Head,
-        );
+            let iter = FactInstruction::iter(&fact.head);
+            let compiled_fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head);
 
-        if self.marker.max_reg_allocated() > MAX_ARITY {
-            return Err(CompilationError::ExceededMaxArity);
+            if self.marker.max_reg_allocated() > MAX_ARITY {
+                return Err(CompilationError::ExceededMaxArity);
+            }
+
+            code.extend(compiled_fact);
         }
 
-        code.extend(compiled_fact);
         code.push(instr!("proceed"));
-
         Ok(code)
     }
 
-    fn compile_query_line(
-        &mut self,
-        term: &mut FocusedHeapRefMut,
-        clause: &QueryClause,
-        context: GenContext,
-        code: &mut CodeDeque,
-    ) {
-        self.marker.reset_arg(term.arity(clause.term_loc()));
-
-        let mut stack = Stack::uninitialized();
-        let iter = query_iterator::<true>(&mut term.heap, &mut stack, clause.term_loc());
+    fn compile_query_line(&mut self, term: &QueryTerm, term_loc: GenContext, code: &mut CodeDeque) {
+        self.marker.reset_arg(term.arity());
 
-        let query = self.compile_target::<QueryInstruction, _>(iter, &clause.code_indices, context);
+        let iter = QueryIterator::new(term);
+        let query = self.compile_target::<QueryInstruction, _>(iter, term_loc);
 
         code.extend(query);
-        self.add_call(code, clause.ct.to_instr(), clause.call_policy);
+
+        match term {
+            &QueryTerm::Clause(_, ref ct, _, call_policy) => {
+                self.add_call(code, ct.to_instr(), call_policy);
+            }
+            _ => unreachable!(),
+        };
     }
 
-    fn split_predicate(heap: &mut Heap, clauses: &[PredicateClause]) -> Vec<ClauseSpan> {
+    fn split_predicate(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(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 let Some(args) = clause.args() {
+                for (instantiated_arg_index, arg) in args.iter().enumerate() {
+                    if !matches!(arg, Term::Var(..) | Term::AnonVar) {
                         if optimal_index != instantiated_arg_index {
                             if left >= right {
                                 optimal_index = instantiated_arg_index;
@@ -1283,7 +1170,6 @@ impl CodeGenerator {
 
     fn compile_pred_subseq<I: Indexer>(
         &mut self,
-        heap: &mut Heap,
         clauses: &mut [PredicateClause],
         optimal_index: usize,
     ) -> Result<Code, CompilationError> {
@@ -1302,11 +1188,11 @@ impl CodeGenerator {
             let clause_code = match clause {
                 PredicateClause::Fact(fact, var_data) => {
                     let var_data = std::mem::take(var_data);
-                    self.compile_fact(heap, fact, var_data)?
+                    self.compile_fact(fact, var_data)?
                 }
                 PredicateClause::Rule(rule, var_data) => {
                     let var_data = std::mem::take(var_data);
-                    self.compile_rule(heap, rule, var_data)?
+                    self.compile_rule(rule, var_data)?
                 }
             };
 
@@ -1334,14 +1220,13 @@ impl CodeGenerator {
                 skip_stub_try_me_else = !self.settings.is_dynamic();
             }
 
-            let arg = clause.args(heap).map(|r| heap[r.start() + optimal_index]);
+            let arg = clause.args().and_then(|args| args.get(optimal_index));
 
             if let Some(arg) = arg {
                 let index = code.len();
 
                 if clauses_len > 1 || self.settings.is_extensible {
-                    let arg = heap_bound_store(heap, heap_bound_deref(heap, arg));
-                    code_offsets.index_term(heap, arg, index, &mut clause_index_info);
+                    code_offsets.index_term(arg, index, &mut clause_index_info);
                 }
             }
 
@@ -1371,12 +1256,11 @@ impl CodeGenerator {
 
     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(heap, &clauses);
+        let split_pred = Self::split_predicate(&clauses);
         let multi_seq = split_pred.len() > 1;
 
         for ClauseSpan {
@@ -1388,13 +1272,11 @@ impl CodeGenerator {
             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 7c86bb881ba13bb957fa5493519f6e359a3fad96..3bc96dfce9d9d52600457659e9c1c12ded25c6c4 100644 (file)
@@ -1,13 +1,10 @@
 use crate::allocator::*;
-use crate::atom_table::*;
 use crate::codegen::SubsumedBranchHits;
 use crate::forms::{GenContext, Level};
 use crate::instructions::*;
-use crate::machine::disjuncts::*;
-use crate::machine::heap::*;
+use crate::machine::disjuncts::VarData;
 use crate::parser::ast::*;
 use crate::targets::*;
-use crate::types::*;
 use crate::variable_records::*;
 
 use bit_set::*;
@@ -15,6 +12,7 @@ use bitvec::prelude::*;
 use fxhash::FxBuildHasher;
 use indexmap::IndexMap;
 
+use std::cell::Cell;
 use std::collections::VecDeque;
 use std::ops::{Deref, DerefMut};
 
@@ -154,8 +152,6 @@ pub(crate) struct DebrayAllocator {
     in_use: BitSet<usize>, // deep and non-var allocations
     temp_free_list: Vec<usize>,
     perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num
-    non_var_registers: IndexMap<usize, usize, FxBuildHasher>,
-    non_var_register_heap_locs: IndexMap<usize, usize, FxBuildHasher>,
 }
 
 impl DebrayAllocator {
@@ -172,9 +168,7 @@ impl DebrayAllocator {
 
         for var_num in subsumed_hits {
             match &mut self.var_data.records[var_num].allocation {
-                VarAlloc::Perm {
-                    ref mut allocation, ..
-                } => {
+                VarAlloc::Perm(_, ref mut allocation) => {
                     if let PermVarAllocation::Done {
                         shallow_safety,
                         deep_safety,
@@ -235,7 +229,7 @@ impl DebrayAllocator {
             let num_occurrences = self.var_data.records[var_num].num_occurrences;
 
             match &mut self.var_data.records[var_num].allocation {
-                VarAlloc::Perm { allocation, .. } => {
+                VarAlloc::Perm(_, allocation) => {
                     let shallow_safety = VarSafetyStatus::needed_if(
                         shallow_safety.contains(var_num),
                         branch_designator,
@@ -372,7 +366,7 @@ impl DebrayAllocator {
         &mut self,
         chunk_num: usize,
         code: &mut CodeDeque,
-    ) -> Option<RegType> {
+    ) {
         if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) {
             let k = self.arg_c;
 
@@ -388,12 +382,8 @@ impl DebrayAllocator {
                     .allocation
                     .set_register(r.reg_num());
                 self.in_use.insert(r.reg_num());
-
-                return Some(r);
             }
         };
-
-        None
     }
 
     fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
@@ -443,7 +433,6 @@ impl DebrayAllocator {
         }
 
         self.temp_lb = final_index + 1;
-
         final_index
     }
 
@@ -467,11 +456,7 @@ impl DebrayAllocator {
             p
         };
 
-        self.var_data.records[var_num].allocation = VarAlloc::Perm {
-            reg: p,
-            allocation: PermVarAllocation::done(),
-        };
-
+        self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done());
         p
     }
 
@@ -487,15 +472,10 @@ impl DebrayAllocator {
     }
 
     #[inline(always)]
-    pub fn get_var_binding(&self, var_num: usize) -> RegType {
+    pub fn get_binding(&self, var_num: usize) -> RegType {
         self.var_data.records[var_num].allocation.as_reg_type()
     }
 
-    #[inline(always)]
-    pub fn get_non_var_binding(&self, heap_loc: usize) -> RegType {
-        RegType::Temp(self.non_var_registers.get(&heap_loc).cloned().unwrap_or(0))
-    }
-
     pub fn num_perm_vars(&self) -> usize {
         self.perm_lb - 1
     }
@@ -505,7 +485,7 @@ impl DebrayAllocator {
     }
 
     fn add_perm_to_free_list(&mut self, chunk_num: usize, var_num: usize) {
-        if let VarAlloc::Perm { .. } = &self.var_data.records[var_num].allocation {
+        if let VarAlloc::Perm(..) = &self.var_data.records[var_num].allocation {
             self.perm_free_list.push_back((chunk_num, var_num));
         }
     }
@@ -516,10 +496,7 @@ impl DebrayAllocator {
                 self.perm_free_list.pop_front();
 
                 match &mut self.var_data.records[var_num].allocation {
-                    VarAlloc::Perm {
-                        reg: p,
-                        allocation: PermVarAllocation::Pending,
-                    } if *p > 0 => {
+                    VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => {
                         return Some(std::mem::replace(p, 0));
                     }
                     _ => {}
@@ -533,12 +510,9 @@ impl DebrayAllocator {
     }
 
     pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) {
-        match &mut self.var_data.records[var_num].allocation {
-            VarAlloc::Perm { allocation, .. } => {
-                *allocation = PermVarAllocation::Pending;
-                self.add_perm_to_free_list(chunk_num, var_num);
-            }
-            _ => {}
+        if let VarAlloc::Perm(_, allocation) = &mut self.var_data.records[var_num].allocation {
+            *allocation = PermVarAllocation::Pending;
+            self.add_perm_to_free_list(chunk_num, var_num);
         }
     }
 
@@ -546,15 +520,14 @@ impl DebrayAllocator {
         let branch_designator = self.branch_stack.current_branch_designator();
 
         match &mut self.var_data.records[var_num].allocation {
-            VarAlloc::Perm {
-                allocation:
-                    PermVarAllocation::Done {
-                        deep_safety,
-                        shallow_safety,
-                        ..
-                    },
-                ..
-            } => {
+            VarAlloc::Perm(
+                _,
+                PermVarAllocation::Done {
+                    deep_safety,
+                    shallow_safety,
+                    ..
+                },
+            ) => {
                 *deep_safety = VarSafetyStatus::unneeded(branch_designator);
                 *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
             }
@@ -562,8 +535,7 @@ impl DebrayAllocator {
                 *safety = VarSafetyStatus::unneeded(branch_designator);
             }
             _ => {
-                // the (permanent) variable might have been freed by
-                // this point, in which case we do nothing.
+                unreachable!()
             }
         }
     }
@@ -572,15 +544,14 @@ impl DebrayAllocator {
         let branch_designator = self.branch_stack.current_branch_designator();
 
         match &mut self.var_data.records[var_num].allocation {
-            VarAlloc::Perm {
-                allocation:
-                    PermVarAllocation::Done {
-                        deep_safety,
-                        shallow_safety,
-                        ..
-                    },
-                ..
-            } => {
+            VarAlloc::Perm(
+                _,
+                PermVarAllocation::Done {
+                    deep_safety,
+                    shallow_safety,
+                    ..
+                },
+            ) => {
                 // GetVariable in head chunk is considered safe.
                 if lvl == Level::Deep {
                     *deep_safety = VarSafetyStatus::unneeded(branch_designator);
@@ -617,14 +588,13 @@ impl DebrayAllocator {
         let branch_designator = self.branch_stack.current_branch_designator();
 
         match &mut self.var_data.records[var_num].allocation {
-            VarAlloc::Perm {
-                allocation:
-                    PermVarAllocation::Done {
-                        ref mut shallow_safety,
-                        ..
-                    },
-                ..
-            } => {
+            VarAlloc::Perm(
+                _,
+                PermVarAllocation::Done {
+                    ref mut shallow_safety,
+                    ..
+                },
+            ) => {
                 if !self.in_tail_position
                     || self
                         .branch_stack
@@ -654,14 +624,13 @@ impl DebrayAllocator {
         let branch_designator = self.branch_stack.current_branch_designator();
 
         match &mut self.var_data.records[var_num].allocation {
-            VarAlloc::Perm {
-                allocation:
-                    PermVarAllocation::Done {
-                        ref mut deep_safety,
-                        ..
-                    },
-                ..
-            } => {
+            VarAlloc::Perm(
+                _,
+                PermVarAllocation::Done {
+                    ref mut deep_safety,
+                    ..
+                },
+            ) => {
                 if self
                     .branch_stack
                     .safety_unneeded_in_branch(deep_safety, &branch_designator)
@@ -704,15 +673,13 @@ impl Allocator for DebrayAllocator {
             temp_free_list: vec![],
             perm_free_list: VecDeque::new(),
             branch_stack: BranchStack { stack: vec![] },
-            non_var_registers: IndexMap::with_hasher(FxBuildHasher::default()),
-            non_var_register_heap_locs: IndexMap::with_hasher(FxBuildHasher::default()),
         }
     }
 
     fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
         &mut self,
         lvl: Level,
-        context: GenContext,
+        term_loc: GenContext,
         code: &mut CodeDeque,
     ) -> RegType {
         let r = RegType::Temp(self.alloc_reg_to_non_var());
@@ -722,7 +689,7 @@ impl Allocator for DebrayAllocator {
             Level::Root | Level::Shallow => {
                 let k = self.arg_c;
 
-                if let GenContext::Last(chunk_num) = context {
+                if let GenContext::Last(chunk_num) = term_loc {
                     self.evacuate_arg::<Target>(chunk_num, code);
                 }
 
@@ -738,69 +705,55 @@ impl Allocator for DebrayAllocator {
     fn mark_non_var<'a, Target: CompilationTarget<'a>>(
         &mut self,
         lvl: Level,
-        heap_loc: usize,
-        context: GenContext,
+        term_loc: GenContext,
+        cell: &'a Cell<RegType>,
         code: &mut CodeDeque,
-    ) -> RegType {
-        let r = self.get_non_var_binding(heap_loc);
+    ) {
+        let r = cell.get();
 
         let r = match lvl {
             Level::Shallow => {
                 let k = self.arg_c;
 
-                if let GenContext::Last(chunk_num) = context {
-                    if let Some(new_r) = self.evacuate_arg::<Target>(chunk_num, code) {
-                        self.non_var_register_heap_locs
-                            .swap_remove(&k)
-                            .map(|old_heap_loc| {
-                                self.non_var_registers.insert(old_heap_loc, new_r.reg_num());
-                                self.non_var_register_heap_locs
-                                    .insert(new_r.reg_num(), old_heap_loc);
-                            });
-
-                        self.non_var_registers.insert(heap_loc, k);
-                        self.non_var_register_heap_locs.insert(k, heap_loc);
-                    }
+                if let GenContext::Last(chunk_num) = term_loc {
+                    self.evacuate_arg::<Target>(chunk_num, code);
                 }
 
                 self.arg_c += 1;
                 RegType::Temp(k)
             }
-            _ if r.reg_num() == 0 => {
-                let r = RegType::Temp(self.alloc_reg_to_non_var());
-                self.non_var_registers.insert(heap_loc, r.reg_num());
-                self.non_var_register_heap_locs
-                    .insert(r.reg_num(), heap_loc);
-                r
-            }
+            _ if r.reg_num() == 0 => RegType::Temp(self.alloc_reg_to_non_var()),
             _ => {
                 self.in_use.insert(r.reg_num());
                 r
             }
         };
 
-        r
+        cell.set(r);
     }
 
     fn mark_var<'a, Target: CompilationTarget<'a>>(
         &mut self,
         var_num: usize,
         lvl: Level,
-        context: GenContext,
+        cell: &Cell<VarReg>,
+        term_loc: GenContext,
         code: &mut CodeDeque,
-    ) -> RegType {
-        let (r, is_new_var) = match self.get_var_binding(var_num) {
+    ) {
+        let (r, is_new_var) = match self.get_binding(var_num) {
             RegType::Temp(0) => {
-                let o = self.alloc_reg_to_var::<Target>(var_num, lvl, context, code);
+                let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
+                cell.set(VarReg::Norm(RegType::Temp(o)));
                 (RegType::Temp(o), true)
             }
             RegType::Perm(0) => {
-                let p = self.alloc_perm_var(var_num, context.chunk_num());
+                let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
+                cell.set(VarReg::Norm(RegType::Perm(p)));
                 (RegType::Perm(p), true)
             }
             r @ RegType::Perm(_) => {
                 let is_new_var = match &mut self.var_data.records[var_num].allocation {
-                    VarAlloc::Perm { allocation, .. } => {
+                    VarAlloc::Perm(_, allocation) => {
                         if allocation.pending() {
                             *allocation = PermVarAllocation::done();
                             true
@@ -816,29 +769,32 @@ impl Allocator for DebrayAllocator {
             r => (r, false),
         };
 
-        self.mark_reserved_var::<Target>(var_num, lvl, context, code, r, is_new_var)
+        self.mark_reserved_var::<Target>(var_num, lvl, cell, term_loc, code, r, is_new_var);
     }
 
     fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
         &mut self,
         var_num: usize,
         lvl: Level,
-        context: GenContext,
+        cell: &Cell<VarReg>,
+        term_loc: GenContext,
         code: &mut CodeDeque,
         r: RegType,
         is_new_var: bool,
-    ) -> RegType {
+    ) {
         match lvl {
             Level::Root | Level::Shallow => {
                 let k = self.arg_c;
 
                 if self.is_curr_arg_distinct_from(var_num) {
-                    self.evacuate_arg::<Target>(context.chunk_num(), code);
+                    self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
                 }
 
-                if !self.in_place(var_num, context, r, k) {
+                cell.set(VarReg::ArgAndNorm(r, k));
+
+                if !self.in_place(var_num, term_loc, r, k) {
                     if is_new_var {
-                        self.mark_safe_var(var_num, lvl, context);
+                        self.mark_safe_var(var_num, lvl, term_loc);
                         code.push_back(Target::argument_to_variable(r, k));
                     } else {
                         code.push_back(self.argument_to_value::<Target>(var_num, r, k));
@@ -848,15 +804,15 @@ impl Allocator for DebrayAllocator {
                 self.arg_c += 1;
             }
             Level::Deep if is_new_var => {
-                if let GenContext::Head = context {
+                if let GenContext::Head = term_loc {
                     if self.occurs_shallowly_in_head(var_num, r.reg_num()) {
                         code.push_back(self.subterm_to_value::<Target>(var_num, r));
                     } else {
-                        self.mark_safe_var(var_num, lvl, context);
+                        self.mark_safe_var(var_num, lvl, term_loc);
                         code.push_back(Target::subterm_to_variable(r));
                     }
                 } else {
-                    self.mark_safe_var(var_num, lvl, context);
+                    self.mark_safe_var(var_num, lvl, term_loc);
                     code.push_back(Target::subterm_to_variable(r));
                 }
             }
@@ -878,15 +834,14 @@ impl Allocator for DebrayAllocator {
         if record.running_count < record.num_occurrences {
             record.running_count += 1;
         } else {
-            self.free_var(context.chunk_num(), var_num);
+            self.free_var(term_loc.chunk_num(), var_num);
         }
 
         self.in_use.insert(o);
-        r
     }
 
     fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
-        match self.get_var_binding(var_num) {
+        match self.get_binding(var_num) {
             RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)),
             RegType::Temp(0) => {
                 let t = self.alloc_reg_to_non_var();
@@ -910,8 +865,6 @@ impl Allocator for DebrayAllocator {
     fn reset(&mut self) {
         self.perm_lb = 1;
         self.shallow_temp_mappings.clear();
-        self.non_var_registers.clear();
-        self.non_var_register_heap_locs.clear();
         self.in_use.clear();
         self.temp_free_list.clear();
     }
@@ -919,8 +872,6 @@ impl Allocator for DebrayAllocator {
     fn reset_contents(&mut self) {
         self.in_use.clear();
         self.shallow_temp_mappings.clear();
-        self.non_var_registers.clear();
-        self.non_var_register_heap_locs.clear();
         self.temp_free_list.clear();
     }
 
@@ -928,54 +879,24 @@ impl Allocator for DebrayAllocator {
         self.arg_c += 1;
     }
 
-    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!(heap[s]).get_arity();
-
-                self.reset_arg(arity);
-                self.arity = arity;
+    fn reset_at_head(&mut self, args: &[Term]) {
+        self.reset_arg(args.len());
+        self.arity = args.len();
 
-                for (c_idx, heap_idx) in (s+1 ..= s+arity).enumerate() {
-                    let arg = heap[heap_idx];
-
-                    if arg.is_var() {
-                        let var = heap_bound_store(
-                            heap,
-                            heap_bound_deref(heap, arg),
-                        );
-
-                        if !var.is_var() {
-                            continue;
-                        }
+        for (idx, arg) in args.iter().enumerate() {
+            if let Term::Var(_, ref var) = arg {
+                let var_num = var.to_var_num().unwrap();
+                let r = self.get_binding(var_num);
 
-                        let term_loc = var.get_value() as usize;
-
-                        match self.var_data.var_locs_to_nums.get(
-                            VarPtrIndex { chunk_num: 0, term_loc },
-                        ) {
-                            VarPtr::Numbered(var_num) => {
-                                let r = self.get_var_binding(var_num);
-
-                                if !r.is_perm() && r.reg_num() == 0 {
-                                    self.in_use.insert(c_idx + 1);
-                                    self.shallow_temp_mappings.insert(c_idx + 1, var_num);
-                                    self.var_data.records[var_num]
-                                        .allocation
-                                        .set_register(c_idx + 1);
-                                }
-                            }
-                            VarPtr::Anon => {}
-                        }
-                    }
+                if !r.is_perm() && r.reg_num() == 0 {
+                    self.in_use.insert(idx + 1);
+                    self.shallow_temp_mappings.insert(idx + 1, var_num);
+                    self.var_data.records[var_num]
+                        .allocation
+                        .set_register(idx + 1);
                 }
             }
-            _ => {
-                self.reset_arg(0);
-            }
-        );
+        }
     }
 
     fn reset_arg(&mut self, arity: usize) {
index 6e9608df1e5cfda5110a264b0347f5c406cb24af..21a5cc91ba40199870273be03174dda12ed374ec 100644 (file)
@@ -3,8 +3,7 @@ use crate::atom_table::*;
 use crate::functor_macro::*;
 use crate::instructions::*;
 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::*;
@@ -18,6 +17,7 @@ use fxhash::FxBuildHasher;
 use indexmap::{IndexMap, IndexSet};
 use ordered_float::OrderedFloat;
 
+use std::cell::Cell;
 use std::collections::VecDeque;
 use std::convert::TryFrom;
 use std::fmt;
@@ -55,6 +55,15 @@ pub enum Level {
     Shallow,
 }
 
+impl Level {
+    pub(crate) fn child_level(self) -> Level {
+        match self {
+            Level::Root => Level::Shallow,
+            _ => Level::Deep,
+        }
+    }
+}
+
 #[derive(Debug, Clone, Copy)]
 pub enum CallPolicy {
     Default,
@@ -77,15 +86,6 @@ impl GenContext {
         }
     }
 
-    #[inline]
-    pub fn chunk_type(&self) -> ChunkType {
-        match self {
-            GenContext::Head => ChunkType::Head,
-            GenContext::Mid(_) => ChunkType::Mid,
-            GenContext::Last(_) => ChunkType::Last,
-        }
-    }
-
     #[inline]
     pub fn is_last(self) -> bool {
         matches!(self, GenContext::Last(_))
@@ -99,6 +99,19 @@ pub enum ChunkType {
     Last,
 }
 
+#[derive(Debug)]
+pub enum RootIterationPolicy {
+    Iterated,
+    NotIterated,
+}
+
+impl RootIterationPolicy {
+    #[inline(always)]
+    pub fn iterable(&self) -> bool {
+        matches!(self, RootIterationPolicy::Iterated)
+    }
+}
+
 impl ChunkType {
     #[inline(always)]
     pub fn to_gen_context(self, chunk_num: usize) -> GenContext {
@@ -118,17 +131,12 @@ impl ChunkType {
 #[derive(Debug)]
 pub enum ChunkedTerms {
     Branch(Vec<VecDeque<ChunkedTerms>>),
-    Chunk {
-        chunk_num: usize,
-        terms: VecDeque<QueryTerm>,
-    },
+    Chunk { terms: VecDeque<QueryTerm> },
 }
 
 #[derive(Debug)]
 pub struct ChunkedTermVec {
     pub chunk_vec: VecDeque<ChunkedTerms>,
-    pub current_chunk_num: usize,
-    pub current_chunk_type: ChunkType,
 }
 
 impl Deref for ChunkedTermVec {
@@ -153,8 +161,6 @@ impl ChunkedTermVec {
     pub fn new() -> Self {
         Self {
             chunk_vec: VecDeque::new(),
-            current_chunk_num: 0,
-            current_chunk_type: ChunkType::Mid,
         }
     }
 
@@ -163,45 +169,18 @@ impl ChunkedTermVec {
             .push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
     }
 
-    pub fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
-        if self.current_chunk_type.is_last() {
-            self.current_chunk_type = ChunkType::Mid;
-            self.current_chunk_num += 1;
-            true
-        } else {
-            false
-        }
-    }
-
-    pub fn try_set_chunk_at_call_boundary(&mut self) -> bool {
-        if self.current_chunk_type.is_last() {
-            self.current_chunk_num += 1;
-            true
-        } else {
-            self.current_chunk_type = ChunkType::Last;
-            false
-        }
-    }
-
     #[inline]
     pub fn add_chunk(&mut self) {
         let chunk = ChunkedTerms::Chunk {
-            chunk_num: self.current_chunk_num,
             terms: VecDeque::from(vec![]),
         };
         self.chunk_vec.push_back(chunk);
     }
 
-    pub fn current_gen_context(&self) -> GenContext {
-        self.current_chunk_type
-            .to_gen_context(self.current_chunk_num)
-    }
-
     pub fn push_chunk_term(&mut self, term: QueryTerm) {
         match self.chunk_vec.back_mut() {
             Some(ChunkedTerms::Branch(_)) => {
                 let chunk = ChunkedTerms::Chunk {
-                    chunk_num: self.current_chunk_num,
                     terms: VecDeque::from(vec![term]),
                 };
 
@@ -212,7 +191,6 @@ impl ChunkedTermVec {
             }
             None => {
                 let chunk = ChunkedTerms::Chunk {
-                    chunk_num: self.current_chunk_num,
                     terms: VecDeque::from(vec![term]),
                 };
 
@@ -222,39 +200,35 @@ impl ChunkedTermVec {
     }
 }
 
-#[derive(Debug)]
-pub struct QueryClause {
-    pub ct: ClauseType,
-    pub term: HeapCellValue,
-    pub code_indices: IndexMap<usize, CodeIndex, FxBuildHasher>,
-    pub call_policy: CallPolicy,
-}
-
-impl QueryClause {
-    pub fn term_loc(&self) -> usize {
-        self.term.get_value() as usize
-    }
-}
-
 #[derive(Debug)]
 pub enum QueryTerm {
-    Clause(QueryClause),
+    // register, clause type, subterms, clause call policy.
+    Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
     Fail,
-    Succeed,
-    LocalCut { var_num: usize, cut_prev: bool },
-    GlobalCut(usize), // var_num
+    LocalCut { var_num: usize, cut_prev: bool }, // var_num
+    GlobalCut(usize),                            // var_num
     GetCutPoint { var_num: usize, prev_b: bool },
     GetLevel(usize), // var_num
 }
 
-#[derive(Clone, Copy, Debug)]
+impl QueryTerm {
+    pub(crate) fn arity(&self) -> usize {
+        match self {
+            QueryTerm::Clause(_, _, subterms, ..) => subterms.len(),
+            &QueryTerm::GetLevel(_) | &QueryTerm::GetCutPoint { .. } => 1,
+            _ => 0,
+        }
+    }
+}
+
+#[derive(Debug)]
 pub struct Fact {
-    pub(crate) term_loc: usize,
+    pub(crate) head: Term,
 }
 
 #[derive(Debug)]
 pub struct Rule {
-    pub(crate) term_loc: usize,
+    pub(crate) head: (Atom, Vec<Term>),
     pub(crate) clauses: ChunkedTermVec,
 }
 
@@ -271,32 +245,90 @@ impl ListingSource {
     }
 }
 
-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))
+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,
         }
-        _ => {
-            if value.is_ref() {
-                clause_predicate_key(heap, value.get_value() as usize)
-            } else {
-                None
+    }
+
+    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
+    }
+}
+
+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),
+                }
             }
+            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,
         }
-    )
+    }
 }
 
-pub fn clause_predicate_key(heap: &impl SizedHeap, term_loc: usize) -> Option<PredicateKey> {
-    let key_opt = term_predicate_key(heap, term_loc);
+impl ClauseInfo for Rule {
+    fn name(&self) -> Option<Atom> {
+        Some(self.head.0)
+    }
 
-    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
+    fn arity(&self) -> usize {
+        self.head.1.len()
+    }
+}
+
+impl ClauseInfo for PredicateClause {
+    fn name(&self) -> Option<Atom> {
+        match self {
+            PredicateClause::Fact(ref term, ..) => term.head.name(),
+            PredicateClause::Rule(ref rule, ..) => rule.name(),
+        }
+    }
+
+    fn arity(&self) -> usize {
+        match self {
+            PredicateClause::Fact(ref term, ..) => term.head.arity(),
+            PredicateClause::Rule(ref rule, ..) => rule.arity(),
+        }
     }
 }
 
@@ -307,26 +339,20 @@ pub enum PredicateClause {
 }
 
 impl PredicateClause {
-    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 = clause_predicate_key(heap, focus)
-            .map(|(_name, arity)| arity)
-            .unwrap_or(0);
-
-        read_heap_cell!(heap_bound_store(heap, heap_bound_deref(heap, heap[focus])),
-            (HeapCellValueTag::Str, s) => {
-                Some(s+1 ..= s+arity)
-            }
-            _ => {
-                None
+    pub(crate) fn args(&self) -> Option<&[Term]> {
+        match self {
+            PredicateClause::Fact(term, ..) => match &term.head {
+                Term::Clause(_, _, args) => Some(args),
+                _ => None,
+            },
+            PredicateClause::Rule(rule, ..) => {
+                if rule.head.1.is_empty() {
+                    None
+                } else {
+                    Some(&rule.head.1)
+                }
             }
-        )
+        }
     }
 }
 
@@ -699,7 +725,7 @@ 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)
+        HeapCellValue::from(fixnum!(Literal, value as i64, arena))
     }
 }
 
@@ -779,10 +805,10 @@ impl Number {
     }
 }
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
 pub(crate) enum OptArgIndexKey {
-    Literal(usize, usize, HeapCellValue, Vec<HeapCellValue>), // index, IndexingCode location, opt arg, alternatives
-    List(usize, usize),                                       // index, IndexingCode location
+    Literal(usize, usize, Literal, Option<Literal>), // index, IndexingCode location, opt arg, alternatives
+    List(usize, usize),                              // index, IndexingCode location
     None,
     Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
 }
index 4f9032a7e384d524187496720e134cdd7c521fd4..ee69679fa4f51d3b45672090f951a3edbd28cb3a 100644 (file)
@@ -84,6 +84,15 @@ macro_rules! build_functor {
                         1 + $res_len,
                         [$($subfunctor),*])
     });
+    ([literal($e:expr) $(, $dt:ident($($value:tt),*))*],
+     [$($res:expr),*],
+     $res_len:expr,
+     [$($subfunctor:expr),*]) => ({
+         build_functor!([$($dt($($value),*)),*],
+                        [$($res, )* FunctorElement::AbsoluteCell(HeapCellValue::from($e))],
+                        1 + $res_len,
+                        [$($subfunctor),*])
+    });
     ([number($n:expr, $arena:expr) $(, $dt:ident($($value:tt),*))*],
      [$($res:expr),*],
      $res_len:expr,
index 2b0e44c12a62168e6c23139a0cea36cf79618db4..97489a6b6de130c417bd0bc45c0ee634520501a6 100644 (file)
@@ -34,7 +34,7 @@ pub struct EagerStackfulPreOrderHeapIter<'a> {
     start_value: HeapCellValue,
     iter_stack: Vec<HeapCellValue>,
     mark_phase: bool,
-    pub heap: &'a mut Heap,
+    heap: &'a mut Heap,
 }
 
 impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> {
@@ -253,7 +253,7 @@ impl<'a, ElideLists> Drop for StackfulPreOrderHeapIter<'a, ElideLists> {
     }
 }
 
-pub trait FocusedHeapIter: Deref<Target = Heap> + Iterator<Item = HeapCellValue> {
+pub trait FocusedHeapIter: Iterator<Item = HeapCellValue> {
     fn focus(&self) -> IterStackLoc;
 }
 
@@ -266,14 +266,6 @@ impl<'a, ElideLists: ListElisionPolicy> FocusedHeapIter
     }
 }
 
-impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> {
-    type Target = Heap;
-
-    fn deref(&self) -> &Self::Target {
-        &self.heap
-    }
-}
-
 impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
     #[inline]
     pub fn read_cell_mut(&mut self, loc: IterStackLoc) -> &mut HeapCellValue {
@@ -352,7 +344,6 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
     #[inline]
     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);
 
         Self {
             heap,
@@ -539,7 +530,7 @@ pub(crate) struct PostOrderIterator<Iter: FocusedHeapIter> {
 }
 
 impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> {
-    type Target = Heap;
+    type Target = Iter;
 
     fn deref(&self) -> &Self::Target {
         &self.base_iter
@@ -611,34 +602,10 @@ impl<Iter: FocusedHeapIter> FocusedHeapIter for PostOrderIterator<Iter> {
     }
 }
 
-/*
-impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
-    /* return true if the term at heap offset idx_loc is a
-     * direct/inlined subterm of a structure at the focus of
-     * self.stack.last(). this function is used to determine, e.g.,
-     * ownership of inlined code indices.
-     */
-    #[inline]
-    pub(crate) fn direct_subterm_of_str(&self, idx_loc: usize) -> bool {
-        if let Some((_child_count, item, focus)) = self.parent_stack.last() {
-            read_heap_cell!(item,
-                (HeapCellValueTag::Atom, (_name, arity)) => {
-                    let focus = focus.value() as usize;
-                    return focus + arity >= idx_loc && focus < idx_loc;
-                }
-                _ => {}
-            );
-        }
-
-        false
-    }
-}
-*/
-
 pub(crate) type LeftistPostOrderHeapIter<'a, ElideLists> =
     PostOrderIterator<StackfulPreOrderHeapIter<'a, ElideLists>>;
 
-impl<'a, ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'a, ElideLists> {
+impl<ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'_, ElideLists> {
     #[inline]
     pub fn pop_stack(&mut self) {
         if let Some((child_count, ..)) = self.parent_stack.last() {
@@ -870,7 +837,7 @@ mod tests {
         // two-part complete string, then a three-part cyclic string
         // involving an uncompacted list of chars.
 
-        wam.machine_st.allocate_pstr("abc ").unwrap();
+        wam.machine_st.heap.allocate_pstr("abc ").unwrap();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
         wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -891,7 +858,7 @@ mod tests {
 
         wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
 
-        wam.machine_st.allocate_pstr("def").unwrap();
+        wam.machine_st.heap.allocate_pstr("def").unwrap();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
         wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -1795,12 +1762,12 @@ mod tests {
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                1,
+                0,
             );
 
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                heap_loc_as_cell!(0)
+                heap_loc_as_cell!(1)
             );
 
             assert_eq!(iter.next(), None);
@@ -1857,7 +1824,7 @@ mod tests {
             let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                0,
+                4,
             );
 
             // the cycle will be iterated twice before being detected.
@@ -1879,15 +1846,7 @@ mod tests {
             );
             assert_eq!(
                 unmark_cell_bits!(iter.next().unwrap()),
-                list_loc_as_cell!(1)
-            );
-            assert_eq!(
-                unmark_cell_bits!(iter.next().unwrap()),
-                atom_as_cell!(a_atom)
-            );
-            assert_eq!(
-                unmark_cell_bits!(iter.next().unwrap()),
-                list_loc_as_cell!(3)
+                heap_loc_as_cell!(0)
             );
 
             assert_eq!(iter.next(), None);
@@ -1928,7 +1887,7 @@ mod tests {
         // two-part complete string, then a three-part cyclic string
         // involving an uncompacted list of chars.
 
-        wam.machine_st.allocate_pstr("abc ").unwrap();
+        wam.machine_st.heap.allocate_pstr("abc ").unwrap();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
         wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -1952,7 +1911,7 @@ mod tests {
         }
 
         wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
-        wam.machine_st.allocate_pstr("def").unwrap();
+        wam.machine_st.heap.allocate_pstr("def").unwrap();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
         wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -2208,14 +2167,17 @@ mod tests {
             section.push_cell(pstr_loc_as_cell!(0));
         });
 
+        assert_eq!(wam.machine_st.heap.cell_len(), 4);
+
         {
             let mut iter = stackful_preorder_iter::<NonListElider>(
                 &mut wam.machine_st.heap,
                 &mut wam.machine_st.stack,
-                2,
+                3,
             );
 
             assert_eq!(iter.heap.slice_to_str(0, "a string".len()), "a string");
+            assert_eq!(iter.next().unwrap(), pstr_loc_as_cell!(0));
             assert_eq!(iter.next().unwrap(), empty_list_as_cell!());
             assert_eq!(iter.next(), None);
         }
@@ -2528,7 +2490,7 @@ mod tests {
         // two-part complete string, then a three-part cyclic string
         // involving an uncompacted list of chars.
 
-        wam.machine_st.allocate_pstr("abc ").unwrap();
+        wam.machine_st.heap.allocate_pstr("abc ").unwrap();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
         wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -2552,7 +2514,7 @@ mod tests {
         }
 
         wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
-        wam.machine_st.allocate_pstr("def").unwrap();
+        wam.machine_st.heap.allocate_pstr("def").unwrap();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
         wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -2993,7 +2955,7 @@ mod tests {
         // two-part complete string, then a three-part cyclic string
         // involving an uncompacted list of chars.
 
-        wam.machine_st.allocate_pstr("abc ").unwrap();
+        wam.machine_st.heap.allocate_pstr("abc ").unwrap();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
         wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -3016,7 +2978,7 @@ mod tests {
         wam.machine_st.heap[2] = heap_loc_as_cell!(2);
         assert_eq!(wam.machine_st.heap.cell_len(), 3);
 
-        wam.machine_st.allocate_pstr("def").unwrap();
+        wam.machine_st.heap.allocate_pstr("def").unwrap();
         assert_eq!(wam.machine_st.heap.cell_len(), 4);
 
         wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
index cdd166c87ce184d6f35e595a12d3771279838a9e..8c39b41e72a6e6d8d2388af57f8ad027ebd3346a 100644 (file)
@@ -477,7 +477,7 @@ pub struct HCPrinter<'a, Outputter> {
     toplevel_spec: Option<DirectedOp>,
     last_item_idx: usize,
     parent_of_first_op: Option<(DirectedOp, usize)>,
-    pub var_names: IndexMap<HeapCellValue, Var>,
+    pub var_names: IndexMap<HeapCellValue, VarPtr>,
     pub numbervars_offset: Integer,
     pub numbervars: bool,
     pub quoted: bool,
@@ -544,11 +544,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         stack: &'a mut Stack,
         op_dir: &'a OpDir,
         output: Outputter,
-        root_loc: usize,
+        term_loc: usize,
     ) -> Self {
         HCPrinter {
             outputter: output,
-            iter: stackful_preorder_iter(heap, stack, root_loc),
+            iter: stackful_preorder_iter(heap, stack, term_loc),
             op_dir,
             state_stack: vec![],
             toplevel_spec: None,
@@ -795,7 +795,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
         if let Some(var) = self.var_names.get(&cell) {
             read_heap_cell!(cell,
                (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
-                   return Some(var.to_string());
+                   return Some(var.borrow().to_string());
                }
                _ => {
                    self.iter.push_stack(h);
@@ -837,7 +837,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                         // short-circuits handle_heap_term.
                         // self.iter.pop_stack();
 
-                        let var_str = var.to_string();
+                        let var_str = var.borrow().to_string();
 
                         push_space_if_amb!(self, &var_str, {
                             append_str!(self, &var_str);
@@ -865,7 +865,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
                                 Some(var) => {
                                     // If the term is bound to a named variable,
                                     // print the variable's name to output.
-                                    let var_str = var.to_string();
+                                    let var_str = var.borrow().to_string();
 
                                     push_space_if_amb!(self, &var_str, {
                                         append_str!(self, &var_str);
@@ -1956,7 +1956,7 @@ mod tests {
 
             printer
                 .var_names
-                .insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
+                .insert(list_loc_as_cell!(1), VarPtr::from("L"));
 
             let output = printer.print();
 
@@ -2033,7 +2033,7 @@ mod tests {
 
             printer
                 .var_names
-                .insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
+                .insert(list_loc_as_cell!(1), VarPtr::from("L"));
 
             let output = printer.print();
 
@@ -2078,7 +2078,7 @@ mod tests {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.allocate_pstr("abc").unwrap();
+        wam.machine_st.heap.allocate_pstr("abc").unwrap();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
         wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
index 344155d83a319a087e503c806690d562a5dc41c4..b9bdfc2814fbdd0ebc79fe64e04b3ef63c64a510 100644 (file)
@@ -1,9 +1,9 @@
 use crate::atom_table::*;
+use crate::parser::ast::*;
+
 use crate::forms::*;
 use crate::instructions::*;
-use crate::machine::heap::*;
-use crate::parser::ast::Fixnum;
-use crate::types::*;
+use crate::types::HeapCellValue;
 
 use fxhash::FxBuildHasher;
 use indexmap::IndexMap;
@@ -113,7 +113,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
 
         match constant_key {
             Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
-                constants.insert(*constant, constant_ptr);
+                constants.insert(HeapCellValue::from(*constant), constant_ptr);
             }
             _ if constant_ptr.is_external() => {
                 // this must be a defunct clause, because it's been deleted
@@ -634,12 +634,15 @@ pub(crate) fn merge_clause_index(
     match &opt_arg_index_key {
         OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => {
             let offset = new_clause_loc - index_loc + 1;
-            merging_ptr.index_constant(*constant, offset);
+            merging_ptr.index_constant(HeapCellValue::from(*constant), offset);
 
-            for overlapping_constant in overlapping_constants {
+            if let Some(overlapping_constant) = overlapping_constants {
                 merging_ptr.offset = 0;
-
-                merging_ptr.index_overlapping_constant(*constant, *overlapping_constant, offset);
+                merging_ptr.index_overlapping_constant(
+                    HeapCellValue::from(*constant),
+                    HeapCellValue::from(*overlapping_constant),
+                    offset,
+                );
             }
         }
         OptArgIndexKey::Structure(_, index_loc, name, arity) => {
@@ -664,8 +667,8 @@ pub(crate) fn merge_clause_index(
 }
 
 pub(crate) fn remove_constant_indices(
-    constant: HeapCellValue,
-    overlapping_constants: &[HeapCellValue],
+    constant: Literal,
+    overlapping_constants: Option<Literal>,
     indexing_code: &mut [IndexingLine],
     offset: usize,
 ) {
@@ -694,7 +697,7 @@ pub(crate) fn remove_constant_indices(
 
     let mut constants_index = 0;
 
-    for constant in iter {
+    for constant in iter.map(|l| HeapCellValue::from(*l)) {
         loop {
             match &mut indexing_code[index] {
                 IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
@@ -702,8 +705,6 @@ pub(crate) fn remove_constant_indices(
                 )) => {
                     constants_index = index;
 
-                    let constant = *constant;
-
                     match constants.get(&constant).cloned() {
                         Some(IndexingCodePtr::DynamicExternal(_))
                         | Some(IndexingCodePtr::External(_))
@@ -741,7 +742,7 @@ pub(crate) fn remove_constant_indices(
                                 IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
                                     ref mut constants,
                                 )) => {
-                                    constants.insert(*constant, ext);
+                                    constants.insert(constant, ext);
                                 }
                                 _ => {
                                     unreachable!()
@@ -774,7 +775,7 @@ pub(crate) fn remove_constant_indices(
                                 IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
                                     ref mut constants,
                                 )) => {
-                                    constants.insert(*constant, ext);
+                                    constants.insert(constant, ext);
                                 }
                                 _ => {
                                     unreachable!()
@@ -1034,7 +1035,7 @@ pub(crate) fn remove_index(
 ) {
     match opt_arg_index_key {
         OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => {
-            remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc);
+            remove_constant_indices(*constant, *overlapping_constants, indexing_code, clause_loc);
         }
         OptArgIndexKey::Structure(_, _, name, arity) => {
             remove_structure_index(*name, *arity, indexing_code, clause_loc);
@@ -1096,60 +1097,18 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
     }
 }
 
-pub(crate) fn constant_key_alternatives(
-    constant: HeapCellValue,
-    // atom_tbl: &AtomTable,
-    // arena: &mut Arena,
-) -> 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(),
-                );
-            }
-        }
-        _ => {}
-    }
+pub(crate) fn constant_key_alternatives(constant: Literal) -> Option<Literal> {
+    let n = match &constant {
+        Literal::Rational(n) if n.denominator().is_one() => n.numerator(),
+        Literal::Integer(n) => n,
+        _ => return None,
+    };
 
-    /*
-    match constant {
-        Literal::Atom(ref name) => {
-            if let Some(c) = name.as_char() {
-                constants.push(Literal::Char(c));
-            }
-        }
-        Literal::Char(c) => {
-            let atom = AtomTable::build_with(atom_tbl, &c.to_string());
-            constants.push(Literal::Atom(atom));
-        }
-        /*
-        // constant_to_literal takes care of the downward conversion from Integer to Fixnum
-        // if possible.
-        Literal::Fixnum(ref n) => {
-            constants.push(Literal::Integer(arena_alloc!(n, arena)));
-        }
-        */
-        Literal::Integer(ref n) => {
-            let result = (&**n).try_into();
-            if let Ok(value) = result {
-                Fixnum::build_with_checked(value)
-                    .map(|n| {
-                        constants.push(Literal::Fixnum(n));
-                    })
-                    .unwrap();
-            }
-        }
-        _ => {}
+    if let Ok(n) = n.try_into() {
+        Fixnum::build_with_checked(n).map(Literal::Fixnum).ok()
+    } else {
+        None
     }
-    */
-
-    constants
 }
 
 #[derive(Debug)]
@@ -1464,9 +1423,13 @@ impl<I: Indexer> CodeOffsets<I> {
         self.indices.lists().push_back(index);
     }
 
-    fn index_constant(&mut self, constant: HeapCellValue, index: usize) -> Vec<HeapCellValue> {
-        let overlapping_constants = constant_key_alternatives(constant);
-        let code = self.indices.constants().entry(constant).or_default();
+    fn index_constant(&mut self, constant: Literal, index: usize) -> Option<Literal> {
+        let overlapping_constant_opt = constant_key_alternatives(constant);
+        let code = self
+            .indices
+            .constants()
+            .entry(HeapCellValue::from(constant))
+            .or_default();
 
         let is_initial_index = code.is_empty();
         code.push_back(I::compute_index(
@@ -1475,8 +1438,8 @@ impl<I: Indexer> CodeOffsets<I> {
             self.non_counted_bt,
         ));
 
-        for constant in &overlapping_constants {
-            let code = self.indices.constants().entry(*constant).or_default();
+        if let Some(constant) = overlapping_constant_opt.map(HeapCellValue::from) {
+            let code = self.indices.constants().entry(constant).or_default();
 
             let is_initial_index = code.is_empty();
             let index = I::compute_index(is_initial_index, index, self.non_counted_bt);
@@ -1484,7 +1447,7 @@ impl<I: Indexer> CodeOffsets<I> {
             code.push_back(index);
         }
 
-        overlapping_constants
+        overlapping_constant_opt
     }
 
     fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
@@ -1503,55 +1466,33 @@ impl<I: Indexer> CodeOffsets<I> {
 
     pub(crate) fn index_term(
         &mut self,
-        heap: &Heap,
-        optimal_arg: HeapCellValue,
+        optimal_arg: &Term,
         index: usize,
         clause_index_info: &mut ClauseIndexInfo,
     ) {
-        read_heap_cell!(optimal_arg,
-            (HeapCellValueTag::Str, s) => {
-                let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
-
-                if (name, arity) == (atom!("."), 2) {
-                    clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
-                    self.index_list(index);
-                } else {
-                    clause_index_info.opt_arg_index_key =
-                        OptArgIndexKey::Structure(self.optimal_index, 0, name, arity);
-
-                    self.index_structure(name, arity, index);
-                }
-            }
-            (HeapCellValueTag::Atom, (name, arity)) => {
-                debug_assert_eq!(arity, 0);
-
-                let overlapping_constants = self.index_constant(atom_as_cell!(name), index);
-
-                clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
-                    self.optimal_index,
-                    0,
-                    atom_as_cell!(name),
-                    overlapping_constants,
-                );
+        match optimal_arg {
+            &Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
+                clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
+                self.index_list(index);
             }
-            (HeapCellValueTag::Lis
-             // | HeapCellValueTag::CStr
-             | HeapCellValueTag::PStrLoc) => {
+            &Term::Cons(..) | &Term::PartialString(..) | &Term::CompleteString(..) => {
                 clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
                 self.index_list(index);
             }
-            _ 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,
-                );
+            &Term::Clause(_, name, ref terms) => {
+                clause_index_info.opt_arg_index_key =
+                    OptArgIndexKey::Structure(self.optimal_index, 0, name, terms.len());
+
+                self.index_structure(name, terms.len(), index);
+            }
+            &Term::Literal(_, constant) => {
+                let overlapping_constants = self.index_constant(constant, index);
+
+                clause_index_info.opt_arg_index_key =
+                    OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
             }
             _ => {}
-        );
+        }
     }
 
     pub(crate) fn no_indices(&mut self) -> bool {
index 1de7541b1f4eddb483c5abd3a36c18ed6c6e53f0..5bd51d9949f39bd91bcca38366b71419bcc5850e 100644 (file)
-use crate::atom_table::AtomCell;
+use crate::atom_table::*;
 use crate::forms::*;
-use crate::heap_iter::*;
-use crate::machine::heap::*;
-use crate::machine::stack::*;
-use crate::types::*;
-
-use bit_set::*;
-use fxhash::FxBuildHasher;
-use indexmap::IndexMap;
+use crate::instructions::*;
+use crate::parser::ast::*;
 
+use std::cell::Cell;
 use std::collections::VecDeque;
 use std::iter::*;
-use std::ops::Deref;
+use std::rc::Rc;
 use std::vec::Vec;
 
-pub(crate) trait TermIterator:
-    Deref<Target = Heap> + Iterator<Item = HeapCellValue>
-{
-    fn focus(&self) -> IterStackLoc;
-    fn level(&mut self) -> Level;
+#[allow(clippy::borrowed_box)]
+#[derive(Debug, Clone)]
+pub(crate) enum TermRef<'a> {
+    AnonVar(Level),
+    Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
+    Literal(Level, &'a Cell<RegType>, &'a Literal),
+    Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
+    PartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
+    CompleteString(Level, &'a Cell<RegType>, Rc<String>),
+    Var(Level, &'a Cell<VarReg>, VarPtr),
 }
 
+#[allow(clippy::borrowed_box)]
 #[derive(Debug)]
-pub(crate) struct TargetIterator<I: FocusedHeapIter, const SKIP_ROOT: bool> {
-    shallow_terms: IndexMap<usize, BitSet<usize>, FxBuildHasher>,
-    root_terms: BitSet<usize>,
-    iter: I,
-    arg_c: usize,
+pub(crate) enum TermIterState<'a> {
+    AnonVar(Level),
+    Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
+    Literal(Level, &'a Cell<RegType>, &'a Literal),
+    InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
+    FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
+    InitialPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
+    FinalPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
+    CompleteString(Level, &'a Cell<RegType>, Rc<String>),
+    Var(Level, &'a Cell<VarReg>, VarPtr),
 }
 
-fn record_path(
-    heap: &impl SizedHeap,
-    root_terms: &mut BitSet<usize>,
-    mut root_loc: usize,
-) -> usize {
-    loop {
-        let cell = heap[root_loc];
-        root_terms.insert(root_loc);
-
-        read_heap_cell!(cell,
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                if h == root_loc {
-                    break;
-                } else {
-                    root_loc = h;
-                }
+impl<'a> TermIterState<'a> {
+    pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
+        match term {
+            Term::AnonVar => TermIterState::AnonVar(lvl),
+            Term::Clause(cell, name, subterms) => {
+                TermIterState::Clause(lvl, 0, cell, *name, subterms)
             }
-            (HeapCellValueTag::Lis) => {
-                root_terms.insert(root_loc);
-                break;
+            Term::Cons(cell, head, tail) => {
+                TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
             }
-            _ => {
-                if cell.is_ref() {
-                    root_terms.insert(cell.get_value() as usize);
-                }
-
-                break;
+            Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
+            Term::PartialString(cell, string_buf, tail) => {
+                TermIterState::InitialPartialString(lvl, cell, string_buf.clone(), tail)
+            }
+            Term::CompleteString(cell, string) => {
+                TermIterState::CompleteString(lvl, cell, string.clone())
             }
-        );
+            Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
+        }
     }
-
-    root_loc
 }
 
-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)
+#[derive(Debug)]
+pub(crate) struct QueryIterator<'a> {
+    state_stack: Vec<TermIterState<'a>>,
 }
 
-fn find_shallow_terms(
-    heap: &impl SizedHeap,
-    root_loc: usize,
-) -> IndexMap<usize, BitSet<usize>, FxBuildHasher> {
-    let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default());
-
-    let (h, arity) = read_heap_cell!(heap[root_loc],
-        (HeapCellValueTag::Str, s) => {
-            (s+1, cell_as_atom_cell!(heap[s]).get_arity())
-        }
-        (HeapCellValueTag::Lis, l) => {
-            (l, 2)
-        }
-        (HeapCellValueTag::Atom, (_name, arity)) => {
-            (root_loc + 1, arity)
-        }
-        _ => {
-            (root_loc, 0)
-        }
-    );
-
-    for idx in 0..arity {
-        let mut shallow_terms = BitSet::default();
-        record_path(heap, &mut shallow_terms, h + idx);
-        shallow_terms_map.insert(idx + 1, shallow_terms);
+impl<'a> QueryIterator<'a> {
+    fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
+        self.state_stack
+            .push(TermIterState::subterm_to_state(lvl, term));
     }
 
-    shallow_terms_map
-}
-
-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.deref(), root_loc);
-        let shallow_terms = find_shallow_terms(iter.deref(), derefed_root_loc);
+    /*
+    fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
+        let state_stack = terms
+            .iter()
+            .rev()
+            .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
+            .collect();
 
-        Self {
-            shallow_terms,
-            root_terms,
-            iter,
-            arg_c,
-        }
+        QueryIterator { state_stack }
     }
+    */
+
+    fn from_term(term: &'a Term) -> Self {
+        let state = match term {
+            Term::AnonVar
+            | Term::Cons(..)
+            | Term::Literal(..)
+            | Term::PartialString(..)
+            | Term::CompleteString(..) => {
+                return QueryIterator {
+                    state_stack: vec![],
+                }
+            }
+            Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms),
+            Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
+        };
 
-    fn current_level(&self, arg_c_inc: usize) -> Level {
-        let current_focus = self.iter.focus().value() as usize;
-
-        if self.root_terms.contains(current_focus) {
-            return Level::Root;
+        QueryIterator {
+            state_stack: vec![state],
         }
+    }
 
-        if let Some(shallow_terms) = self.shallow_terms.get(&(self.arg_c + arg_c_inc)) {
-            if shallow_terms.contains(current_focus) {
-                return Level::Shallow;
+    fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) {
+        match term {
+            QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
+                self.state_stack
+                    .push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms));
+            }
+            QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
+                self.state_stack
+                    .push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
             }
+            _ => {}
         }
+    }
 
-        Level::Deep
+    pub fn new(term: &'a QueryTerm) -> Self {
+        let mut iter = QueryIterator {
+            state_stack: vec![],
+        };
+        iter.extend_state(Level::Root, term);
+        iter
     }
 }
 
-impl<'a, const SKIP_ROOT: bool> TermIterator for FactIterator<'a, SKIP_ROOT> {
-    fn focus(&self) -> IterStackLoc {
-        self.iter.focus()
-    }
+impl<'a> Iterator for QueryIterator<'a> {
+    type Item = TermRef<'a>;
 
-    fn level(&mut self) -> Level {
-        let lvl = self.current_level(1);
+    fn next(&mut self) -> Option<Self::Item> {
+        while let Some(iter_state) = self.state_stack.pop() {
+            match iter_state {
+                TermIterState::AnonVar(lvl) => {
+                    return Some(TermRef::AnonVar(lvl));
+                }
+                TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
+                    if child_num == child_terms.len() {
+                        match name {
+                            atom!("$call") if lvl == Level::Root => {
+                                self.push_subterm(Level::Shallow, &child_terms[0]);
+                            }
+                            _ => {
+                                return match lvl {
+                                    Level::Root => None,
+                                    lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
+                                }
+                            }
+                        };
+                    } else {
+                        self.state_stack.push(TermIterState::Clause(
+                            lvl,
+                            child_num + 1,
+                            cell,
+                            name,
+                            child_terms,
+                        ));
+
+                        self.push_subterm(lvl.child_level(), &child_terms[child_num]);
+                    }
+                }
+                TermIterState::InitialCons(lvl, cell, head, tail) => {
+                    self.state_stack
+                        .push(TermIterState::FinalCons(lvl, cell, head, tail));
 
-        if let Level::Shallow = lvl {
-            self.arg_c += 1;
+                    self.push_subterm(lvl.child_level(), tail);
+                    self.push_subterm(lvl.child_level(), head);
+                }
+                TermIterState::InitialPartialString(lvl, cell, string, tail) => {
+                    self.state_stack
+                        .push(TermIterState::FinalPartialString(lvl, cell, string, tail));
+                    self.push_subterm(lvl.child_level(), tail);
+                }
+                TermIterState::FinalPartialString(lvl, cell, string, tail) => {
+                    return Some(TermRef::PartialString(lvl, cell, string, tail));
+                }
+                TermIterState::CompleteString(lvl, cell, string) => {
+                    return Some(TermRef::CompleteString(lvl, cell, string));
+                }
+                TermIterState::FinalCons(lvl, cell, head, tail) => {
+                    return Some(TermRef::Cons(lvl, cell, head, tail));
+                }
+                TermIterState::Literal(lvl, cell, constant) => {
+                    return Some(TermRef::Literal(lvl, cell, constant));
+                }
+                TermIterState::Var(lvl, cell, var_ptr) => {
+                    return Some(TermRef::Var(lvl, cell, var_ptr));
+                }
+            };
         }
 
-        lvl
+        None
     }
 }
 
-impl<'a, const SKIP_ROOT: bool> TermIterator for QueryIterator<'a, SKIP_ROOT> {
-    fn focus(&self) -> IterStackLoc {
-        self.iter.focus()
+#[derive(Debug)]
+pub(crate) struct FactIterator<'a> {
+    state_queue: VecDeque<TermIterState<'a>>,
+    iterable_root: RootIterationPolicy,
+}
+
+impl<'a> FactIterator<'a> {
+    fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
+        self.state_queue
+            .push_back(TermIterState::subterm_to_state(lvl, term));
     }
 
-    fn level(&mut self) -> Level {
-        let lvl = self.current_level(0);
+    pub(crate) fn from_rule_head_clause(terms: &'a [Term]) -> Self {
+        let state_queue = terms
+            .iter()
+            .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
+            .collect();
 
-        if let Level::Shallow = lvl {
-            self.arg_c += 1;
+        FactIterator {
+            state_queue,
+            iterable_root: RootIterationPolicy::NotIterated,
         }
+    }
 
-        lvl
+    fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self {
+        let states = match term {
+            Term::AnonVar => {
+                vec![TermIterState::AnonVar(Level::Root)]
+            }
+            Term::Clause(cell, name, terms) => {
+                vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
+            }
+            Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
+                Level::Root,
+                cell,
+                head.as_ref(),
+                tail.as_ref(),
+            )],
+            Term::PartialString(cell, string, tail) => {
+                vec![TermIterState::InitialPartialString(
+                    Level::Root,
+                    cell,
+                    string.clone(),
+                    tail,
+                )]
+            }
+            Term::CompleteString(cell, string) => {
+                vec![TermIterState::CompleteString(
+                    Level::Root,
+                    cell,
+                    string.clone(),
+                )]
+            }
+            Term::Literal(cell, constant) => {
+                vec![TermIterState::Literal(Level::Root, cell, constant)]
+            }
+            Term::Var(cell, var_ptr) => {
+                vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())]
+            }
+        };
+
+        FactIterator {
+            state_queue: VecDeque::from(states),
+            iterable_root,
+        }
     }
 }
 
-impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Iterator for TargetIterator<I, SKIP_ROOT> {
-    type Item = HeapCellValue;
+impl<'a> Iterator for FactIterator<'a> {
+    type Item = TermRef<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
-        loop {
-            let next_term = self.iter.next();
-
-            if next_term.is_none() {
-                return None;
-            }
+        while let Some(state) = self.state_queue.pop_front() {
+            match state {
+                TermIterState::AnonVar(lvl) => {
+                    return Some(TermRef::AnonVar(lvl));
+                }
+                TermIterState::Clause(lvl, _, cell, name, child_terms) => {
+                    for child_term in child_terms {
+                        self.push_subterm(lvl.child_level(), child_term);
+                    }
 
-            let focus = self.iter.focus().value() as usize;
+                    match lvl {
+                        Level::Root if !self.iterable_root.iterable() => continue,
+                        _ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
+                    };
+                }
+                TermIterState::InitialCons(lvl, cell, head, tail) => {
+                    self.push_subterm(Level::Deep, head);
+                    self.push_subterm(Level::Deep, tail);
 
-            if SKIP_ROOT && self.root_terms.contains(focus) {
-                continue;
-            } else {
-                return next_term;
+                    return Some(TermRef::Cons(lvl, cell, head, tail));
+                }
+                TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => {
+                    self.push_subterm(Level::Deep, tail);
+                    return Some(TermRef::PartialString(lvl, cell, string_buf, tail));
+                }
+                TermIterState::CompleteString(lvl, cell, atom) => {
+                    return Some(TermRef::CompleteString(lvl, cell, atom));
+                }
+                TermIterState::Literal(lvl, cell, constant) => {
+                    return Some(TermRef::Literal(lvl, cell, constant))
+                }
+                TermIterState::Var(lvl, cell, var_ptr) => {
+                    return Some(TermRef::Var(lvl, cell, var_ptr));
+                }
+                _ => {}
             }
         }
-    }
-}
-
-impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Deref for TargetIterator<I, SKIP_ROOT> {
-    type Target = Heap;
 
-    fn deref(&self) -> &Self::Target {
-        self.iter.deref()
-    }
-}
-
-impl<I: FocusedHeapIter, const SKIP_ROOT: bool> FocusedHeapIter for TargetIterator<I, SKIP_ROOT> {
-    fn focus(&self) -> IterStackLoc {
-        self.iter.focus()
+        None
     }
 }
 
-pub(crate) type FactIterator<'a, const SKIP_ROOT: bool> =
-    TargetIterator<StackfulPreOrderHeapIter<'a, NonListElider>, SKIP_ROOT>;
-
-pub(crate) fn fact_iterator<'a, const SKIP_ROOT: bool>(
-    heap: &'a mut Heap,
-    stack: &'a mut Stack,
-    root_loc: usize,
-) -> FactIterator<'a, SKIP_ROOT> {
-    TargetIterator::new(stackful_preorder_iter(heap, stack, root_loc), root_loc, 0)
+pub(crate) fn post_order_iter(term: &'_ Term) -> QueryIterator {
+    QueryIterator::from_term(term)
 }
 
-pub(crate) type QueryIterator<'a, const SKIP_ROOT: bool> =
-    TargetIterator<PostOrderIterator<StackfulPreOrderHeapIter<'a, NonListElider>>, SKIP_ROOT>;
-
-pub(crate) fn query_iterator<'a, const SKIP_ROOT: bool>(
-    heap: &'a mut Heap,
-    stack: &'a mut Stack,
-    root_loc: usize,
-) -> QueryIterator<'a, SKIP_ROOT> {
-    TargetIterator::new(stackful_post_order_iter(heap, stack, root_loc), root_loc, 1)
+pub(crate) fn breadth_first_iter(
+    term: &'_ Term,
+    iterable_root: RootIterationPolicy,
+) -> FactIterator {
+    FactIterator::new(term, iterable_root)
 }
 
 #[derive(Debug, Copy, Clone)]
@@ -230,10 +327,7 @@ pub(crate) enum ClauseItem<'a> {
     FirstBranch(usize),
     NextBranch,
     BranchEnd(usize),
-    Chunk {
-        chunk_num: usize,
-        terms: &'a VecDeque<QueryTerm>,
-    },
+    Chunk { terms: &'a VecDeque<QueryTerm> },
 }
 
 #[derive(Debug)]
@@ -309,11 +403,8 @@ impl<'a> Iterator for ClauseIterator<'a> {
                             self.state_stack
                                 .push(ClauseIteratorState::RemainingBranches(branches, 0));
                         }
-                        &ChunkedTerms::Chunk {
-                            chunk_num,
-                            ref terms,
-                        } => {
-                            return Some(ClauseItem::Chunk { chunk_num, terms });
+                        &ChunkedTerms::Chunk { ref terms } => {
+                            return Some(ClauseItem::Chunk { terms });
                         }
                     }
                 }
index 6d18b447cf0261dc9ee0a8625b332bb479cddc1c..f251b57d9d4228c3e8169c7fd712eefe0ec67069 100644 (file)
@@ -59,7 +59,7 @@ get_attrs_var_check(Module) -->
                              !,
                              '$get_attr_list'(Var, Ls),
                              nonvar(Ls),
-                            atts:'$copy_attr_list'(Ls, Module, Attr))].
+                                        atts:'$copy_attr_list'(Ls, Module, Attr))].
 
 put_attrs(Name/Arity, Module) -->
     put_attr(Name, Arity, Module),
index bc78b7113b41bc301514b18383e76660324a3de3..ca07e0c68598ac5cd1eaf3f33fc14ef433b05d38 100644 (file)
@@ -1175,8 +1175,14 @@ clause(H, B) :-
 % Asserts (inserts) a new clause (rule or fact) into the current module.
 % The clause will be inserted at the beginning of the module.
 asserta(Clause0) :-
-    loader:strip_subst_module(Clause0, user, Module, Clause),
-    '$asserta'(Module, Clause).
+    loader:strip_module(Clause0, Module, Clause),
+    asserta_(Module, Clause).
+
+asserta_(Module, (Head :- Body)) :-
+    !,
+    '$asserta'(Module, Head, Body).
+asserta_(Module, Fact) :-
+    '$asserta'(Module, Fact, true).
 
 :- meta_predicate assertz(:).
 
@@ -1185,8 +1191,14 @@ asserta(Clause0) :-
 % Asserts (inserts) a new clause (rule or fact) into the current module.
 % The clase will be inserted at the end of the module.
 assertz(Clause0) :-
-    loader:strip_subst_module(Clause0, user, Module, Clause),
-    '$assertz'(Module, Clause).
+    loader:strip_module(Clause0, Module, Clause),
+    assertz_(Module, Clause).
+
+assertz_(Module, (Head :- Body)) :-
+    !,
+    '$assertz'(Module, Head, Body).
+assertz_(Module, Fact) :-
+    '$assertz'(Module, Fact, true).
 
 
 :- meta_predicate retract(:).
index 90cc4d3ff902f86ef4142fb8bb96d2195c1a9963..0e29c190d0879b108406733ba45015175a2daf64 100644 (file)
@@ -126,3 +126,4 @@ when_condition_si((A, B)) :-
 when_condition_si((A ; B)) :-
     when_condition_si(A),
     when_condition_si(B).
+
index f2d77009f485e99eeddf97f2a48b447fd0d0356f..2a5e9fb84a209b9f0c29f8943e75f7ccab52000e 100644 (file)
@@ -177,6 +177,7 @@ print_comma_separated_list([VN=_, VNEq | VNEqs]) :-
 
 filter_anonymous_vars([], []).
 filter_anonymous_vars([VN=V | VNEqs0], VNEqs) :-
+    '$debug_hook',
     (  atom_concat('_', _, VN) ->
        filter_anonymous_vars(VNEqs0, VNEqs)
     ;  VNEqs = [VN=V | VNEqs1],
index 86470097d3e3440686950e8221c0c8e56e170f63..f7bd69eff253a69ec4c37d6cefd51fe0f035bba9 100644 (file)
@@ -1126,7 +1126,10 @@ impl MachineState {
 
                 match Number::try_from(value) {
                     Ok(n) => Ok(n),
-                    Err(_) => self.arith_eval_by_metacall(value),
+                    Err(_) => {
+                        self.heap[0] = value;
+                        self.arith_eval_by_metacall(0)
+                    }
                 }
             }
             &ArithmeticTerm::Interm(i) => Ok(mem::replace(
@@ -1152,21 +1155,11 @@ impl MachineState {
 
     pub(crate) fn arith_eval_by_metacall(
         &mut self,
-        value: HeapCellValue,
+        term_loc: usize,
     ) -> 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() {
-            value.get_value() as usize
-        } else {
-            let type_error = self.type_error(ValidType::Evaluable, value);
-            return Err(self.error_form(type_error, stub_gen()));
-        };
-
         let mut iter =
-            stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, root_loc);
+            stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term_loc);
 
         while let Some(value) = iter.next() {
             if value.get_forwarding_bit() {
@@ -1459,7 +1452,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.focus)),
+            wam.arith_eval_by_metacall(term_write_result.heap_loc),
             Ok(Number::Fixnum(Fixnum::build_with(8))),
         );
 
@@ -1469,7 +1462,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.focus)),
+            wam.arith_eval_by_metacall(term_write_result.heap_loc),
             Ok(Number::Fixnum(Fixnum::build_with(19))),
         );
 
@@ -1479,7 +1472,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.focus)),
+            wam.arith_eval_by_metacall(term_write_result.heap_loc),
             Ok(Number::Fixnum(Fixnum::build_with(-1)))
         );
     }
index 368152f5b2a64311e9b01752c732a0a608985f14..34e4755d7df560ca00f98c02e76ad362ca54e97f 100644 (file)
@@ -10,8 +10,8 @@ use std::cmp::Ordering;
 pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
 
 #[derive(Debug)]
-pub(crate) struct AttrVarInitializer {
-    pub(crate) attr_var_queue: Vec<usize>,
+pub(super) struct AttrVarInitializer {
+    pub(super) attr_var_queue: Vec<usize>,
     pub(super) bindings: Bindings,
     pub(super) p: usize,
     pub(super) cp: usize,
@@ -138,17 +138,10 @@ impl MachineState {
 
         let mut seen_set = IndexSet::new();
         let mut seen_vars = vec![];
-        let root_loc = if cell.is_ref() {
-            cell.get_value() as usize
-        } else {
-            return vec![];
-        };
 
-        let mut iter = stackful_preorder_iter::<NonListElider>(
-            &mut self.heap,
-            &mut self.stack,
-            root_loc, // cell,
-        );
+        self.heap[0] = cell;
+
+        let mut iter = stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
 
         while let Some(value) = iter.next() {
             read_heap_cell!(value,
index 84b89c3973ca198c8cf0844b55c1bdb04cf12bd6..4f0fb1b64bb324575781da7324d1bf211cc6cc01 100644 (file)
@@ -11,6 +11,7 @@ use crate::machine::term_stream::*;
 use crate::machine::*;
 use crate::parser::ast::*;
 
+use std::cell::Cell;
 use std::collections::VecDeque;
 use std::mem;
 use std::ops::Range;
@@ -1232,16 +1233,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 
     fn compile_standalone_clause(
         &mut self,
-        term: TermWriteResult,
+        term: Term,
         settings: CodeGenSettings,
     ) -> Result<StandaloneCompileResult, SessionError> {
         let mut preprocessor = Preprocessor::new(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(&mut machine_st.heap, vec![clause])?;
+        let mut cg = CodeGenerator::new(settings);
+        let clause_code = cg.compile_predicate(vec![clause])?;
 
         Ok(StandaloneCompileResult {
             clause_code,
@@ -1262,6 +1261,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         let code_len = self.wam_prelude.code.len();
         let mut code_ptr = code_len;
 
+        if key == (atom!("..."), 2) {
+            print!("");
+        }
+
         let mut clauses = vec![];
         let mut preprocessor = Preprocessor::new(settings);
 
@@ -1269,10 +1272,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             clauses.push(preprocessor.try_term_to_tl(self, term)?);
         }
 
-        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)?;
+        let mut code = cg.compile_predicate(clauses)?;
 
         if settings.is_extensible {
             let mut clause_clause_locs = VecDeque::new();
@@ -1469,7 +1470,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
     pub(super) fn incremental_compile_clause(
         &mut self,
         key: PredicateKey,
-        clause: TermWriteResult,
+        clause: Term,
         compilation_target: CompilationTarget,
         non_counted_bt: bool,
         append_or_prepend: AppendOrPrepend,
@@ -2004,13 +2005,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 }
 
 impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
-    pub(super) fn compile_clause_clauses(
+    pub(super) fn compile_clause_clauses<ClauseIter: Iterator<Item = (Term, Term)>>(
         &mut self,
         key: PredicateKey,
         compilation_target: CompilationTarget,
-        clause_clauses: Vec<TermWriteResult>,
+        clause_clauses: ClauseIter,
         append_or_prepend: AppendOrPrepend,
     ) -> Result<(), SessionError> {
+        let clause_predicates = clause_clauses
+            .map(|(head, body)| Term::Clause(Cell::default(), atom!("$clause"), vec![head, body]));
+
         let clause_clause_compilation_target = match compilation_target {
             CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
             _ => compilation_target,
@@ -2018,7 +2022,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 
         let mut num_clause_predicates = 0;
 
-        for clause_term in clause_clauses {
+        for clause_term in clause_predicates {
             self.incremental_compile_clause(
                 (atom!("$clause"), 2),
                 clause_term,
@@ -2102,13 +2106,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
     }
 
     pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> {
-        let key = match self.payload.predicates.first().map(|term| term.focus) {
-            Some(focus) => clause_predicate_key(self.machine_heap(), focus)
-                .ok_or(SessionError::NamelessEntry)?,
-            None => {
-                return Err(SessionError::NamelessEntry);
-            }
-        };
+        let key = self
+            .payload
+            .predicates
+            .first()
+            .and_then(|cl| {
+                let arity = ClauseInfo::arity(cl);
+                ClauseInfo::name(cl).map(|name| (name, arity))
+            })
+            .ok_or(SessionError::NamelessEntry)?;
 
         let listing_src_file_name = self.listing_src_file_name();
 
@@ -2247,12 +2253,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                 .clause_clauses
                 .drain(0..std::cmp::min(predicates_len, clause_clauses_len))
                 .collect();
+
             let compilation_target = self.payload.predicates.compilation_target;
 
             self.compile_clause_clauses(
                 key,
                 compilation_target,
-                clauses_vec,
+                clauses_vec.into_iter(),
                 AppendOrPrepend::Append,
             )?;
         }
@@ -2281,50 +2288,15 @@ impl Machine {
 
     pub(crate) fn compile_standalone_clause(
         &mut self,
-        term_reg: RegType,
-        vars: Vec<HeapCellValue>,
+        term_loc: RegType,
+        vars: &[Term],
     ) -> 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.cell_len();
-        let arity = vars.len();
-        let term_loc = self.machine_st.heap.cell_len() + 1 + arity;
-
-        let mut writer = self
-            .machine_st
-            .heap
-            .reserve(4 + arity)
-            .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
-
-        writer.write_with(move |section| {
-            section.push_cell(atom_as_cell!(atom!(""), arity));
-
-            for var in vars {
-                section.push_cell(var);
-            }
-
-            let head_loc = if arity > 0 {
-                str_loc_as_cell!(new_header_loc)
-            } else {
-                heap_loc_as_cell!(new_header_loc)
-            };
-
-            section.push_cell(atom_as_cell!(atom!(":-"), 2));
-            section.push_cell(head_loc);
-            section.push_cell(body_cell);
-        });
-
         let mut compile = || {
             let mut loader: Loader<'_, InlineLoadState<'_>> =
                 Loader::new(self, InlineTermStream {});
 
-            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 term = loader.read_term_from_heap(term_loc);
+            let clause = build_rule_body(vars, term);
 
             let settings = CodeGenSettings {
                 global_clock_tick: None,
@@ -2332,7 +2304,7 @@ impl Machine {
                 non_counted_bt: true,
             };
 
-            loader.compile_standalone_clause(term, settings)
+            loader.compile_standalone_clause(clause, settings)
         };
 
         let StandaloneCompileResult { clause_code, .. } = compile()?;
index ad4460d45b4b0bb389e3f46b0c80f4f0d2ad31fe..2187e7b88bc59ff6b5eb3778819af51d36b476fa 100644 (file)
@@ -1,20 +1,18 @@
 use crate::atom_table::*;
 use crate::forms::*;
 use crate::instructions::*;
-use crate::iterators::fact_iterator;
-use crate::machine::heap::*;
+use crate::iterators::*;
 use crate::machine::loader::*;
 use crate::machine::machine_errors::CompilationError;
 use crate::machine::preprocessor::*;
-use crate::machine::Stack;
 use crate::parser::ast::*;
 use crate::parser::dashu::Rational;
-use crate::types::*;
 use crate::variable_records::*;
 
 use dashu::Integer;
 use indexmap::{IndexMap, IndexSet};
 
+use std::cell::Cell;
 use std::cmp::Ordering;
 use std::collections::VecDeque;
 use std::hash::{Hash, Hasher};
@@ -81,34 +79,9 @@ impl BranchNumber {
     }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum ClassifiedVar {
-    Anon { term_loc: usize },
-    InSitu { var_num: usize },
-    Generated { term_loc: usize },
-}
-
-impl ClassifiedVar {
-    fn term_loc(&self) -> Option<usize> {
-        if let &ClassifiedVar::Generated { term_loc } = self {
-            Some(term_loc)
-        } else {
-            None
-        }
-    }
-}
-
-fn to_classified_var(inverse_var_locs: &InverseVarLocs, term_loc: usize) -> ClassifiedVar {
-    if inverse_var_locs.contains_key(&term_loc) {
-        ClassifiedVar::Generated { term_loc }
-    } else {
-        ClassifiedVar::Anon { term_loc }
-    }
-}
-
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct VarInfo {
-    var: ClassifiedVar,
+    var_ptr: VarPtr,
     chunk_type: ChunkType,
     classify_info: ClassifyInfo,
     lvl: Level,
@@ -116,6 +89,7 @@ pub struct VarInfo {
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct ChunkInfo {
+    chunk_num: usize,
     term_loc: GenContext,
     // pointer to incidence, term occurrence arity.
     vars: Vec<VarInfo>,
@@ -136,7 +110,7 @@ impl BranchInfo {
     }
 }
 
-type BranchMapInt = IndexMap<ClassifiedVar, Vec<BranchInfo>>;
+type BranchMapInt = IndexMap<VarPtr, Vec<BranchInfo>>;
 
 #[derive(Debug, Clone)]
 pub struct BranchMap(BranchMapInt);
@@ -173,21 +147,11 @@ enum TraversalState {
     // where it leaves off.
     BuildFinalDisjunct(usize),
     Fail,
-    Succeed,
-    GetCutPoint {
-        var_num: usize,
-        prev_b: bool,
-    },
-    Cut {
-        var_num: usize,
-        is_global: bool,
-    },
+    GetCutPoint { var_num: usize, prev_b: bool },
+    Cut { var_num: usize, is_global: bool },
     CutPrev(usize),
     ResetCallPolicy(CallPolicy),
-    Term {
-        subterm: HeapCellValue,
-        term_loc: usize,
-    },
+    Term(Term),
     OverrideGlobalCutVar(usize),
     ResetGlobalCutVarOverride(Option<usize>),
     RemoveBranchNum,            // pop the current_branch_num and from the root set.
@@ -199,6 +163,8 @@ enum TraversalState {
 pub struct VariableClassifier {
     call_policy: CallPolicy,
     current_branch_num: BranchNumber,
+    current_chunk_num: usize,
+    current_chunk_type: ChunkType,
     branch_map: BranchMap,
     var_num: usize,
     root_set: RootSet,
@@ -206,50 +172,18 @@ pub struct VariableClassifier {
     global_cut_var_num_override: Option<usize>,
 }
 
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub struct VarPtrIndex {
-    pub chunk_num: usize,
-    pub term_loc: usize,
-}
-
-#[derive(Debug)]
-pub enum VarPtr {
-    Numbered(usize),
-    Anon,
-}
-
-#[derive(Debug, Default)]
-pub struct VarLocsToNums {
-    map: IndexMap<VarPtrIndex, usize>,
-}
-
-impl VarLocsToNums {
-    pub fn insert(&mut self, key: VarPtrIndex, var_num: usize) {
-        self.map.insert(key, var_num);
-    }
-
-    pub fn get(&self, idx: VarPtrIndex) -> VarPtr {
-        self.map
-            .get(&idx)
-            .cloned()
-            .map(VarPtr::Numbered)
-            .unwrap_or_else(|| VarPtr::Anon)
-    }
-}
-
 #[derive(Debug, Default)]
 pub struct VarData {
     pub records: VariableRecords,
     pub global_cut_var_num: Option<usize>,
     pub allocates: bool,
-    pub var_locs_to_nums: VarLocsToNums,
 }
 
 impl VarData {
     fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) {
         let global_cut_var_num = if let &Some(global_cut_var_num) = &self.global_cut_var_num {
             match &self.records[global_cut_var_num].allocation {
-                VarAlloc::Perm { .. } => Some(global_cut_var_num),
+                VarAlloc::Perm(..) => Some(global_cut_var_num),
                 VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => {
                     Some(global_cut_var_num)
                 }
@@ -261,15 +195,12 @@ impl VarData {
 
         if let Some(global_cut_var_num) = global_cut_var_num {
             let term = QueryTerm::GetLevel(global_cut_var_num);
-            self.records[global_cut_var_num].allocation = VarAlloc::Perm {
-                reg: 0,
-                allocation: PermVarAllocation::Pending,
-            };
+            self.records[global_cut_var_num].allocation =
+                VarAlloc::Perm(0, PermVarAllocation::Pending);
 
             match build_stack.front_mut() {
                 Some(ChunkedTerms::Branch(_)) => {
                     build_stack.push_front(ChunkedTerms::Chunk {
-                        chunk_num: 0,
                         terms: VecDeque::from(vec![term]),
                     });
                 }
@@ -284,8 +215,8 @@ impl VarData {
     }
 }
 
-pub type ClassifyFactResult = VarData;
-pub type ClassifyRuleResult = (ChunkedTermVec, VarData);
+pub type ClassifyFactResult = (Term, VarData);
+pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData);
 
 fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
     let mut branch_info = BranchInfo::new(BranchNumber::default());
@@ -316,6 +247,8 @@ impl VariableClassifier {
         Self {
             call_policy,
             current_branch_num: BranchNumber::default(),
+            current_chunk_num: 0,
+            current_chunk_type: ChunkType::Head,
             branch_map: BranchMap(BranchMapInt::new()),
             root_set: RootSet::new(),
             var_num: 0,
@@ -324,45 +257,40 @@ impl VariableClassifier {
         }
     }
 
-    pub fn classify_fact<'a, LS: LoadState<'a>>(
-        mut self,
-        loader: &mut Loader<'a, LS>,
-        term: &TermWriteResult,
-    ) -> Result<ClassifyFactResult, CompilationError> {
-        self.classify_head_variables(loader, &term, term.focus)?;
-        Ok(self.branch_map.separate_and_classify_variables(
-            self.var_num,
-            self.global_cut_var_num,
-            0,
+    pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> {
+        self.classify_head_variables(&term)?;
+        Ok((
+            term,
+            self.branch_map.separate_and_classify_variables(
+                self.var_num,
+                self.global_cut_var_num,
+                self.current_chunk_num,
+            ),
         ))
     }
 
     pub fn classify_rule<'a, LS: LoadState<'a>>(
         mut self,
         loader: &mut Loader<'a, LS>,
-        term: &TermWriteResult,
+        head: Term,
+        body: Term,
     ) -> Result<ClassifyRuleResult, CompilationError> {
-        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(loader, &term, head_loc)?;
+        self.classify_head_variables(&head)?;
         self.root_set.insert(self.current_branch_num.clone());
 
-        let mut query_terms = self.classify_body_variables(loader, term, body_loc)?;
+        let mut query_terms = self.classify_body_variables(loader, body)?;
 
         self.merge_branches();
 
         let mut var_data = self.branch_map.separate_and_classify_variables(
             self.var_num,
             self.global_cut_var_num,
-            query_terms.current_chunk_num,
+            self.current_chunk_num,
         );
 
         var_data.emit_initial_get_level(&mut query_terms);
 
-        Ok((query_terms, var_data))
+        Ok((head, query_terms, var_data))
     }
 
     fn merge_branches(&mut self) {
@@ -386,45 +314,51 @@ impl VariableClassifier {
         }
     }
 
-    fn probe_body_term(
-        &mut self,
-        arg_c: usize,
-        arity: usize,
-        term: &mut FocusedHeapRefMut,
-        inverse_var_locs: &InverseVarLocs,
-        context: GenContext,
-    ) {
-        let classify_info = ClassifyInfo { arg_c, arity };
-
-        let mut lvl = Level::Shallow;
-        let mut stack = Stack::uninitialized();
-        let mut iter = fact_iterator::<false>(term.heap, &mut stack, term.focus);
+    fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
+        if self.current_chunk_type.is_last() {
+            self.current_chunk_type = ChunkType::Mid;
+            self.current_chunk_num += 1;
+            true
+        } else {
+            false
+        }
+    }
 
-        // second arg is true to iterate the root, which may be a variable
-        while let Some(subterm) = iter.next() {
-            if !subterm.is_var() {
-                lvl = Level::Deep;
-                continue;
-            }
+    fn try_set_chunk_at_call_boundary(&mut self) -> bool {
+        if self.current_chunk_type.is_last() {
+            self.current_chunk_num += 1;
+            true
+        } else {
+            self.current_chunk_type = ChunkType::Last;
+            false
+        }
+    }
 
-            let var_loc = subterm.get_value() as usize;
-            let var = to_classified_var(inverse_var_locs, var_loc);
+    fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) {
+        let classify_info = ClassifyInfo { arg_c, arity };
 
-            self.probe_body_var(
-                context,
-                VarInfo {
-                    var,
+        // second arg is true to iterate the root, which may be a variable
+        for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
+            if let TermRef::Var(lvl, _, var_ptr) = term_ref {
+                // root terms are shallow here (since we're iterating a
+                // body term) so take the child level.
+                let lvl = lvl.child_level();
+                self.probe_body_var(VarInfo {
+                    var_ptr,
                     lvl,
                     classify_info,
-                    chunk_type: context.chunk_type(),
-                },
-            );
+                    chunk_type: self.current_chunk_type,
+                });
+            }
         }
     }
 
-    fn probe_body_var(&mut self, context: GenContext, var_info: VarInfo) {
-        let chunk_num = context.chunk_num();
-        let branch_info_v = self.branch_map.entry(var_info.var).or_default();
+    fn probe_body_var(&mut self, var_info: VarInfo) {
+        let term_loc = self
+            .current_chunk_type
+            .to_gen_context(self.current_chunk_num);
+
+        let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone()).or_default();
 
         let needs_new_branch = if let Some(last_bi) = branch_info_v.last() {
             !self.root_set.contains(&last_bi.branch_num)
@@ -439,14 +373,15 @@ impl VariableClassifier {
         let branch_info = branch_info_v.last_mut().unwrap();
 
         let needs_new_chunk = if let Some(last_ci) = branch_info.chunks.last() {
-            last_ci.term_loc.chunk_num() != chunk_num
+            last_ci.chunk_num != self.current_chunk_num
         } else {
             true
         };
 
         if needs_new_chunk {
             branch_info.chunks.push(ChunkInfo {
-                term_loc: context,
+                chunk_num: self.current_chunk_num,
+                term_loc,
                 vars: vec![],
             });
         }
@@ -455,81 +390,68 @@ impl VariableClassifier {
         chunk_info.vars.push(var_info);
     }
 
-    fn probe_in_situ_var(&mut self, context: GenContext, var_num: usize) {
+    fn probe_in_situ_var(&mut self, var_num: usize) {
         let classify_info = ClassifyInfo { arg_c: 1, arity: 1 };
 
         let var_info = VarInfo {
-            var: ClassifiedVar::InSitu { var_num },
+            var_ptr: VarPtr::from(Var::InSitu(var_num)),
             classify_info,
-            chunk_type: context.chunk_type(),
+            chunk_type: self.current_chunk_type,
             lvl: Level::Shallow,
         };
 
-        self.probe_body_var(context, var_info);
+        self.probe_body_var(var_info);
     }
 
-    fn classify_head_variables<'a, LS: LoadState<'a>>(
-        &mut self,
-        loader: &mut Loader<'a, LS>,
-        term: &TermWriteResult,
-        head_loc: usize,
-    ) -> Result<(), CompilationError> {
-        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(heap, head_loc);
-            let str_offset = value.get_value() as usize;
-
-            debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str);
-
-            for idx in str_offset + 1..=str_offset + arity {
-                let mut lvl = Level::Shallow;
-                let mut stack = Stack::uninitialized();
-                let mut iter = fact_iterator::<false>(heap, &mut stack, idx);
-
-                while let Some(subterm) = iter.next() {
-                    if !subterm.is_var() {
-                        lvl = Level::Deep;
-                        continue;
-                    }
-
-                    let term_loc = subterm.get_value() as usize;
-                    let var = to_classified_var(&term.inverse_var_locs, term_loc);
+    fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> {
+        match term {
+            Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {}
+            _ => return Err(CompilationError::InvalidRuleHead),
+        }
 
-                    // the body of the if let here is an inlined
-                    // "probe_head_var". note the difference between it
-                    // and "probe_body_var".
-                    let branch_info_v = self.branch_map.entry(var).or_default();
-                    let needs_new_branch = branch_info_v.is_empty();
+        let mut classify_info = ClassifyInfo {
+            arg_c: 1,
+            arity: term.arity(),
+        };
 
-                    if needs_new_branch {
-                        branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
-                    }
+        if let Term::Clause(_, _, terms) = term {
+            for term in terms.iter() {
+                for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
+                    if let TermRef::Var(lvl, _, var_ptr) = term_ref {
+                        // a body term, so we need the child level here.
+                        let lvl = lvl.child_level();
+
+                        // the body of the if let here is an inlined
+                        // "probe_head_var". note the difference between it
+                        // and "probe_body_var".
+                        let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
+                        let needs_new_branch = branch_info_v.is_empty();
+
+                        if needs_new_branch {
+                            branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
+                        }
 
-                    let branch_info = branch_info_v.last_mut().unwrap();
-                    let needs_new_chunk = branch_info.chunks.is_empty();
+                        let branch_info = branch_info_v.last_mut().unwrap();
+                        let needs_new_chunk = branch_info.chunks.is_empty();
 
-                    if needs_new_chunk {
-                        branch_info.chunks.push(ChunkInfo {
-                            term_loc: GenContext::Head,
-                            vars: vec![],
-                        });
-                    }
+                        if needs_new_chunk {
+                            branch_info.chunks.push(ChunkInfo {
+                                chunk_num: self.current_chunk_num,
+                                term_loc: GenContext::Head,
+                                vars: vec![],
+                            });
+                        }
 
-                    let chunk_info = branch_info.chunks.last_mut().unwrap();
-                    let var_info = VarInfo {
-                        var,
-                        classify_info,
-                        chunk_type: ChunkType::Head,
-                        lvl,
-                    };
+                        let chunk_info = branch_info.chunks.last_mut().unwrap();
+                        let var_info = VarInfo {
+                            var_ptr,
+                            classify_info,
+                            chunk_type: self.current_chunk_type,
+                            lvl,
+                        };
 
-                    chunk_info.vars.push(var_info);
+                        chunk_info.vars.push(var_info);
+                    }
                 }
 
                 classify_info.arg_c += 1;
@@ -539,38 +461,17 @@ impl VariableClassifier {
         Ok(())
     }
 
-    fn new_cut_state(&mut self, context: GenContext) -> TraversalState {
-        let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override {
-            (var_num, false)
-        } else if let Some(var_num) = self.global_cut_var_num {
-            (var_num, true)
-        } else {
-            let var_num = self.var_num;
-
-            self.global_cut_var_num = Some(var_num);
-            self.var_num += 1;
-
-            (var_num, true)
-        };
-
-        self.probe_in_situ_var(context, var_num);
-
-        TraversalState::Cut { var_num, is_global }
-    }
-
     fn classify_body_variables<'a, LS: LoadState<'a>>(
         &mut self,
         loader: &mut Loader<'a, LS>,
-        terms: &TermWriteResult,
-        term_loc: usize,
+        term: Term,
     ) -> Result<ChunkedTermVec, CompilationError> {
-        let mut state_stack = vec![TraversalState::Term {
-            subterm: loader.machine_heap()[term_loc],
-            term_loc,
-        }];
+        let mut state_stack = vec![TraversalState::Term(term)];
         let mut build_stack = ChunkedTermVec::new();
 
-        'outer: while let Some(traversal_st) = state_stack.pop() {
+        self.current_chunk_type = ChunkType::Mid;
+
+        while let Some(traversal_st) = state_stack.pop() {
             match traversal_st {
                 TraversalState::AddBranchNum(branch_num) => {
                     self.root_set.insert(branch_num.clone());
@@ -590,22 +491,21 @@ impl VariableClassifier {
                 TraversalState::BuildDisjunct(preceding_len) => {
                     flatten_into_disjunct(&mut build_stack, preceding_len);
 
-                    build_stack.current_chunk_type = ChunkType::Mid;
-                    build_stack.current_chunk_num += 1;
+                    self.current_chunk_type = ChunkType::Mid;
+                    self.current_chunk_num += 1;
                 }
                 TraversalState::BuildFinalDisjunct(preceding_len) => {
                     flatten_into_disjunct(&mut build_stack, preceding_len);
 
-                    build_stack.current_chunk_type = ChunkType::Mid;
-                    build_stack.current_chunk_num += 1;
+                    self.current_chunk_type = ChunkType::Mid;
+                    self.current_chunk_num += 1;
                 }
                 TraversalState::GetCutPoint { var_num, prev_b } => {
-                    if build_stack.try_set_chunk_at_inlined_boundary() {
+                    if self.try_set_chunk_at_inlined_boundary() {
                         build_stack.add_chunk();
                     }
 
-                    let context = build_stack.current_gen_context();
-                    self.probe_in_situ_var(context, var_num);
+                    self.probe_in_situ_var(var_num);
                     build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
                 }
                 TraversalState::OverrideGlobalCutVar(var_num) => {
@@ -615,12 +515,11 @@ impl VariableClassifier {
                     self.global_cut_var_num_override = old_override;
                 }
                 TraversalState::Cut { var_num, is_global } => {
-                    if build_stack.try_set_chunk_at_inlined_boundary() {
+                    if self.try_set_chunk_at_inlined_boundary() {
                         build_stack.add_chunk();
                     }
 
-                    let context = build_stack.current_gen_context();
-                    self.probe_in_situ_var(context, var_num);
+                    self.probe_in_situ_var(var_num);
 
                     build_stack.push_chunk_term(if is_global {
                         QueryTerm::GlobalCut(var_num)
@@ -632,12 +531,11 @@ impl VariableClassifier {
                     });
                 }
                 TraversalState::CutPrev(var_num) => {
-                    if build_stack.try_set_chunk_at_inlined_boundary() {
+                    if self.try_set_chunk_at_inlined_boundary() {
                         build_stack.add_chunk();
                     }
 
-                    let context = build_stack.current_gen_context();
-                    self.probe_in_situ_var(context, var_num);
+                    self.probe_in_situ_var(var_num);
 
                     build_stack.push_chunk_term(QueryTerm::LocalCut {
                         var_num,
@@ -647,374 +545,297 @@ impl VariableClassifier {
                 TraversalState::Fail => {
                     build_stack.push_chunk_term(QueryTerm::Fail);
                 }
-                TraversalState::Succeed => {
-                    build_stack.push_chunk_term(QueryTerm::Succeed);
-                }
-                TraversalState::Term {
-                    mut subterm,
-                    mut term_loc,
-                } => {
+                TraversalState::Term(term) => {
                     // return true iff new chunk should be added.
-                    let update_chunk_data =
-                        |build_stack: &mut ChunkedTermVec, key: PredicateKey| {
-                            if ClauseType::is_inlined(key.0, key.1) {
-                                build_stack.try_set_chunk_at_inlined_boundary()
-                            } else {
-                                build_stack.try_set_chunk_at_call_boundary()
-                            }
-                        };
+                    let update_chunk_data = |classifier: &mut Self, predicate_name, arity| {
+                        if ClauseType::is_inlined(predicate_name, arity) {
+                            classifier.try_set_chunk_at_inlined_boundary()
+                        } else {
+                            classifier.try_set_chunk_at_call_boundary()
+                        }
+                    };
 
-                    macro_rules! add_chunk {
-                        ($key:expr, $tag:expr, $term_loc:expr) => {{
-                            if update_chunk_data(&mut build_stack, $key) {
-                                build_stack.add_chunk();
-                            }
+                    let mut add_chunk = |classifier: &mut Self, name: Atom, terms: Vec<Term>| {
+                        if update_chunk_data(classifier, name, terms.len()) {
+                            build_stack.add_chunk();
+                        }
+
+                        for (arg_c, term) in terms.iter().enumerate() {
+                            classifier.probe_body_term(arg_c + 1, terms.len(), term);
+                        }
 
-                            let context = build_stack.current_gen_context();
+                        build_stack.push_chunk_term(clause_to_query_term(
+                            loader,
+                            name,
+                            terms,
+                            classifier.call_policy,
+                        ));
+                    };
 
-                            for (arg_c, term_loc) in
-                                ($term_loc + 1..=$term_loc + $key.1).enumerate()
-                            {
-                                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,
-                                );
+                    match term {
+                        Term::Clause(
+                            _,
+                            name @ (atom!("->") | atom!(";") | atom!(",")),
+                            mut terms,
+                        ) if terms.len() == 3 => {
+                            if let Some(last_arg) = terms.last() {
+                                if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
+                                    terms.pop();
+                                    state_stack.push(TraversalState::Term(Term::Clause(
+                                        Cell::default(),
+                                        name,
+                                        terms,
+                                    )));
+                                } else {
+                                    add_chunk(self, name, terms);
+                                }
                             }
+                        }
+                        Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => {
+                            let tail = terms.pop().unwrap();
+                            let head = terms.pop().unwrap();
 
-                            build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
-                                loader,
-                                $key,
-                                &terms,
-                                HeapCellValue::build_with($tag, $term_loc as u64),
-                                self.call_policy,
-                            )));
-                        }};
-                    }
+                            let iter = unfold_by_str(tail, atom!(","))
+                                .into_iter()
+                                .rev()
+                                .chain(std::iter::once(head))
+                                .map(TraversalState::Term);
 
-                    macro_rules! add_qualified_chunk {
-                        ($module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{
-                            if update_chunk_data(&mut build_stack, $key) {
-                                build_stack.add_chunk();
-                            }
+                            state_stack.extend(iter);
+                        }
+                        Term::Clause(_, atom!(";"), mut terms) if terms.len() == 2 => {
+                            let tail = terms.pop().unwrap();
+                            let head = terms.pop().unwrap();
 
-                            let context = build_stack.current_gen_context();
+                            let first_branch_num = self.current_branch_num.split();
+                            let branches: Vec<_> = std::iter::once(head)
+                                .chain(unfold_by_str(tail, atom!(";")).into_iter())
+                                .collect();
 
-                            for (arg_c, term_loc) in
-                                ($term_loc + 1..=$term_loc + $key.1).enumerate()
-                            {
-                                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,
-                                );
+                            let mut branch_numbers = vec![first_branch_num];
+
+                            for idx in 1..branches.len() {
+                                let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
+
+                                branch_numbers.push(if idx + 1 < branches.len() {
+                                    succ_branch_number.split()
+                                } else {
+                                    succ_branch_number
+                                });
                             }
 
-                            build_stack.push_chunk_term(QueryTerm::Clause(
-                                qualified_clause_to_query_term(
-                                    loader,
-                                    $key,
-                                    $module_name,
-                                    &terms,
-                                    HeapCellValue::build_with($tag, $term_loc as u64),
-                                    self.call_policy,
-                                ),
+                            let build_stack_len = build_stack.len();
+                            build_stack.reserve_branch(branches.len());
+
+                            state_stack.push(TraversalState::RepBranchNum(
+                                self.current_branch_num.halve_delta(),
                             ));
-                        }};
-                    }
 
-                    loop {
-                        let heap = loader.machine_heap();
+                            let iter = branches.into_iter().zip(branch_numbers.into_iter());
+                            let final_disjunct_loc = state_stack.len();
 
-                        read_heap_cell!(subterm,
-                            (HeapCellValueTag::Str, subterm_loc) => {
-                                let (name, arity) = cell_as_atom_cell!(heap[subterm_loc])
-                                    .get_name_and_arity();
+                            for (term, branch_num) in iter.rev() {
+                                state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
+                                state_stack.push(TraversalState::RemoveBranchNum);
+                                state_stack.push(TraversalState::Term(term));
+                                state_stack.push(TraversalState::AddBranchNum(branch_num));
+                            }
 
-                                match (name, arity) {
-                                    (atom!("->") | atom!(";") | atom!(","), 3) => {
-                                        if blunt_index_ptr(heap, (name, 2), subterm_loc) {
-                                            subterm = heap[subterm_loc];
-                                            continue;
-                                        }
+                            if let TraversalState::BuildDisjunct(build_stack_len) =
+                                state_stack[final_disjunct_loc]
+                            {
+                                state_stack[final_disjunct_loc] =
+                                    TraversalState::BuildFinalDisjunct(build_stack_len);
+                            }
 
-                                        add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc);
-                                    }
-                                    (atom!(","), 2) => {
-                                        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(heap, tail_loc, atom!(","))
-                                            .into_iter()
-                                            .rev()
-                                            .chain(std::iter::once((head, head_loc)))
-                                            .map(|(subterm, term_loc)| {
-                                                TraversalState::Term { subterm, term_loc }
-                                            });
-                                        state_stack.extend(iter);
-                                    }
-                                    (atom!(";"), 2) => {
-                                        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 first_branch_num = self.current_branch_num.split();
-                                        let branches: Vec<_> = std::iter::once((head, head_loc))
-                                            .chain(
-                                                unfold_by_str_locs(heap, tail_loc, atom!(";"))
-                                                    .into_iter(),
-                                            )
-                                            .collect();
-
-                                        let mut branch_numbers = vec![first_branch_num];
-
-                                        for idx in 1..branches.len() {
-                                            let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
-
-                                            branch_numbers.push(if idx + 1 < branches.len() {
-                                                succ_branch_number.split()
-                                            } else {
-                                                succ_branch_number
-                                            });
-                                        }
-
-                                        let build_stack_len = build_stack.len();
-                                        build_stack.reserve_branch(branches.len());
-
-                                        state_stack.push(TraversalState::RepBranchNum(
-                                            self.current_branch_num.halve_delta(),
-                                        ));
-
-                                        let iter = branches.into_iter().zip(branch_numbers.into_iter());
-                                        let final_disjunct_loc = state_stack.len();
-
-                                        for ((subterm, term_loc), branch_num) in iter.rev() {
-                                            state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
-                                            state_stack.push(TraversalState::RemoveBranchNum);
-                                            state_stack.push(TraversalState::Term { subterm, term_loc });
-                                            state_stack.push(TraversalState::AddBranchNum(branch_num));
-                                        }
-
-                                        if let TraversalState::BuildDisjunct(build_stack_len) =
-                                            state_stack[final_disjunct_loc]
-                                        {
-                                            state_stack[final_disjunct_loc] =
-                                                TraversalState::BuildFinalDisjunct(build_stack_len);
-                                        }
-
-                                        build_stack.current_chunk_type = ChunkType::Mid;
-                                        build_stack.current_chunk_num += 1;
-                                    }
-                                    (atom!("->"), 2) => {
-                                        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 = heap[if_term_loc];
-                                        let then_term = heap[then_term_loc];
-
-                                        let prev_b = if matches!(
-                                            state_stack.last(),
-                                            Some(TraversalState::RemoveBranchNum)
-                                        ) {
-                                            // check if the second-to-last element
-                                            // is a regular BuildDisjunct, as we
-                                            // don't want to add GetPrevLevel in
-                                            // case of a TrustMe.
-                                            match state_stack.iter().rev().nth(1) {
-                                                Some(&TraversalState::BuildDisjunct(preceding_len)) => {
-                                                    preceding_len + 1 == build_stack.len()
-                                                }
-                                                _ => false,
-                                            }
-                                        } else {
-                                            false
-                                        };
-
-                                        state_stack.push(TraversalState::Term {
-                                            subterm: then_term,
-                                            term_loc: then_term_loc,
-                                        });
-                                        state_stack.push(TraversalState::Cut {
-                                            var_num: self.var_num,
-                                            is_global: false,
-                                        });
-                                        state_stack.push(TraversalState::Term {
-                                            subterm: if_term,
-                                            term_loc: if_term_loc,
-                                        });
-                                        state_stack.push(TraversalState::GetCutPoint {
-                                            var_num: self.var_num,
-                                            prev_b,
-                                        });
-
-                                        self.var_num += 1;
-                                    }
-                                    (atom!("\\+"), 1) => {
-                                        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);
-
-                                        let branch_num = self.current_branch_num.split();
-                                        let succ_branch_num = branch_num.incr_by_delta();
-
-                                        state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
-                                        state_stack.push(TraversalState::Succeed);
-                                        state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
-                                        state_stack.push(TraversalState::RepBranchNum(succ_branch_num));
-                                        state_stack.push(TraversalState::Fail);
-                                        state_stack.push(TraversalState::CutPrev(self.var_num));
-                                        state_stack.push(TraversalState::ResetGlobalCutVarOverride(
-                                            self.global_cut_var_num_override,
-                                        ));
-                                        state_stack.push(TraversalState::Term {
-                                            subterm: not_term,
-                                            term_loc: not_term_loc,
-                                        });
-                                        state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
-                                        state_stack.push(TraversalState::GetCutPoint {
-                                            var_num: self.var_num,
-                                            prev_b: false,
-                                        });
-                                        state_stack.push(TraversalState::AddBranchNum(branch_num));
-
-                                        build_stack.current_chunk_type = ChunkType::Mid;
-                                        build_stack.current_chunk_num += 1;
-
-                                        self.var_num += 1;
+                            self.current_chunk_type = ChunkType::Mid;
+                            self.current_chunk_num += 1;
+                        }
+                        Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => {
+                            let then_term = terms.pop().unwrap();
+                            let if_term = terms.pop().unwrap();
+
+                            let prev_b = if matches!(
+                                state_stack.last(),
+                                Some(TraversalState::RemoveBranchNum)
+                            ) {
+                                // check if the second-to-last element
+                                // is a regular BuildDisjunct, as we
+                                // don't want to add GetPrevLevel in
+                                // case of a TrustMe.
+                                match state_stack.iter().rev().nth(1) {
+                                    Some(&TraversalState::BuildDisjunct(preceding_len)) => {
+                                        preceding_len + 1 == build_stack.len()
                                     }
-                                    (atom!(":"), 2) => {
-                                        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 = 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!(heap[s])
-                                                                .get_name_and_arity();
-
-                                                            add_qualified_chunk!(
-                                                                module_name,
-                                                                key,
-                                                                HeapCellValueTag::Str,
-                                                                s
-                                                            );
-                                                        }
-                                                        (HeapCellValueTag::Atom, (predicate_name, predicate_arity)) => {
-                                                            debug_assert_eq!(predicate_arity, 0);
-                                                            let key = (predicate_name, predicate_arity);
-
-                                                            add_qualified_chunk!(
-                                                                module_name,
-                                                                key,
-                                                                HeapCellValueTag::Str,
-                                                                predicate_term_loc
-                                                            );
-                                                        }
-                                                        _ => {}
-                                                    );
-
-                                                    continue 'outer;
-                                                }
-                                            }
-                                            _ => {}
-                                        );
-
-                                        if update_chunk_data(&mut build_stack, (atom!("call"), 2)) {
-                                            build_stack.add_chunk();
-                                        }
-
-                                        let context = build_stack.current_gen_context();
-
-                                        focused.focus = module_name_loc;
-
-                                        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();
-
-                                        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,
-                                            str_loc_as_cell!(h),
-                                            self.call_policy,
-                                        )));
+                                    _ => false,
+                                }
+                            } else {
+                                false
+                            };
+
+                            state_stack.push(TraversalState::Term(then_term));
+                            state_stack.push(TraversalState::Cut {
+                                var_num: self.var_num,
+                                is_global: false,
+                            });
+                            state_stack.push(TraversalState::Term(if_term));
+                            state_stack.push(TraversalState::GetCutPoint {
+                                var_num: self.var_num,
+                                prev_b,
+                            });
+
+                            self.var_num += 1;
+                        }
+                        Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => {
+                            let not_term = terms.pop().unwrap();
+                            let build_stack_len = build_stack.len();
+
+                            build_stack.reserve_branch(2);
+
+                            state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
+                            state_stack.push(TraversalState::Term(Term::Clause(
+                                Cell::default(),
+                                atom!("$succeed"),
+                                vec![],
+                            )));
+                            state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
+                            state_stack.push(TraversalState::Fail);
+                            state_stack.push(TraversalState::CutPrev(self.var_num));
+                            state_stack.push(TraversalState::ResetGlobalCutVarOverride(
+                                self.global_cut_var_num_override,
+                            ));
+                            state_stack.push(TraversalState::Term(not_term));
+                            state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
+                            state_stack.push(TraversalState::GetCutPoint {
+                                var_num: self.var_num,
+                                prev_b: false,
+                            });
+
+                            self.current_chunk_type = ChunkType::Mid;
+                            self.current_chunk_num += 1;
+
+                            self.var_num += 1;
+                        }
+                        Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => {
+                            let predicate_name = terms.pop().unwrap();
+                            let module_name = terms.pop().unwrap();
+
+                            match (module_name, predicate_name) {
+                                (
+                                    Term::Literal(_, Literal::Atom(module_name)),
+                                    Term::Literal(_, Literal::Atom(predicate_name)),
+                                ) => {
+                                    if update_chunk_data(self, predicate_name, 0) {
+                                        build_stack.add_chunk();
                                     }
-                                    (atom!("$call_with_inference_counting"), 1) => {
-                                        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 });
-
-                                        self.call_policy = CallPolicy::Counted;
+
+                                    build_stack.push_chunk_term(qualified_clause_to_query_term(
+                                        loader,
+                                        module_name,
+                                        predicate_name,
+                                        vec![],
+                                        self.call_policy,
+                                    ));
+                                }
+                                (
+                                    Term::Literal(_, Literal::Atom(module_name)),
+                                    Term::Clause(_, name, terms),
+                                ) => {
+                                    if update_chunk_data(self, name, terms.len()) {
+                                        build_stack.add_chunk();
                                     }
-                                    (name, arity) => {
-                                        add_chunk!((name, arity), HeapCellValueTag::Str, subterm_loc);
+
+                                    for (arg_c, term) in terms.iter().enumerate() {
+                                        self.probe_body_term(arg_c + 1, terms.len(), term);
                                     }
+
+                                    build_stack.push_chunk_term(qualified_clause_to_query_term(
+                                        loader,
+                                        module_name,
+                                        name,
+                                        terms,
+                                        self.call_policy,
+                                    ));
                                 }
-                            }
-                            (HeapCellValueTag::Atom, (name, arity)) => {
-                                debug_assert_eq!(arity, 0);
+                                (module_name, predicate_name) => {
+                                    if update_chunk_data(self, atom!("call"), 2) {
+                                        build_stack.add_chunk();
+                                    }
 
-                                if name == atom!("!") {
-                                    let context = build_stack.current_gen_context();
-                                    state_stack.push(self.new_cut_state(context));
-                                } else {
-                                    add_chunk!((name, 0), HeapCellValueTag::Var, term_loc);
+                                    self.probe_body_term(1, 0, &module_name);
+                                    self.probe_body_term(2, 0, &predicate_name);
+
+                                    terms.push(module_name);
+                                    terms.push(predicate_name);
+
+                                    build_stack.push_chunk_term(clause_to_query_term(
+                                        loader,
+                                        atom!("call"),
+                                        vec![Term::Clause(Cell::default(), atom!(":"), terms)],
+                                        self.call_policy,
+                                    ));
                                 }
                             }
-                            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                                if h != term_loc {
-                                    subterm = heap[h];
-                                    term_loc = h;
-                                    continue;
-                                }
+                        }
+                        Term::Clause(_, atom!("$call_with_inference_counting"), mut terms)
+                            if terms.len() == 1 =>
+                        {
+                            state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
+                            state_stack.push(TraversalState::Term(terms.pop().unwrap()));
 
-                                add_chunk!((atom!("call"), 1), HeapCellValueTag::Var, h);
+                            self.call_policy = CallPolicy::Counted;
+                        }
+                        Term::Clause(_, name, terms) => {
+                            add_chunk(self, name, terms);
+                        }
+                        var @ Term::Var(..) => {
+                            if update_chunk_data(self, atom!("call"), 1) {
+                                build_stack.add_chunk();
                             }
-                            _ => {
-                                return Err(CompilationError::InadmissibleQueryTerm);
+
+                            self.probe_body_term(1, 1, &var);
+
+                            build_stack.push_chunk_term(clause_to_query_term(
+                                loader,
+                                atom!("call"),
+                                vec![var],
+                                self.call_policy,
+                            ));
+                        }
+                        Term::Literal(_, Literal::Atom(atom!("!"))) => {
+                            let (var_num, is_global) =
+                                if let Some(var_num) = self.global_cut_var_num_override {
+                                    (var_num, false)
+                                } else if let Some(var_num) = self.global_cut_var_num {
+                                    (var_num, true)
+                                } else {
+                                    let var_num = self.var_num;
+
+                                    self.global_cut_var_num = Some(var_num);
+                                    self.var_num += 1;
+
+                                    (var_num, true)
+                                };
+
+                            self.probe_in_situ_var(var_num);
+
+                            state_stack.push(TraversalState::Cut { var_num, is_global });
+                        }
+                        Term::Literal(_, Literal::Atom(name)) => {
+                            if update_chunk_data(self, name, 0) {
+                                build_stack.add_chunk();
                             }
-                        );
 
-                        break;
+                            build_stack.push_chunk_term(clause_to_query_term(
+                                loader,
+                                name,
+                                vec![],
+                                self.call_policy,
+                            ));
+                        }
+                        _ => {
+                            return Err(CompilationError::InadmissibleQueryTerm);
+                        }
                     }
                 }
             }
@@ -1035,13 +856,13 @@ impl BranchMap {
             records: VariableRecords::new(var_num),
             global_cut_var_num,
             allocates: current_chunk_num > 0,
-            var_locs_to_nums: VarLocsToNums::default(),
         };
 
         for (var, branches) in self.iter_mut() {
-            let (mut var_num, var_num_incr) = match var {
-                &ClassifiedVar::InSitu { var_num } => (var_num, false),
-                _ => (var_data.records.len(), true),
+            let (mut var_num, var_num_incr) = if let Var::InSitu(var_num) = *var.borrow() {
+                (var_num, false)
+            } else {
+                (var_data.records.len(), true)
             };
 
             for branch in branches.iter_mut() {
@@ -1059,10 +880,7 @@ impl BranchMap {
 
                     for var_info in chunk.vars.iter_mut() {
                         if var_info.lvl == Level::Shallow {
-                            let context = var_info
-                                .chunk_type
-                                .to_gen_context(chunk.term_loc.chunk_num());
-
+                            let context = var_info.chunk_type.to_gen_context(chunk.chunk_num);
                             temp_var_data
                                 .use_set
                                 .insert((context, var_info.classify_info.arg_c));
@@ -1081,16 +899,8 @@ impl BranchMap {
                 for chunk in branch.chunks.iter_mut() {
                     var_data.records[var_num].num_occurrences += chunk.vars.len();
 
-                    if let Some(term_loc) = var.term_loc() {
-                        let chunk_num = chunk.term_loc.chunk_num();
-
-                        var_data.var_locs_to_nums.insert(
-                            VarPtrIndex {
-                                chunk_num,
-                                term_loc,
-                            },
-                            var_num,
-                        );
+                    for var_info in chunk.vars.iter_mut() {
+                        var_info.var_ptr.set(Var::Generated(var_num));
                     }
                 }
             }
index cd6723209275f61c1f1851204551f54324e97918..f1519986fc17becb139fb5391636a8cc26876fa0 100644 (file)
@@ -2829,7 +2829,7 @@ impl Machine {
                                     Some(PStrCmpResult::PartialPStrMatch { string, var_loc }) => {
                                         let cell = backtrack_on_resource_error!(
                                             self.machine_st,
-                                            self.machine_st.allocate_pstr(string)
+                                            self.machine_st.heap.allocate_pstr(string)
                                         );
 
                                         self.machine_st.mode = MachineMode::Write;
@@ -2851,7 +2851,7 @@ impl Machine {
                              HeapCellValueTag::Var) => {
                                 let target_cell = backtrack_on_resource_error!(
                                     self.machine_st,
-                                    self.machine_st.allocate_pstr(string)
+                                    self.machine_st.heap.allocate_pstr(string)
                                 );
 
                                 self.machine_st.bind(
@@ -3196,7 +3196,7 @@ impl Machine {
                     &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.heap.allocate_pstr(&string)
                         );
 
                         self.machine_st.p += 1;
index cb46f8614eec79527b423f5b925bc180450405de..7c79eba0a297e533998e7b1df8139fa6c09d776a 100644 (file)
@@ -1,23 +1,19 @@
 #[cfg(test)]
-use crate::atom_table::*;
-#[cfg(test)]
-use crate::machine::heap::*;
+use fxhash::FxBuildHasher;
 #[cfg(test)]
-use crate::types::*;
-
+use indexmap::IndexMap;
 #[cfg(test)]
-use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc};
+use std::collections::BTreeMap;
 
 #[cfg(test)]
-use std::collections::BTreeMap;
+use crate::atom_table::*;
 #[cfg(test)]
-use std::ops::Deref;
-
+use crate::machine::heap::*;
 #[cfg(test)]
-use fxhash::FxBuildHasher;
+use crate::types::*;
 
 #[cfg(test)]
-use indexmap::IndexMap;
+use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc};
 
 #[cfg(test)]
 pub(crate) trait UnmarkPolicy {
@@ -185,15 +181,6 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
     pstr_loc_values: PStrLocValuesMap,
 }
 
-#[cfg(test)]
-impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> {
-    type Target = Heap;
-
-    fn deref(&self) -> &Self::Target {
-        self.heap
-    }
-}
-
 #[cfg(test)]
 impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
     #[inline]
@@ -778,7 +765,7 @@ mod tests {
         // two-part complete string, then a three-part cyclic string
         // involving an uncompacted list of chars.
 
-        let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap();
+        let pstr_cell = wam.machine_st.heap.allocate_pstr("abc ").unwrap();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
 
@@ -812,7 +799,7 @@ mod tests {
 
         wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
 
-        wam.machine_st.allocate_pstr("abcdef ").unwrap();
+        wam.machine_st.heap.allocate_pstr("abcdef ").unwrap();
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap();
 
         mark_cells(&mut wam.machine_st.heap, 2);
index efd4337cc4f2fc84b8a8d61425741337b11d1760..0c754baf6db71e8cdc30fb295badfe4fc8ae0bd1 100644 (file)
@@ -4,13 +4,12 @@ use crate::functor_macro::*;
 use crate::types::*;
 
 use std::alloc;
+use std::cmp::Ordering;
 use std::convert::TryFrom;
 use std::ops::{Bound, Index, IndexMut, Range, RangeBounds};
 use std::ptr;
 use std::sync::Once;
 
-use super::MachineState;
-
 const ALIGN: usize = Heap::heap_cell_alignment();
 
 #[derive(Debug)]
@@ -92,9 +91,10 @@ pub struct HeapStringScan<'a> {
 }
 
 // return the string at ptr and the tail location relative to ptr.
-unsafe fn scan_slice_to_str<'a>(heap_slice: &'a [u8]) -> HeapStringScan<'a> {
+unsafe fn scan_slice_to_str(heap_slice: &[u8]) -> HeapStringScan {
     let string_len = heap_slice.iter().position(|b| *b == 0u8).unwrap();
     let zero_byte_addr = heap_slice.as_ptr().add(string_len);
+
     let sentinel_len = pstr_sentinel_length(zero_byte_addr as usize);
     let tail_idx = cell_index!(
         (string_len + sentinel_len).next_multiple_of(ALIGN)
@@ -111,79 +111,9 @@ unsafe fn scan_slice_to_str<'a>(heap_slice: &'a [u8]) -> HeapStringScan<'a> {
 
 #[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::pstr_tail_idx(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::pstr_tail_idx(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));
-            }
-            PStrSegmentCmpResult::BothMatch {
-                pstr_loc1,
-                pstr_loc2,
-                null_offset,
-            } => {
-                // exhaustive match
-                let tail1 = Heap::pstr_tail_idx(pstr_loc1 + null_offset);
-                let tail2 = Heap::pstr_tail_idx(pstr_loc2 + null_offset);
-
-                pdl.push(heap_loc_as_cell!(tail1));
-                pdl.push(heap_loc_as_cell!(tail2));
-            }
-            PStrSegmentCmpResult::Mismatch { c1, c2 } => {
-                return Some(c1.cmp(&c2));
-            }
-        }
-
-        None
-    }
-}
-
-#[derive(Debug)]
-pub struct PStrWriteInfo {
-    cell: HeapCellValue,
+    Less,
+    Greater,
+    Continue(HeapCellValue, HeapCellValue),
 }
 
 #[derive(Debug)]
@@ -269,7 +199,6 @@ impl ReservedHeapSection {
                 }
 
                 self.push_cell(char_as_cell!('\u{0}'));
-
                 src = &src[1..];
             }
 
@@ -277,8 +206,6 @@ impl ReservedHeapSection {
                 return ret;
             }
 
-            debug_assert!(!src.is_empty());
-
             if let Some(null_char_idx) = src.find('\u{0}') {
                 debug_assert_ne!(null_char_idx, 0);
 
@@ -300,6 +227,7 @@ impl ReservedHeapSection {
                 self.push_cell(char_as_cell!('\u{0}'));
 
                 src = &src[null_char_idx + 1..];
+
                 if src.is_empty() {
                     return ret;
                 }
@@ -316,7 +244,6 @@ impl ReservedHeapSection {
                 }
 
                 self.push_pstr_segment(&src);
-
                 return ret;
             }
         }
@@ -449,23 +376,6 @@ impl<'a> HeapWriter<'a> {
             result,
         }
     }
-
-    #[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> {
@@ -517,8 +427,6 @@ impl<'a> SizedHeap for HeapWriter<'a> {
     }
 }
 
-impl<'a> SizedHeapMut for HeapWriter<'a> {}
-
 impl Heap {
     pub(crate) fn new() -> Self {
         Self {
@@ -638,16 +546,6 @@ impl Heap {
         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();
@@ -699,48 +597,69 @@ impl Heap {
         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 slice1 = &self.as_slice()[pstr_loc1..];
+        let slice2 = &self.as_slice()[pstr_loc2..];
+
+        let find_tail = |null_idx: usize| -> usize { self.scan_slice_to_str(null_idx).tail_idx };
+
+        match slice1
+            .iter()
+            .zip(slice2.iter())
+            .position(|(b1, b2)| b1 != b2 || *b1 == 0 || *b2 == 0)
+        {
+            Some(pos) => {
+                if slice1[pos] == 0 {
+                    // subtract 1 from pos to offset the increment of scan_slice_to_str if the
+                    // string is "\0\".
+                    let tail1_idx = find_tail(pstr_loc1 + pos);
+
+                    if slice2[pos] == 0 {
+                        let tail2_idx = find_tail(pstr_loc2 + pos);
+
+                        PStrSegmentCmpResult::Continue(
+                            heap_loc_as_cell!(tail1_idx),
+                            heap_loc_as_cell!(tail2_idx),
+                        )
+                    } else {
+                        PStrSegmentCmpResult::Continue(
+                            heap_loc_as_cell!(tail1_idx),
+                            pstr_loc_as_cell!(pstr_loc2 + pos),
+                        )
+                    }
+                } else if slice2[pos] == 0 {
+                    let tail2_idx = find_tail(pstr_loc2 + pos);
 
-            let slice2 = std::slice::from_raw_parts(
-                self.inner.ptr.add(pstr_loc2),
-                self.inner.byte_len - pstr_loc2,
-            );
+                    PStrSegmentCmpResult::Continue(
+                        pstr_loc_as_cell!(pstr_loc1 + pos),
+                        heap_loc_as_cell!(tail2_idx),
+                    )
+                } else {
+                    // Compute 7-byte chunks with the mismatching character at pos in the middle of
+                    // each. This way, the character of which the byte at pos is a part will be
+                    // validated and reached eventually by the utf8_chunks() iterator.
 
-            let str1 = std::str::from_utf8_unchecked(&slice1);
-            let str2 = std::str::from_utf8_unchecked(&slice2);
+                    let slice1_range = pos.saturating_sub(3)..(pos + 4).min(slice1.len());
+                    let slice2_range = pos.saturating_sub(3)..(pos + 4).min(slice2.len());
 
-            debug_assert!(!str1.is_empty());
-            debug_assert!(!str2.is_empty());
+                    let chars1_iter = slice1[slice1_range].utf8_chunks();
+                    let chars2_iter = slice2[slice2_range].utf8_chunks();
 
-            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 };
+                    for (chunk1, chunk2) in chars1_iter.zip(chars2_iter) {
+                        let result = chunk1.valid().cmp(chunk2.valid());
+
+                        if result == Ordering::Greater {
+                            return PStrSegmentCmpResult::Greater;
+                        } else if result == Ordering::Less {
+                            return PStrSegmentCmpResult::Less;
+                        }
+                    }
+
+                    unreachable!()
                 }
             }
-
-            unreachable!() // PStrSegmentCmpResult::Match(std::cmp::min(str1.len(), str2.len()))
+            None => {
+                unreachable!()
+            }
         }
     }
 
@@ -833,43 +752,34 @@ impl Heap {
         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 fn allocate_pstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
+        let size_in_heap = Self::compute_pstr_size(src);
+        let mut writer = self.reserve(size_in_heap)?;
+        let HeapSectionWriteResult { result, .. } =
+            writer.write_with(|section| match section.push_pstr(src) {
+                None => empty_list_as_cell!(),
+                Some(cell) => cell,
+            });
 
-    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],
-        }
+        Ok(result)
     }
-    */
 
-    pub fn allocate_pstr(&mut self, src: &str) -> Result<Option<PStrWriteInfo>, usize> {
+    // note that allocate_cstr emits a tail cell to the string (completing it with the empty list)
+    // unlike any version of allocate_pstr.
+
+    pub fn allocate_cstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
         let size_in_heap = Self::compute_pstr_size(src);
-        let mut writer = self.reserve(size_in_heap)?;
+        let mut writer = self.reserve(size_in_heap + 1)?;
         let HeapSectionWriteResult { result, .. } =
-            writer.write_with(|section| section.push_pstr(src));
+            writer.write_with(|section| match section.push_pstr(src) {
+                None => empty_list_as_cell!(),
+                Some(cell) => {
+                    section.push_cell(empty_list_as_cell!());
+                    cell
+                }
+            });
 
-        Ok(result.map(|cell| PStrWriteInfo { cell }))
+        Ok(result)
     }
 
     pub const fn heap_cell_alignment() -> usize {
@@ -1007,7 +917,7 @@ impl Heap {
             // by at least two null bytes so one of them may be used
             // to mark partial strings e.g. during iteration
 
-            if (null_idx + 1) % ALIGN == 0 {
+            if (null_idx + 1).next_multiple_of(ALIGN) == null_idx + 1 {
                 byte_size += 2 * size_of::<HeapCellValue>();
             } else {
                 byte_size += size_of::<HeapCellValue>();
@@ -1107,27 +1017,6 @@ impl<'a> Iterator for PStrSegmentIter<'a> {
     }
 }
 
-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 { cell }) => Ok(cell),
-        }
-    }
-
-    // note that allocate_cstr emits a tail cell to the string (completing it with the empty list)
-    // unlike any version of allocate_pstr.
-    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 { cell }) => {
-                self.heap.push_cell(empty_list_as_cell!())?;
-                Ok(cell)
-            }
-        }
-    }
-}
-
 pub trait SizedHeap: Index<usize, Output = HeapCellValue> {
     // return the size of the instance in cells
     fn cell_len(&self) -> usize;
@@ -1141,8 +1030,6 @@ pub trait SizedHeap: Index<usize, Output = HeapCellValue> {
     // fn pstr_at(&self, cell_offset: usize) -> bool;
 }
 
-pub trait SizedHeapMut: IndexMut<usize, Output = HeapCellValue> + SizedHeap {}
-
 impl Index<usize> for Heap {
     type Output = HeapCellValue;
 
@@ -1183,8 +1070,6 @@ impl SizedHeap for Heap {
     }
 }
 
-impl SizedHeapMut for Heap {}
-
 // 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
index c139bc128237af8a3721275ea54f63a47dc0795c..66c1783ab248f37e40cf65abbec7625e82119ce8 100644 (file)
@@ -1,15 +1,18 @@
+use std::cmp::Ordering;
 use std::collections::BTreeMap;
+use std::rc::Rc;
 
 use crate::atom_table;
 use crate::heap_iter::{stackful_post_order_iter, NonListElider};
+use crate::machine::machine_indices::VarKey;
 use crate::machine::mock_wam::CompositeOpDir;
 use crate::machine::{
     ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC,
     LIB_QUERY_SUCCESS,
 };
-use crate::parser::ast::{TermWriteResult, Var};
-use crate::parser::lexer::LexerParser;
-use crate::parser::parser::Tokens;
+use crate::parser::ast::{Var, VarPtr};
+use crate::parser::parser::{Parser, Tokens};
+use crate::read::{write_term_to_heap, TermWriteResult};
 use crate::types::UntypedArenaPtr;
 
 use dashu::{Integer, Rational};
@@ -169,7 +172,7 @@ impl Term {
     pub(crate) fn from_heapcell(
         machine: &mut Machine,
         heap_cell: HeapCellValue,
-        var_names: &mut IndexMap<HeapCellValue, Var>,
+        var_names: &mut IndexMap<HeapCellValue, VarPtr>,
     ) -> Self {
         // Adapted from MachineState::read_term_from_heap
         let mut term_stack = vec![];
@@ -183,6 +186,16 @@ impl Term {
         );
 
         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,
+            },
+        };
 
         while let Some(addr) = iter.next() {
             let addr = unmark_cell_bits!(addr);
@@ -233,33 +246,34 @@ impl Term {
                     term_stack.push(list);
                 }
                 (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
-                    let var = var_names.get(&addr).cloned();
+                    let var = var_names.get(&addr).map(|x| x.borrow().clone());
                     match var {
-                        Some(name) => term_stack.push(Term::Var(name.to_string())),
+                        Some(Var::Named(name)) => term_stack.push(Term::Var(name.as_ref().to_owned())),
                         _ => {
                             let anon_name = loop {
                                 // Generate a name for the anonymous variable
-                                let anon_name = count_to_letter_code(anon_count);
+                                let anon_name = Rc::new(count_to_letter_code(anon_count));
 
                                 // Find if this name is already being used
-                                var_names.sort_by(|_, a, _, b| a.cmp(b));
-
+                                var_names.sort_by(|_, a, _, b| {
+                                    var_ptr_cmp(a.borrow().clone(), b.borrow().clone())
+                                });
                                 let binary_result = var_names.binary_search_by(|_,a| {
-                                    let a: &String = a.as_ref();
-                                    a.cmp(&anon_name)
+                                    let var_ptr = Var::Named(anon_name.clone());
+                                    var_ptr_cmp(a.borrow().clone(), var_ptr.clone())
                                 });
 
                                 match binary_result {
                                     Ok(_) => anon_count += 1, // Name already used
                                     Err(_) => {
                                         // Name not used, assign it to this variable
-                                        let var = anon_name.clone();
-                                        var_names.insert(addr, Var::from(var));
+                                        let var_ptr = VarPtr::from(Var::Named(anon_name.clone()));
+                                        var_names.insert(addr, var_ptr);
                                         break anon_name;
                                     },
                                 }
                             };
-                            term_stack.push(Term::Var(anon_name));
+                            term_stack.push(Term::Var(anon_name.as_ref().to_owned()));
                         },
                     }
                 }
@@ -401,7 +415,7 @@ pub struct QueryState<'a> {
     machine: &'a mut Machine,
     term: TermWriteResult,
     stub_b: usize,
-    var_names: IndexMap<HeapCellValue, Var>,
+    var_names: IndexMap<HeapCellValue, VarPtr>,
     called: bool,
 }
 
@@ -465,7 +479,7 @@ impl Iterator for QueryState<'_> {
         }
 
         if machine.machine_st.p == LIB_QUERY_SUCCESS {
-            if term_write_result.inverse_var_locs.is_empty() {
+            if term_write_result.var_dict.is_empty() {
                 self.machine.machine_st.backtrack();
                 return Some(Ok(LeafAnswer::True));
             }
@@ -474,39 +488,47 @@ impl Iterator for QueryState<'_> {
         }
 
         let mut bindings: BTreeMap<String, Term> = BTreeMap::new();
-        let inverse_var_locs = &term_write_result.inverse_var_locs;
 
-        for (var_loc, var_name) in inverse_var_locs.iter() {
+        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();
             if var_name.starts_with('_') {
-                let should_print = var_names.values().any(|v| v == var_name);
+                let should_print = var_names.values().any(|x| match x.borrow().clone() {
+                    Var::Named(v) => *v == *var_name,
+                    _ => false,
+                });
                 if !should_print {
                     continue;
                 }
             }
 
-            let var_loc = *var_loc;
-            let term =
-                Term::from_heapcell(machine, heap_loc_as_cell!(var_loc), &mut var_names.clone());
+            let mut term =
+                Term::from_heapcell(machine, *term_to_be_printed, &mut var_names.clone());
 
             if let Term::Var(ref term_str) = term {
-                if *term_str == **var_name {
+                if *term_str == var_name {
                     continue;
                 }
 
-                // inverse_var_locs is in the order things appear in
-                // the query. If var_name appears after term in the
-                // query, switch their places.
-                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(), Term::Var(var_name.to_string()));
-                    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::from(var_name.clone()).into()))
+                    .unwrap();
+                let term_idx =
+                    var_dict.get_index_of(&VarKey::VarPtr(Var::from(term_str.clone()).into()));
+                if let Some(idx) = term_idx {
+                    if idx < var_name_idx {
+                        let new_term = Term::Var(var_name);
+                        let new_var_name = term_str.into();
+                        term = new_term;
+                        var_name = new_var_name;
+                    }
                 }
             }
 
-            bindings.insert(var_name.to_string(), term);
+            bindings.insert(var_name, term);
         }
 
         // NOTE: there are outstanding choicepoints, backtrack
@@ -530,9 +552,9 @@ impl Machine {
     pub fn consult_module_string(&mut self, module_name: &str, program: impl Into<String>) {
         let stream = Stream::from_owned_string(program.into(), &mut self.machine_st.arena);
         self.machine_st.registers[1] = stream_as_cell!(stream);
-        self.machine_st.registers[2] = atom_as_cell!(atom_table::AtomTable::build_with(
+        self.machine_st.registers[2] = atom_as_cell!(&atom_table::AtomTable::build_with(
             &self.machine_st.atom_tbl,
-            module_name,
+            module_name
         ));
 
         self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2));
@@ -564,7 +586,7 @@ impl Machine {
 
     /// Runs a query.
     pub fn run_query(&mut self, query: impl Into<String>) -> QueryState {
-        let mut parser = LexerParser::new(
+        let mut parser = Parser::new(
             Stream::from_owned_string(query.into(), &mut self.machine_st.arena),
             &mut self.machine_st,
         );
@@ -575,10 +597,26 @@ impl Machine {
 
         self.allocate_stub_choice_point();
 
+        // Write parsed term to heap
+        let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap)
+            .expect("couldn't write term to heap");
+
+        let var_names: IndexMap<_, _> = term_write_result
+            .var_dict
+            .iter()
+            .map(|(var_key, cell)| match var_key {
+                // NOTE: not the intention behind Var::InSitu here but
+                // we can hijack it to store anonymous variables
+                // without creating problems.
+                VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))),
+                VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()),
+            })
+            .collect();
+
         // Write term to heap
-        self.machine_st.registers[1] = self.machine_st.heap[term.focus];
-        self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
+        self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc];
 
+        self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
         let call_index_p = self
             .indices
             .code_dir
@@ -587,22 +625,12 @@ impl Machine {
             .local()
             .unwrap();
 
-        let var_names: IndexMap<_, _> = term
-            .inverse_var_locs
-            .iter()
-            .map(|(var_loc, var)| {
-                let cell = self.machine_st.heap[*var_loc];
-                (cell, var.clone())
-            })
-            .collect();
-
         self.machine_st.execute_at_index(1, call_index_p);
 
         let stub_b = self.machine_st.b;
-
         QueryState {
             machine: self,
-            term,
+            term: term_write_result,
             stub_b,
             var_names,
             called: false,
index 9ac569725d57bbe41146d3e6e20009e30bcbf558..64d0bb827c43010890a21012da7bc74760dc6235 100644 (file)
@@ -1150,8 +1150,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                 let mut path_buf = PathBuf::from(&*filename.as_str());
                 path_buf.set_extension("pl");
 
-                let file = File::open(&path_buf)
-                    .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
+                let file = File::open(&path_buf)?;
 
                 (
                     Stream::from_file_as_input(
@@ -1232,8 +1231,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             ModuleSource::File(filename) => {
                 let mut path_buf = PathBuf::from(&*filename.as_str());
                 path_buf.set_extension("pl");
-                let file = File::open(&path_buf)
-                    .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
+                let file = File::open(&path_buf)?;
 
                 (
                     Stream::from_file_as_input(
index 0d850150b1d4ac906cf202bec774d5ef6389c751..c117887b0a3d09e20cb216df738f391dbf1d0869 100644 (file)
@@ -15,28 +15,12 @@ use crate::types::*;
 
 use indexmap::IndexSet;
 
+use std::cell::Cell;
 use std::collections::VecDeque;
 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,
-        })
-    }
-}
+use std::rc::Rc;
 
 /*
  * The loader compiles Prolog terms read from a TermStream instance,
@@ -194,18 +178,18 @@ impl CompilationTarget {
 }
 
 pub struct PredicateQueue {
-    pub predicates: Vec<TermWriteResult>,
-    pub compilation_target: CompilationTarget,
+    pub(super) predicates: Vec<Term>,
+    pub(super) compilation_target: CompilationTarget,
 }
 
 impl PredicateQueue {
     #[inline]
-    pub(super) fn push(&mut self, term_write_result: TermWriteResult) {
-        self.predicates.push(term_write_result);
+    pub(super) fn push(&mut self, clause: Term) {
+        self.predicates.push(clause);
     }
 
     #[inline]
-    pub(crate) fn first(&self) -> Option<&TermWriteResult> {
+    pub(crate) fn first(&self) -> Option<&Term> {
         self.predicates.first()
     }
 
@@ -416,7 +400,7 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
 
     #[inline(always)]
     fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState {
-        loader.term_stream.lexer_parser.machine_st
+        loader.term_stream.parser.lexer.machine_st
     }
 
     #[inline(always)]
@@ -508,9 +492,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         }
     }
 
-    #[inline]
-    pub(super) fn machine_heap(&mut self) -> &mut Heap {
-        &mut LS::machine_st(&mut self.payload).heap
+    pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Term {
+        let machine_st = LS::machine_st(&mut self.payload);
+        let cell = machine_st[r];
+
+        machine_st.read_term_from_heap(cell)
     }
 
     pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
@@ -527,30 +513,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             let compilation_target = &load_state.compilation_target;
             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);
-
-            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());
+            let term = load_state.term_stream.next(&composite_op_dir)?;
 
-                if term_key_opt != predicate_key_opt {
-                    self.compile_and_submit()?;
-                }
+            if !term.is_consistent(&load_state.predicates) {
+                self.compile_and_submit()?;
             }
 
-            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)?));
-            }
+            let term = match term {
+                Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => {
+                    return Ok(Some(setup_declaration(self, terms)?));
+                }
+                term => term,
+            };
 
             self.payload.predicates.push(term);
         }
@@ -788,7 +762,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                             ) => {
                                 remove_constant_indices(
                                     constant,
-                                    &overlapping_constants,
+                                    overlapping_constants,
                                     indexing_code,
                                     clause_loc - index_loc, // WAS: &inner_index_locs,
                                 );
@@ -1071,73 +1045,30 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         let machine_st = LS::machine_st(&mut self.payload);
         let cell = machine_st[r];
 
-        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 = machine_st.read_term_from_heap(cell);
         let export_list = setup_module_export_list(export_list)?;
 
         Ok(export_list.into_iter().collect())
     }
 
-    fn clause_clause(&mut self, cell: HeapCellValue) -> Result<TermWriteResult, CompilationError> {
-        let machine_st = LS::machine_st(&mut self.payload);
-        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();
-
-                let mut writer = machine_st.heap.reserve(4)
-                    .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+    fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> {
+        match term {
+            Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => {
+                let body = terms.pop().unwrap();
+                let head = terms.pop().unwrap();
 
-                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) => {
-                            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")));
-                        }
-                    }
-                });
+                self.payload.clause_clauses.push((head, body));
             }
-            (HeapCellValueTag::Atom, (name, arity)) => {
-                if arity == 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);
-                }
+            head @ (Term::Clause(..) | Term::Literal(_, Literal::Atom(_))) => {
+                let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
+                self.payload.clause_clauses.push((head, body));
             }
             _ => {
                 return Err(CompilationError::InadmissibleFact);
             }
-        );
+        }
 
-        Ok(
-            TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus))
-                .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?,
-        )
+        Ok(())
     }
 
     fn add_extensible_predicate_declaration(
@@ -1355,11 +1286,9 @@ 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 key_opt = clause_predicate_key_from_heap(&machine_st.heap, value);
-
-        if let Some((predicate_name, predicate_arity)) = key_opt {
+    fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
+        if let Some(predicate_name) = ClauseInfo::name(term) {
+            let predicate_arity = ClauseInfo::arity(term);
             let predicates_compilation_target = self.payload.predicates.compilation_target;
 
             let is_dynamic = self
@@ -1373,8 +1302,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                 .unwrap_or(false);
 
             if is_dynamic {
-                let clause_clause_term = self.clause_clause(value)?;
-                self.payload.clause_clauses.push(clause_clause_term);
+                self.add_clause_clause(term.clone())?;
             }
         }
 
@@ -1440,6 +1368,90 @@ impl<'a> MachinePreludeView<'a> {
     }
 }
 
+impl MachineState {
+    pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term {
+        let mut term_stack = vec![];
+        self.heap[0] = term_addr;
+        let mut iter =
+            stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
+
+        while let Some(addr) = iter.next() {
+            let addr = unmark_cell_bits!(addr);
+
+            if let Ok(literal) = Literal::try_from(addr) {
+                term_stack.push(Term::Literal(Cell::default(), literal));
+            } else {
+                read_heap_cell!(addr,
+                    (HeapCellValueTag::Lis) => {
+                        use crate::parser::parser::as_partial_string;
+
+                        let tail = term_stack.pop().unwrap();
+                        let head = term_stack.pop().unwrap();
+
+                        match as_partial_string(head, tail) {
+                            Ok((string, Some(tail))) => {
+                                term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail));
+                            }
+                            Ok((string, None)) => {
+                                term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string)));
+                            }
+                            Err(cons_term) => term_stack.push(cons_term),
+                        }
+                    }
+                    (HeapCellValueTag::StackVar, h) => {
+                        term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h))));
+                    }
+                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
+                        term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
+                    }
+                    (HeapCellValueTag::Atom, (name, arity)) => {
+                        let h = iter.focus().value() as usize;
+                        let mut arity = arity;
+                        let value = iter.heap[h.saturating_sub(1)];
+
+                        if let Some(idx) = get_structure_index(value) {
+                            term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
+                            arity += 1;
+                        }
+
+                        if arity == 0 {
+                            term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
+                        } else {
+                            let subterms = term_stack
+                                .drain(term_stack.len() - arity ..)
+                                .collect();
+
+                            term_stack.push(Term::Clause(Cell::default(), name, subterms));
+                        }
+                    }
+                    (HeapCellValueTag::PStrLoc, h) => {
+                        let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h);
+                        let tail = term_stack.pop().unwrap();
+
+                        term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) {
+                            Term::CompleteString(
+                                Cell::default(),
+                                Rc::new(string.to_owned()),
+                            )
+                        } else {
+                            Term::PartialString(
+                                Cell::default(),
+                                Rc::new(string.to_owned()),
+                                Box::new(tail),
+                            )
+                        });
+                    }
+                    _ => {
+                    }
+                );
+            }
+        }
+
+        debug_assert!(term_stack.len() == 1);
+        term_stack.pop().unwrap()
+    }
+}
+
 impl Machine {
     pub(crate) fn use_module(&mut self) -> CallResult {
         let subevacuable_addr = self
@@ -1600,15 +1612,11 @@ 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.read_term_from_heap(temp_v!(1));
+
             loader.incremental_compile_clause(
                 (atom!("term_expansion"), 2),
                 term,
@@ -1629,37 +1637,30 @@ impl Machine {
             .machine_st
             .store(self.machine_st.deref(self.machine_st.registers[1])));
 
+        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 value = self.machine_st.registers[2];
-        let term = resource_error_call_result!(
-            self.machine_st,
-            TermWriteResult::from(&mut self.machine_st.heap, value)
-        );
-
         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),
+            let term = loader.read_term_from_heap(temp_v!(2));
+
+            let indexing_arg = match term.name() {
+                Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg),
+                Some(_) => term.first_arg(),
                 None => None,
             };
 
-            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));
+            if let Some(indexing_term) = indexing_arg {
+                if let Some(indexing_name) = indexing_term.name() {
+                    loader
+                        .wam_prelude
+                        .indices
+                        .goal_expansion_indices
+                        .insert((indexing_name, indexing_term.arity()));
+                }
             }
 
             loader.incremental_compile_clause(
@@ -1964,21 +1965,29 @@ impl Machine {
         };
 
         let stub_gen = || functor_stub(key.0, key.1);
-        let assert_clause = self.machine_st.registers[2];
-        let key_opt = clause_predicate_key_from_heap(&self.machine_st.heap, assert_clause);
+        let head = self.deref_register(2);
+
+        if head.is_var() {
+            let err = self.machine_st.instantiation_error();
+            return Err(self.machine_st.error_form(err, stub_gen()));
+        }
 
-        let mut compile_assert = |assert_clause, key_opt| {
+        let mut compile_assert = || {
             let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
                 Loader::new(self, LiveTermStream::new(ListingSource::User));
 
             loader.payload.compilation_target = compilation_target;
 
-            let (name, arity) = if let Some(key) = key_opt {
-                key
+            let head =
+                LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head);
+
+            let name = if let Some(name) = head.name() {
+                name
             } else {
                 return Err(SessionError::from(CompilationError::InvalidRuleHead));
             };
 
+            let arity = head.arity();
             let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity));
 
             let is_dynamic_predicate = loader
@@ -2010,39 +2019,39 @@ impl Machine {
                 return LiveLoadAndMachineState::evacuate(loader);
             }
 
-            // if a new predicate was just created, make it dynamic.
-            loader.add_dynamic_predicate(compilation_target, name, arity)?;
+            let body = loader.read_term_from_heap(temp_v!(3));
 
-            let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload);
-            // let asserted_clause = loader.copy_term_from_heap(assert_clause);
+            let asserted_clause = Term::Clause(
+                Cell::default(),
+                atom!(":-"),
+                vec![head.clone(), body.clone()],
+            );
 
-            let term = TermWriteResult::from(&mut machine_st.heap, assert_clause)
-                .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+            // if a new predicate was just created, make it dynamic.
+            loader.add_dynamic_predicate(compilation_target, name, arity)?;
 
             loader.incremental_compile_clause(
                 (name, arity),
-                term,
+                asserted_clause,
                 compilation_target,
                 false,
                 append_or_prepend,
             )?;
 
-            let clause_clause_term = loader.clause_clause(assert_clause)?;
-
             // the global clock is incremented after each assertion.
             LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
 
             loader.compile_clause_clauses(
                 (name, arity),
                 compilation_target,
-                vec![clause_clause_term],
+                std::iter::once((head, body)),
                 append_or_prepend,
             )?;
 
             LiveLoadAndMachineState::evacuate(loader)
         };
 
-        match compile_assert(assert_clause, key_opt) {
+        match compile_assert() {
             Ok(_) => Ok(()),
             Err(SessionError::CompilationError(
                 CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact,
@@ -2244,23 +2253,11 @@ 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)
-                || !is_consistent;
+                || !key.is_consistent(&loader.payload.predicates);
 
         let result = LiveLoadAndMachineState::evacuate(loader);
         self.restore_load_state_payload(result)
@@ -2467,17 +2464,11 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
             self.payload.predicates.compilation_target = compilation_target;
         }
 
-        let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload);
-        let value = machine_st.store(MachineState::deref(machine_st, machine_st[term_reg]));
-
-        self.add_clause_clause_if_dynamic(value)?;
-
-        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()))?;
+        let term = self.read_term_from_heap(term_reg);
 
+        self.add_clause_clause_if_dynamic(&term)?;
         self.payload.term_stream.term_queue.push_back(term);
+
         self.load()
     }
 }
index 1a4e84879c8df9d524d3d7342e66e1fec3c25fc3..4551991e5cbe4b722873221ff6df9e1592fe935e 100644 (file)
@@ -19,7 +19,7 @@ pub type MachineStubGen = Box<dyn Fn(&mut MachineState) -> MachineStub>;
 #[derive(Debug)]
 pub(crate) struct MachineError {
     stub: MachineStub,
-    location: Option<ParserErrorSrc>,
+    location: Option<(usize, usize)>, // line_num, col_num
 }
 
 // from 7.12.2 b) of 13211-1:1995
@@ -301,7 +301,7 @@ impl MachineState {
         }
     }
 
-    pub(super) fn resource_error(&mut self, err: ResourceError) -> MachineError {
+    pub(super) fn resource_error(err: ResourceError) -> MachineError {
         let stub = match err {
             ResourceError::FiniteMemory(size_requested) => {
                 functor!(
@@ -466,10 +466,10 @@ impl MachineState {
     fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
         match err {
             ArithmeticError::NonEvaluableFunctor(cell, arity) => {
-                let culprit = functor!(atom!("/"), [cell(cell), fixnum(arity)]);
-
+                let culprit = functor!(atom!("/"), [literal(cell), fixnum(arity)]);
                 self.type_error(ValidType::Evaluable, culprit)
             }
+            ArithmeticError::UninstantiatedVar => self.instantiation_error(),
         }
     }
 
@@ -609,7 +609,7 @@ impl MachineState {
     }
 
     pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub {
-        if let Some(ParserErrorSrc { line_num, .. }) = err.location {
+        if let Some((line_num, _col_num)) = err.location {
             functor!(
                 atom!("error"),
                 [
@@ -665,16 +665,17 @@ pub enum CompilationError {
     InvalidRuleHead,
     InvalidUseModuleDecl,
     InvalidModuleResolution(Atom),
+    FiniteMemoryInHeap(usize),
 }
 
 #[derive(Debug)]
 pub enum DirectiveError {
-    ExpectedDirective(HeapCellValue),
+    ExpectedDirective(Term),
     InvalidDirective(Atom, usize /* arity */),
-    InvalidOpDeclNameType(HeapCellValue),
-    InvalidOpDeclSpecDomain(HeapCellValue),
+    InvalidOpDeclNameType(Term),
+    InvalidOpDeclSpecDomain(Term),
     InvalidOpDeclSpecValue(Atom),
-    InvalidOpDeclPrecType(HeapCellValue),
+    InvalidOpDeclPrecType(Term),
     InvalidOpDeclPrecDomain(Fixnum),
     ShallNotCreate(Atom),
     ShallNotModify(Atom),
@@ -695,9 +696,9 @@ impl From<ParserError> for CompilationError {
 }
 
 impl CompilationError {
-    pub(crate) fn line_and_col_num(&self) -> Option<ParserErrorSrc> {
+    pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> {
         match self {
-            CompilationError::ParserError(err) => Some(err.err_src()),
+            CompilationError::ParserError(err) => err.line_and_col_num(),
             _ => None,
         }
     }
@@ -740,6 +741,9 @@ impl CompilationError {
             CompilationError::ParserError(ref err) => {
                 functor!(err.as_atom())
             }
+            CompilationError::FiniteMemoryInHeap(h) => {
+                vec![FunctorElement::AbsoluteCell(str_loc_as_cell!(*h))]
+            }
         }
     }
 }
@@ -1015,6 +1019,13 @@ pub enum SessionError {
     PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
 }
 
+impl From<std::io::Error> for SessionError {
+    #[inline]
+    fn from(err: std::io::Error) -> SessionError {
+        SessionError::from(ParserError::from(err))
+    }
+}
+
 impl From<ParserError> for SessionError {
     #[inline]
     fn from(err: ParserError) -> Self {
index e0142b774768522345532d94447045ad3aa665bb..d4a10a8c19e9d50d4c515d6322672d2f20af7700 100644 (file)
@@ -21,8 +21,6 @@ use std::collections::BTreeSet;
 use std::ops::{Deref, DerefMut};
 
 use crate::types::*;
-// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-// pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
 
 // 7.2
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -223,6 +221,30 @@ impl CodeIndex {
     */
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum VarKey {
+    AnonVar(usize),
+    VarPtr(VarPtr),
+}
+
+impl VarKey {
+    #[allow(clippy::inherent_to_string)]
+    #[inline]
+    pub(crate) fn to_string(&self) -> String {
+        match self {
+            VarKey::AnonVar(h) => format!("_{}", h),
+            VarKey::VarPtr(var) => var.borrow().to_string(),
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn is_anon(&self) -> bool {
+        matches!(self, VarKey::AnonVar(_))
+    }
+}
+
+pub(crate) type HeapVarDict = IndexMap<VarKey, HeapCellValue, FxBuildHasher>;
+
 pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
 
 pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
@@ -279,9 +301,11 @@ impl IndexStore {
             _ => self
                 .get_meta_predicate_spec(key.0, key.1, &compilation_target)
                 .map(|meta_specs| {
-                    meta_specs.iter().find(|meta_spec| match meta_spec {
-                        MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) => true,
-                        _ => false,
+                    meta_specs.iter().find(|meta_spec| {
+                        matches!(
+                            meta_spec,
+                            MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_)
+                        )
                     })
                 })
                 .map(|meta_spec_opt| meta_spec_opt.is_some())
index 8c50c12853a058292cee64e013f4fcfbc36668a4..049f131cdf2f786d30d8c42b11dc50bfb6994830 100644 (file)
@@ -13,6 +13,7 @@ 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;
@@ -22,7 +23,6 @@ use indexmap::IndexMap;
 use std::convert::TryFrom;
 use std::fmt;
 use std::ops::{Index, IndexMut, Range};
-use std::rc::Rc;
 use std::sync::Arc;
 
 pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
@@ -72,7 +72,7 @@ pub struct MachineState {
     pub(super) e: usize,
     pub(super) num_of_args: usize,
     pub(super) cp: usize,
-    pub(crate) attr_var_init: AttrVarInitializer,
+    pub(super) attr_var_init: AttrVarInitializer,
     pub(super) fail: bool,
     pub heap: Heap,
     pub(super) mode: MachineMode,
@@ -203,52 +203,56 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
 }
 */
 
-fn push_var_eq_functors(
+// size may be an upper bound.
+// true_size is calculated to compute the exact offset.
+
+fn push_var_eq_functors<'a>(
     heap: &mut Heap,
     size: usize,
-    iter: impl Iterator<Item = (usize, Var)>,
+    iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
     atom_tbl: &AtomTable,
 ) -> Result<HeapCellValue, usize> {
     let src_h = heap.cell_len();
 
-    if size > 0 {
-        let mut writer = heap.reserve(1 + 5 * size)?;
+    let true_size = if size > 0 {
+        let mut writer = heap.reserve(2 + 5 * size)?;
 
-        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);
+        writer
+            .write_with(|section| {
+                let mut size = 0;
 
-                section.push_cell(atom_as_cell!(atom!("="), 2));
-                section.push_cell(atom_as_cell!(var_atom));
-                section.push_cell(binding);
-            }
+                for (var, binding) in iter {
+                    let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
 
-            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(atom_as_cell!(atom!("="), 2));
+                    section.push_cell(atom_as_cell!(var_atom));
+                    section.push_cell(*binding);
 
-            section.push_cell(empty_list_as_cell!());
-        });
+                    size += 1;
+                }
+
+                for idx in 0..size {
+                    section.push_cell(list_loc_as_cell!(section.cell_len() + 1));
+                    section.push_cell(str_loc_as_cell!(src_h + 3 * idx));
+                }
+
+                if size > 0 {
+                    section.push_cell(empty_list_as_cell!());
+                }
 
-        Ok(heap_loc_as_cell!(src_h + 3 * size))
+                size
+            })
+            .result
     } else {
-        Ok(empty_list_as_cell!())
-    }
-}
+        size
+    };
 
-/*
-pub(crate) fn copy_and_align_iter<Iter: Iterator<Item = HeapCellValue>>(
-    iter: Iter,
-    boundary: i64,
-    h: i64,
-) -> impl Iterator<Item = HeapCellValue> {
-    let diff = boundary - h;
-    iter.map(move |heap_value| heap_value - diff)
+    Ok(if true_size > 0 {
+        heap_loc_as_cell!(src_h + 3 * true_size)
+    } else {
+        empty_list_as_cell!()
+    })
 }
-*/
 
 #[derive(Debug)]
 pub struct Ball {
@@ -377,7 +381,7 @@ impl<'a> CopierTarget for CopyTerm<'a> {
 }
 
 #[derive(Debug)]
-pub(crate) struct CopyBallTerm<'a> {
+pub(super) struct CopyBallTerm<'a> {
     attr_var_queue: &'a mut Vec<usize>,
     stack: &'a mut Stack,
     heap: &'a mut Heap,
@@ -385,7 +389,7 @@ pub(crate) struct CopyBallTerm<'a> {
 }
 
 impl<'a> CopyBallTerm<'a> {
-    pub(crate) fn new(
+    pub(super) fn new(
         attr_var_queue: &'a mut Vec<usize>,
         stack: &'a mut Stack,
         heap: &'a mut Heap,
@@ -629,24 +633,13 @@ impl MachineState {
 
     pub fn write_read_term_options(
         &mut self,
-        mut var_list: Vec<(Var, HeapCellValue, usize)>,
-        singletons_heap_list: HeapCellValue,
+        mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
+        singleton_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];
-        unify_fn!(*self, singletons_heap_list, singleton_addr);
+        unify_fn!(*self, singleton_heap_list, singleton_addr);
 
         if self.fail {
             return Ok(());
@@ -669,21 +662,18 @@ 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()) }),
+                var_list.iter().filter_map(|(var_name, var, _)| {
+                    if var_name.is_anon() {
+                        None
+                    } else {
+                        Some((var_name, var))
+                    }
+                }),
                 &self.atom_tbl,
             )
         );
@@ -691,37 +681,22 @@ impl MachineState {
         Ok(unify_fn!(*self, var_names_offset, var_names_addr))
     }
 
-    pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult {
-        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)
-            }
-        );
-        */
-
+    pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
+        let heap_loc = heap_loc_as_cell!(term_write_result.heap_loc);
         unify_fn!(*self, heap_loc, self.registers[2]);
 
         if self.fail {
             return Ok(());
         }
 
-        /*
         for var in term_write_result.var_dict.values_mut() {
             *var = heap_bound_deref(&self.heap, *var);
         }
-        */
 
         let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
+        self.heap[0] = heap_loc;
 
-        for cell in
-            stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, term.focus)
-        {
+        for cell in stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0) {
             let cell = unmark_cell_bits!(cell);
 
             if let Some(var) = cell.as_var() {
@@ -737,38 +712,36 @@ impl MachineState {
             self,
             push_var_eq_functors(
                 &mut self.heap,
-                singleton_var_set
+                term_write_result.var_dict.len(),
+                term_write_result
+                    .var_dict
                     .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);
+                    .filter(|(var_name, binding)| {
+                        if var_name.is_anon() {
+                            return false;
+                        }
 
-                        if singleton_var_set.get(&r).cloned().unwrap_or(false) {
-                            Some((*var_loc, var_name.clone()))
+                        if let Some(r) = binding.as_var() {
+                            *singleton_var_set.get(&r).unwrap_or(&false)
                         } else {
-                            None
+                            false
                         }
                     }),
                 &self.atom_tbl,
             )
         );
 
-        let mut var_list = Vec::with_capacity(singleton_var_set.len());
+        for var in term_write_result.var_dict.values_mut() {
+            *var = heap_bound_deref(&self.heap, *var);
+        }
 
-        for (var_loc, var_name) in term.inverse_var_locs {
-            let r = Ref::heap_cell(var_loc);
-            let cell = self.heap[var_loc];
+        let mut var_list = Vec::with_capacity(singleton_var_set.len());
 
-            if let Some(idx) = singleton_var_set.get_index_of(&r) {
-                var_list.push((var_name, cell, idx));
+        for (var_name, addr) in term_write_result.var_dict {
+            if let Some(var) = addr.as_var() {
+                if let Some(idx) = singleton_var_set.get_index_of(&var) {
+                    var_list.push((var_name, addr, idx));
+                }
             }
         }
 
@@ -851,8 +824,8 @@ impl MachineState {
         }
 
         loop {
-            match self.read_to_heap(stream, &indices.op_dir) {
-                Ok(term) => return self.read_term_body(term),
+            match self.read(stream, &indices.op_dir) {
+                Ok(term_write_result) => return self.read_term_body(term_write_result),
                 Err(err) => {
                     match &err {
                         CompilationError::ParserError(e) if e.is_unexpected_eof() => {
@@ -891,7 +864,7 @@ impl MachineState {
 
         let printer = match self.try_from_list(self.registers[6], stub_gen) {
             Ok(addrs) => {
-                let mut var_names: IndexMap<HeapCellValue, Var> = IndexMap::new();
+                let mut var_names: IndexMap<HeapCellValue, VarPtr> = IndexMap::new();
 
                 for addr in addrs {
                     read_heap_cell!(addr,
@@ -910,14 +883,14 @@ impl MachineState {
                                 read_heap_cell!(atom,
                                     (HeapCellValueTag::Atom, (name, _arity)) => {
                                         debug_assert_eq!(_arity, 0);
-                                        var_names.insert(var, Rc::new(name.as_str().to_owned()));
+                                        var_names.insert(var, VarPtr::from(name.as_str().to_owned()));
                                     }
                                     (HeapCellValueTag::Str, s) => {
                                         let (name, arity) = cell_as_atom_cell!(self.heap[s])
                                             .get_name_and_arity();
 
                                         debug_assert_eq!(arity, 0);
-                                        var_names.insert(var, Rc::new(name.as_str().to_owned()));
+                                        var_names.insert(var, VarPtr::from(name.as_str().to_owned()));
                                     }
                                     _ => {
                                         unreachable!();
@@ -996,18 +969,14 @@ impl MachineState {
                     }
                 );
 
-                let term_loc = self.heap.cell_len();
-
-                step_or_resource_error!(self, self.heap.push_cell(term_to_be_printed), {
-                    return Ok(None);
-                });
+                self.heap[0] = term_to_be_printed;
 
                 let mut printer = HCPrinter::new(
                     &mut self.heap,
                     &mut self.stack,
                     op_dir,
                     PrinterOutputter::new(),
-                    term_loc,
+                    0,
                 );
 
                 printer.ignore_ops = ignore_ops;
@@ -1040,7 +1009,6 @@ impl MachineState {
                 }
 
                 printer.var_names = var_names;
-
                 printer
             }
             Err(err) => {
index ef1d32dc275cf78636c766dced21b7699bff8d77..bd041f36b0016306bf355b6bbae8228b14895710 100644 (file)
@@ -621,10 +621,17 @@ impl MachineState {
                         (HeapCellValueTag::PStrLoc, l1) => {
                             read_heap_cell!(v2,
                                 (HeapCellValueTag::PStrLoc, l2) => {
-                                    let cmp_result = self.heap.compare_pstr_segments(l1, l2);
-
-                                    if let Some(ordering) = cmp_result.continue_pstr_compare(&mut self.pdl) {
-                                        return Some(ordering);
+                                    match self.heap.compare_pstr_segments(l1, l2) {
+                                        PStrSegmentCmpResult::Continue(v1, v2) => {
+                                            self.pdl.push(v1);
+                                            self.pdl.push(v2);
+                                        }
+                                        PStrSegmentCmpResult::Less => {
+                                            return Some(Ordering::Less);
+                                        }
+                                        PStrSegmentCmpResult::Greater => {
+                                            return Some(Ordering::Greater);
+                                        }
                                     }
                                 }
                                 (HeapCellValueTag::Lis, l2) => {
@@ -747,38 +754,6 @@ impl MachineState {
         Some(Ordering::Equal)
     }
 
-    /* TODO: new, inlined match_partial_string. now inlined into GetPartialString,
-     * the only place it is called from. Therefore, it has been inlined.
-
-    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(PStrCmpResult::PartialMatch { string, var_loc }) => {
-                let cell = self.heap.allocate_pstr(string)?;
-                unify!(self, cell, heap_loc_as_loc!(var_loc));
-            }
-            None => {
-                self.fail = true;
-            }
-        }
-
-        Ok(())
-    }
-    */
-
     pub(crate) fn setup_call_n_init_goal_info(
         &mut self,
         goal: HeapCellValue,
index 32c4cf59fb2dffefcebb98e0ea822e1e033cb1da..a372e0af977921401a9054e0389aab0c40f0beb8 100644 (file)
@@ -7,6 +7,7 @@ pub use crate::parser::ast::*;
 
 #[cfg(test)]
 use crate::machine::copier::CopierTarget;
+use crate::read::TermWriteResult;
 
 #[cfg(test)]
 use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
@@ -34,7 +35,7 @@ impl MockWAM {
         &mut self,
         input_stream: Stream,
     ) -> Result<TermWriteResult, CompilationError> {
-        self.machine_st.read_to_heap(input_stream, &self.op_dir)
+        self.machine_st.read(input_stream, &self.op_dir)
     }
 
     pub fn parse_and_write_parsed_term_to_heap(
@@ -50,24 +51,24 @@ impl MockWAM {
         term_string: &'static str,
     ) -> Result<String, CompilationError> {
         let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
-
-        print_heap_terms(&self.machine_st.heap, term_write_result.focus);
-
-        let var_names = term_write_result
-            .inverse_var_locs
-            .iter()
-            .map(|(var_loc, var_name)| (self.machine_st.heap[*var_loc], var_name.clone()))
-            .collect();
+        print_heap_terms(&self.machine_st.heap, term_write_result.heap_loc);
 
         let mut printer = HCPrinter::new(
             &mut self.machine_st.heap,
             &mut self.machine_st.stack,
             &self.op_dir,
             PrinterOutputter::new(),
-            term_write_result.focus,
+            term_write_result.heap_loc,
         );
 
-        printer.var_names = var_names;
+        printer.var_names = term_write_result
+            .var_dict
+            .into_iter()
+            .map(|(var, cell)| match var {
+                VarKey::VarPtr(var) => (cell, var.clone()),
+                VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string())),
+            })
+            .collect();
 
         Ok(printer.print().result())
     }
@@ -238,7 +239,7 @@ pub(crate) fn write_parsed_term_to_heap(
     input_stream: Stream,
     op_dir: &OpDir,
 ) -> Result<TermWriteResult, CompilationError> {
-    machine_st.read_to_heap(input_stream, op_dir)
+    machine_st.read(input_stream, op_dir)
 }
 
 #[cfg(test)]
@@ -298,7 +299,7 @@ mod tests {
             unify!(
                 wam,
                 str_loc_as_cell!(0),
-                str_loc_as_cell!(term_write_result_2.focus)
+                str_loc_as_cell!(term_write_result_2.heap_loc)
             );
 
             assert!(wam.fail);
@@ -310,16 +311,15 @@ mod tests {
         wam.heap.clear();
 
         {
-            let term_write_result_1 =
-                parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+            parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
 
             let term_write_result_2 =
                 parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.focus),
-                heap_loc_as_cell!(term_write_result_2.focus)
+                str_loc_as_cell!(1),
+                heap_loc_as_cell!(term_write_result_2.heap_loc)
             );
 
             assert!(!wam.fail);
@@ -331,16 +331,15 @@ mod tests {
         wam.heap.clear();
 
         {
-            let term_write_result_1 =
-                parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+            parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
 
             let term_write_result_2 =
                 parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.focus),
-                heap_loc_as_cell!(term_write_result_2.focus)
+                heap_loc_as_cell!(0),
+                heap_loc_as_cell!(term_write_result_2.heap_loc)
             );
 
             assert!(!wam.fail);
@@ -352,16 +351,15 @@ mod tests {
         wam.heap.clear();
 
         {
-            let term_write_result_1 =
-                parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+            parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
 
             let term_write_result_2 =
                 parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.focus),
-                heap_loc_as_cell!(term_write_result_2.focus)
+                heap_loc_as_cell!(0),
+                heap_loc_as_cell!(term_write_result_2.heap_loc)
             );
 
             assert!(!wam.fail);
@@ -373,16 +371,15 @@ mod tests {
         wam.heap.clear();
 
         {
-            let term_write_result_1 =
-                parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+            parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
 
             let term_write_result_2 =
                 parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.focus),
-                heap_loc_as_cell!(term_write_result_2.focus)
+                heap_loc_as_cell!(0),
+                heap_loc_as_cell!(term_write_result_2.heap_loc)
             );
 
             assert!(!wam.fail);
@@ -394,8 +391,7 @@ mod tests {
         wam.heap.clear();
 
         {
-            let term_write_result_1 =
-                parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+            parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
 
             let term_write_result_2 =
                 parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
@@ -404,8 +400,8 @@ mod tests {
 
             unify!(
                 wam,
-                heap_loc_as_cell!(term_write_result_1.focus),
-                heap_loc_as_cell!(term_write_result_2.focus)
+                heap_loc_as_cell!(0),
+                heap_loc_as_cell!(term_write_result_2.heap_loc)
             );
 
             assert!(!wam.fail);
@@ -526,8 +522,21 @@ mod tests {
         });
 
         unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
+
         assert!(!wam.fail);
         all_cells_unmarked(&wam.heap);
+        wam.heap.clear();
+
+        {
+            let term_write_result_1 =
+                parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
+
+            print_heap_terms(&wam.heap, term_write_result_1.heap_loc);
+
+            unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
+
+            assert_eq!(wam.heap[2], str_loc_as_cell!(4));
+        }
     }
 
     #[test]
@@ -550,8 +559,8 @@ mod tests {
 
             unify_with_occurs_check!(
                 wam,
-                heap_loc_as_cell!(0),
-                heap_loc_as_cell!(term_write_result_2.focus)
+                str_loc_as_cell!(0),
+                str_loc_as_cell!(term_write_result_2.heap_loc)
             );
 
             assert!(wam.fail);
@@ -594,7 +603,7 @@ mod tests {
             Some(Ordering::Equal)
         );
 
-        let cstr_cell = wam.allocate_cstr("string").unwrap();
+        let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
 
         assert_eq!(
             compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell),
@@ -693,7 +702,7 @@ mod tests {
             Some(Ordering::Greater)
         );
 
-        let cstr_cell = wam.allocate_cstr("string").unwrap();
+        let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
 
         assert_eq!(
             compare_term_test!(wam, empty_list_as_cell!(), cstr_cell),
@@ -782,7 +791,7 @@ mod tests {
         wam.heap.clear();
 
         let h = wam.heap.cell_len();
-        wam.allocate_cstr("a string").unwrap();
+        wam.heap.allocate_cstr("a string").unwrap();
 
         assert!(!wam.is_cyclic_term(h));
     }
index 02471f251b7bfcf671fa5ffba919cf49e8093e62..98b70ca62a57faf75b36f816110a283db54c376c 100644 (file)
@@ -1114,7 +1114,6 @@ impl Machine {
             if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
                 self.try_execute(name, arity, idx.get())
             } else {
-                println!("aaand undefined!");
                 self.undefined_procedure(name, arity)
             }
         } else if let Some(module) = self.indices.modules.get(&module_name) {
index 9484bf400d754b5b8654f1f764e136b01bbf493f..43163ce20c8d2262d4c3e6751aad5fe0e47ec9c5 100644 (file)
@@ -363,7 +363,7 @@ mod test {
     fn pstr_iter_tests() {
         let mut wam = MockWAM::new();
 
-        let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap();
+        let pstr_cell = wam.machine_st.heap.allocate_pstr("abc ").unwrap();
         wam.machine_st
             .heap
             .push_cell(empty_list_as_cell!())
@@ -391,7 +391,7 @@ mod test {
 
         wam.machine_st.heap[2] = pstr_loc_as_cell!(heap_index!(3));
 
-        wam.machine_st.allocate_pstr("def").unwrap();
+        wam.machine_st.heap.allocate_pstr("def").unwrap();
         let h = wam.machine_st.heap.cell_len();
 
         wam.machine_st.heap.push_cell(heap_loc_as_cell!(h)).unwrap();
@@ -456,7 +456,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap();
+        let pstr_cell = wam.machine_st.heap.allocate_cstr("abc").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -484,7 +484,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap();
+        let pstr_cell = wam.machine_st.heap.allocate_cstr("abc").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -515,7 +515,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        let pstr_cell = wam.machine_st.allocate_cstr("d").unwrap();
+        let pstr_cell = wam.machine_st.heap.allocate_cstr("d").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -534,7 +534,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap();
+        let pstr_cell = wam.machine_st.heap.allocate_cstr("abc").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -564,7 +564,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        let pstr_cell = wam.machine_st.allocate_cstr("abcdef").unwrap();
+        let pstr_cell = wam.machine_st.heap.allocate_cstr("abcdef").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -602,7 +602,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.allocate_cstr("abc").unwrap();
+        wam.machine_st.heap.allocate_cstr("abc").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -629,7 +629,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.allocate_cstr("a ").unwrap();
+        wam.machine_st.heap.allocate_cstr("a ").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -653,7 +653,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.allocate_cstr(" a").unwrap();
+        wam.machine_st.heap.allocate_cstr(" a").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -678,7 +678,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.allocate_cstr("a b").unwrap();
+        wam.machine_st.heap.allocate_cstr("a b").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -706,7 +706,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.allocate_cstr(" a ").unwrap();
+        wam.machine_st.heap.allocate_cstr(" a ").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -733,7 +733,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.allocate_cstr(" a bc").unwrap();
+        wam.machine_st.heap.allocate_cstr(" a bc").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -764,7 +764,7 @@ mod test {
 
         wam.machine_st.heap.clear();
 
-        wam.machine_st.allocate_cstr("abc").unwrap();
+        wam.machine_st.heap.allocate_cstr("abc").unwrap();
         let start = wam.machine_st.heap.cell_len();
 
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -791,7 +791,7 @@ mod test {
         // #2293, test7.
 
         wam.machine_st.heap.clear();
-        wam.machine_st.allocate_cstr("abcde").unwrap();
+        wam.machine_st.heap.allocate_cstr("abcde").unwrap();
 
         let start = wam.machine_st.heap.cell_len();
         let mut writer = wam.machine_st.heap.reserve(16).unwrap();
index ff64494a33531315aed36d364a4c2f67ed2a1d48..9ee332ed1d4db656e8093764fc11caf5dfdeb731 100644 (file)
@@ -3,17 +3,13 @@ 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;
 use crate::parser::ast::*;
-use crate::types::*;
 
-use fxhash::FxBuildHasher;
-use indexmap::IndexMap;
 use indexmap::IndexSet;
 
+use std::cell::Cell;
 use std::convert::TryFrom;
 pub(crate) fn to_op_decl(prec: u16, spec: OpDeclSpec, name: Atom) -> OpDecl {
     OpDecl::new(OpDesc::build_with(prec, spec), name)
@@ -25,47 +21,43 @@ 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_predicate_key(term.heap, focus + 3) {
-        Some((name, 0)) => name,
-        _ => {
+fn setup_op_decl(mut terms: Vec<Term>) -> Result<OpDecl, CompilationError> {
+    // should allow non-partial lists?
+    let name = match terms.pop().unwrap() {
+        Term::Literal(_, Literal::Atom(name)) => name,
+        other => {
             return Err(CompilationError::InvalidDirective(
-                DirectiveError::InvalidOpDeclNameType(term.heap[focus + 3]),
+                DirectiveError::InvalidOpDeclNameType(other),
             ));
         }
     };
 
-    let spec = match term_predicate_key(term.heap, focus + 2) {
-        Some((name, _)) => name,
-        None => {
+    let spec = match terms.pop().unwrap() {
+        Term::Literal(_, Literal::Atom(name)) => name,
+        other => {
             return Err(CompilationError::InvalidDirective(
-                DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus + 2]),
-            ));
+                DirectiveError::InvalidOpDeclSpecDomain(other),
+            ))
         }
     };
 
     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::InvalidDirective(
-                        DirectiveError::InvalidOpDeclPrecDomain(n),
-                    ));
-                }
+    let prec = match terms.pop().unwrap() {
+        Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) {
+            Ok(n) if n <= 1200 => n,
+            _ => {
+                return Err(CompilationError::InvalidDirective(
+                    DirectiveError::InvalidOpDeclPrecDomain(bi),
+                ));
             }
-        }
-        _ => {
+        },
+        other => {
             return Err(CompilationError::InvalidDirective(
-                DirectiveError::InvalidOpDeclPrecType(prec),
+                DirectiveError::InvalidOpDeclPrecType(other),
             ));
         }
-    );
+    };
 
     if name == "[]" || name == "{}" {
         return Err(CompilationError::InvalidDirective(
@@ -88,162 +80,129 @@ fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> {
     Ok(to_op_decl(prec, spec, name))
 }
 
-fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result<PredicateKey, CompilationError> {
-    let key_opt = term_predicate_key(term.heap, term.focus);
-
-    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)) {
-            Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
-            Ok(Number::Integer(n)) => (&*n).try_into().ok(),
-            _ => None,
-        }
-        .ok_or(CompilationError::InvalidModuleExport)?;
+fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
+    match term {
+        Term::Clause(_, slash, ref mut terms)
+            if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 =>
+        {
+            let arity = terms.pop().unwrap();
+            let name = terms.pop().unwrap();
+
+            let arity = match arity {
+                Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(),
+                Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
+                _ => None,
+            }
+            .ok_or(CompilationError::InvalidModuleExport)?;
 
-        let name_loc = term.nth_arg(term.focus, 1).unwrap();
-        let name = term_predicate_key(term.heap, name_loc)
-            .map(|(name, _)| name)
+            let name = match name {
+                Term::Literal(_, Literal::Atom(name)) => Some(name),
+                _ => None,
+            }
             .ok_or(CompilationError::InvalidModuleExport)?;
 
-        if matches!(key_opt, Some((atom!("/"), _))) {
-            Ok((name, arity))
-        } else {
-            Ok((name, arity + 2))
+            if *slash == atom!("/") {
+                Ok((name, arity))
+            } else {
+                Ok((name, arity + 2))
+            }
         }
-    } else {
-        Err(CompilationError::InvalidModuleExport)
+        _ => Err(CompilationError::InvalidModuleExport),
     }
 }
 
-fn setup_module_export(term: &FocusedHeapRefMut) -> Result<ModuleExport, CompilationError> {
-    setup_predicate_indicator(term)
+fn setup_module_export(mut term: Term) -> Result<ModuleExport, CompilationError> {
+    setup_predicate_indicator(&mut term)
         .map(ModuleExport::PredicateKey)
         .or_else(|_| {
-            let key_opt = term_predicate_key(term.heap, term.focus);
-
-            if let Some((atom!("op"), 3)) = key_opt {
-                Ok(ModuleExport::OpDecl(setup_op_decl(term)?))
+            if let Term::Clause(_, name, terms) = term {
+                if terms.len() == 3 && name == atom!("op") {
+                    Ok(ModuleExport::OpDecl(setup_op_decl(terms)?))
+                } else {
+                    Err(CompilationError::InvalidModuleDecl)
+                }
             } else {
                 Err(CompilationError::InvalidModuleDecl)
             }
         })
 }
 
-/* TODO: should be unnecessary now.
-
 pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
     let head_term = Term::Clause(Cell::default(), atom!(""), vars.to_vec());
     let rule = vec![head_term, body_term];
 
     Term::Clause(Cell::default(), atom!(":-"), rule)
 }
-*/
 
 pub(super) fn setup_module_export_list(
-    term: FocusedHeapRefMut,
+    mut export_list: Term,
 ) -> Result<Vec<ModuleExport>, CompilationError> {
     let mut exports = vec![];
-    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;
-            }
-        );
+
+    while let Term::Cons(_, t1, t2) = export_list {
+        let module_export = setup_module_export(*t1)?;
+
+        exports.push(module_export);
+        export_list = *t2;
     }
 
-    Err(CompilationError::InvalidModuleDecl)
+    if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
+        Ok(exports)
+    } else {
+        Err(CompilationError::InvalidModuleDecl)
+    }
 }
 
-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)?;
+fn setup_module_decl(mut terms: Vec<Term>) -> Result<ModuleDecl, CompilationError> {
+    let export_list = terms.pop().unwrap();
+    let name = terms.pop().unwrap();
 
-    term.focus = term.focus + 2;
-    let exports = setup_module_export_list(term)?;
+    let name = match name {
+        Term::Literal(_, Literal::Atom(name)) => Some(name),
+        _ => None,
+    }
+    .ok_or(CompilationError::InvalidModuleDecl)?;
 
+    let exports = setup_module_export_list(export_list)?;
     Ok(ModuleDecl { name, exports })
 }
 
-fn setup_use_module_decl(term: &FocusedHeapRefMut) -> Result<ModuleSource, CompilationError> {
-    read_heap_cell!(term.deref_loc(term.focus+1),
-        (HeapCellValueTag::Str, s) => {
-            let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity();
-
-            if (name, arity) == (atom!("library"), 1) {
-                read_heap_cell!(term.deref_loc(s+1),
-                    (HeapCellValueTag::Atom, (name, arity)) => {
-                        if arity == 0 {
-                            return Ok(ModuleSource::Library(name));
-                        }
-                    }
-                    _ => {
-                    }
-                )
-            }
-
-            return Err(CompilationError::InvalidModuleDecl);
-        }
-        (HeapCellValueTag::Atom, (name, arity)) => {
-            if arity == 0 {
-                Ok(ModuleSource::File(name))
-            } else {
-                Err(CompilationError::InvalidUseModuleDecl)
+fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
+    match terms.pop().unwrap() {
+        Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
+            match terms.pop().unwrap() {
+                Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
+                _ => Err(CompilationError::InvalidModuleDecl),
             }
         }
-        _ => {
-            Err(CompilationError::InvalidUseModuleDecl)
-        }
-    )
+        Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
+        _ => Err(CompilationError::InvalidUseModuleDecl),
+    }
 }
 
 type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
 
-fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, CompilationError> {
-    let module_src = setup_use_module_decl(&term)?;
-    let mut exports = IndexSet::new();
-
-    let mut focus = term.focus + 2;
-
-    while let HeapCellValueTag::Lis = term.heap[focus].get_tag() {
-        focus = term.heap[focus].get_value() as usize;
+fn setup_qualified_import(mut terms: Vec<Term>) -> Result<UseModuleExport, CompilationError> {
+    let mut export_list = terms.pop().unwrap();
+    let module_src = match terms.pop().unwrap() {
+        Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
+            match terms.pop().unwrap() {
+                Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
+                _ => Err(CompilationError::InvalidModuleDecl),
+            }
+        }
+        Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
+        _ => Err(CompilationError::InvalidUseModuleDecl),
+    }?;
 
-        let term = FocusedHeapRefMut {
-            heap: term.heap,
-            focus,
-        };
+    let mut exports = IndexSet::new();
 
-        exports.insert(setup_module_export(&term)?);
-        focus = focus + 1;
+    while let Term::Cons(_, t1, t2) = export_list {
+        exports.insert(setup_module_export(*t1)?);
+        export_list = *t2;
     }
 
-    if term.heap[focus] == empty_list_as_cell!() {
+    if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
         Ok((module_src, exports))
     } else {
         Err(CompilationError::InvalidModuleDecl)
@@ -290,20 +249,18 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, Co
  */
 
 fn setup_meta_predicate<'a, LS: LoadState<'a>>(
-    term: TermWriteResult,
+    mut terms: Vec<Term>,
     loader: &mut Loader<'a, LS>,
 ) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
-    fn get_meta_specs(
-        term: FocusedHeapRefMut,
-        arity: usize,
-    ) -> Result<Vec<MetaSpec>, CompilationError> {
+    fn get_name_and_meta_specs(
+        name: Atom,
+        terms: &mut [Term],
+    ) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
         let mut meta_specs = vec![];
 
-        for meta_spec_loc in term.focus + 1..term.focus + arity + 1 {
-            read_heap_cell!(term.deref_loc(meta_spec_loc),
-                (HeapCellValueTag::Atom, (meta_spec, arity)) => {
-                    debug_assert_eq!(arity, 0);
-
+        for meta_spec in terms.iter_mut() {
+            match meta_spec {
+                Term::Literal(_, Literal::Atom(meta_spec)) => {
                     let meta_spec = match meta_spec {
                         atom!("+") => MetaSpec::Plus,
                         atom!("-") => MetaSpec::Minus,
@@ -314,322 +271,263 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
 
                     meta_specs.push(meta_spec);
                 }
-                (HeapCellValueTag::Fixnum, n) => {
-                    match usize::try_from(n.get_num()) {
-                        Ok(n) if n <= MAX_ARITY => {
-                            meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
-                        }
-                        _ => {
-                            return Err(CompilationError::InvalidMetaPredicateDecl);
-                        }
+                Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
+                    Ok(n) if n <= MAX_ARITY => {
+                        meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
                     }
-                }
+                    _ => {
+                        return Err(CompilationError::InvalidMetaPredicateDecl);
+                    }
+                },
                 _ => {
                     return Err(CompilationError::InvalidMetaPredicateDecl);
                 }
-            );
+            }
         }
 
-        Ok(meta_specs)
+        Ok((name, meta_specs))
     }
 
-    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!(heap[s]).get_name_and_arity();
-
-            match (name, arity) {
-                (atom!(":"), 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!(heap[s])
-                                            .get_name_and_arity();
-
-                                        let term = FocusedHeapRefMut { heap, focus: s };
-                                        return Ok((module_name, name, get_meta_specs(term, arity)?));
-                                    }
-                                    _ => {
-                                    }
-                                );
-                            } else {
-                                return Err(CompilationError::InvalidMetaPredicateDecl);
-                            }
-                        }
-                        _ => {
-                        }
-                    );
-                }
-                _ => {
-                    let term = FocusedHeapRefMut { heap, focus: s };
-                    let specs = get_meta_specs(term, arity)?;
-                    let module_name = loader.payload.compilation_target.module_name();
+    match terms.pop().unwrap() {
+        Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => {
+            let spec = terms.pop().unwrap();
+            let module_name = terms.pop().unwrap();
 
-                    return Ok((module_name, name, specs));
-                }
+            match module_name {
+                Term::Literal(_, Literal::Atom(module_name)) => match spec {
+                    Term::Clause(_, name, mut terms) => {
+                        let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
+                        Ok((module_name, name, meta_specs))
+                    }
+                    _ => Err(CompilationError::InvalidMetaPredicateDecl),
+                },
+                _ => Err(CompilationError::InvalidMetaPredicateDecl),
             }
-
-            Err(CompilationError::InvalidMetaPredicateDecl)
         }
-        _ => {
-            Err(CompilationError::InvalidMetaPredicateDecl)
+        Term::Clause(_, name, mut terms) => {
+            let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
+            Ok((
+                loader.payload.compilation_target.module_name(),
+                name,
+                meta_specs,
+            ))
         }
-    )
+        _ => Err(CompilationError::InvalidMetaPredicateDecl),
+    }
 }
 
 pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
     loader: &mut Loader<'a, LS>,
-    mut term: TermWriteResult,
+    mut terms: Vec<Term>,
 ) -> Result<Declaration, CompilationError> {
-    let mut focus = term.focus;
-    let machine_st = LS::machine_st(&mut loader.payload);
-
-    loop {
-        let decl = machine_st.heap[focus];
+    let term = terms.pop().unwrap();
 
-        read_heap_cell!(decl,
-            (HeapCellValueTag::Atom, (name, arity)) => {
-                let mut focused = FocusedHeapRefMut::from(&mut machine_st.heap, focus);
-
-                return match (name, arity) {
-                    (atom!("dynamic"), 1) => {
-                        let (name, arity) = setup_predicate_indicator(&focused)?;
-                        Ok(Declaration::Dynamic(name, arity))
-                    }
-                    (atom!("module"), 2) => {
-                        Ok(Declaration::Module(setup_module_decl(focused)?))
-                    }
-                    (atom!("op"), 3) => {
-                        Ok(Declaration::Op(setup_op_decl(&focused)?))
-                    }
-                    (atom!("non_counted_backtracking"), 1) => {
-                        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(&focused)?)),
-                    (atom!("use_module"), 2) => {
-                        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))
-                    }
-                    _ => Err(CompilationError::InvalidDirective(
-                        DirectiveError::InvalidDirective(name, arity)
-                    ))
-                };
+    match term {
+        Term::Clause(_, name, mut terms) => match (name, terms.len()) {
+            (atom!("dynamic"), 1) => {
+                let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
+                Ok(Declaration::Dynamic(name, arity))
             }
-            (HeapCellValueTag::Str, s) => {
-                focus = s;
+            (atom!("module"), 2) => Ok(Declaration::Module(setup_module_decl(terms)?)),
+            (atom!("op"), 3) => Ok(Declaration::Op(setup_op_decl(terms)?)),
+            (atom!("non_counted_backtracking"), 1) => {
+                let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
+                Ok(Declaration::NonCountedBacktracking(name, arity))
             }
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                if focus != h {
-                    focus = h;
-                } else {
-                    return Err(CompilationError::InvalidDirective(
-                        DirectiveError::ExpectedDirective(decl),
-                    ));
-                }
+            (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
+            (atom!("use_module"), 2) => {
+                let (name, exports) = setup_qualified_import(terms)?;
+                Ok(Declaration::UseQualifiedModule(name, exports))
             }
-            _ => {
-                return Err(CompilationError::InvalidDirective(
-                    DirectiveError::ExpectedDirective(decl),
-                ));
+            (atom!("meta_predicate"), 1) => {
+                let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
+                Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
             }
-        );
+            _ => Err(CompilationError::InvalidDirective(
+                DirectiveError::InvalidDirective(name, terms.len()),
+            )),
+        },
+        other => Err(CompilationError::InvalidDirective(
+            DirectiveError::ExpectedDirective(other),
+        )),
     }
 }
 
 fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
     loader: &mut Loader<'a, LS>,
     module_name: Atom,
-    arity: usize,
-    term: &TermWriteResult,
+    terms: Vec<Term>,
     meta_specs: Vec<MetaSpec>,
-) -> IndexMap<usize, CodeIndex, FxBuildHasher> {
-    use crate::machine::heap::Heap;
-    let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default());
-
-    let focus = {
-        let heap = loader.machine_heap();
-        let focus_cell =
-            heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(term.focus)));
-
-        if focus_cell.get_tag() == HeapCellValueTag::Str {
-            focus_cell.get_value() as usize
-        } else {
-            return index_ptrs;
-        }
-    };
+) -> Vec<Term> {
+    let mut arg_terms = Vec::with_capacity(terms.len());
 
-    for (subterm_loc, meta_spec) in (focus + 1..focus + arity + 1).zip(meta_specs) {
+    for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) {
         if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
-            let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc);
-
-            if let Some((name, arity)) = predicate_key_opt {
+            if let Some(name) = term.name() {
                 if name == atom!("$call") {
+                    arg_terms.push(term);
                     continue;
                 }
 
-                struct QualifiedNameInfo {
-                    module_name: Atom,
-                    name: Atom,
-                    arity: usize,
-                    qualified_term_loc: usize,
-                }
+                let arity = term.arity();
 
                 fn get_qualified_name(
-                    heap: &Heap,
-                    module_term_loc: usize,
-                    qualified_term_loc: usize,
-                ) -> Option<QualifiedNameInfo> {
-                    let (module_term_loc, _) = subterm_index(heap, module_term_loc);
-                    let (qualified_term_loc, _) = subterm_index(heap, qualified_term_loc);
-
-                    read_heap_cell!(heap[module_term_loc],
-                        (HeapCellValueTag::Atom, (module_name, arity)) => {
-                            if arity == 0 {
-                                if let Some((name, arity)) = term_predicate_key(heap, qualified_term_loc) {
-                                    return Some(QualifiedNameInfo {
-                                        module_name,
-                                        name,
-                                        arity,
-                                        qualified_term_loc,
-                                    });
-                                }
-                            }
+                    module_term: &Term,
+                    qualified_term: &Term,
+                ) -> Option<(Atom, Atom)> {
+                    if let Term::Literal(_, Literal::Atom(module_name)) = module_term {
+                        if let Some(name) = qualified_term.name() {
+                            return Some((*module_name, name));
                         }
-                        _ => {}
-                    );
+                    }
 
                     None
                 }
 
-                let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc);
-                let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc);
+                fn identity_fn(_module_name: Atom, term: Term) -> Term {
+                    term
+                }
 
-                let (module_name, key, term_loc) = 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, arity + supp_args), qualified_term_loc),
-                        None => {
+                fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
+                    Term::Clause(
+                        Cell::default(),
+                        atom!(":"),
+                        vec![
+                            Term::Literal(Cell::default(), Literal::Atom(module_name)),
+                            term,
+                        ],
+                    )
+                }
+
+                let process_term: fn(Atom, Term) -> Term;
+
+                let (module_name, key, term) = match term {
+                    Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => {
+                        if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1])
+                        {
+                            process_term = tag_with_module_name;
+                            (
+                                module_name,
+                                (name, terms[1].arity() + supp_args),
+                                terms.pop().unwrap(),
+                            )
+                        } else {
+                            arg_terms.push(Term::Clause(cell, atom!(":"), terms));
                             continue;
                         }
                     }
-                } else {
-                    (module_name, (name, arity + supp_args), subterm_loc)
+                    term => {
+                        process_term = identity_fn;
+                        (module_name, (name, arity + supp_args), term)
+                    }
                 };
 
-                if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), term_loc) {
-                    index_ptrs.insert(term_loc, index_ptr);
-                    continue;
-                }
+                let term = match term {
+                    Term::Clause(cell, name, mut terms) => {
+                        if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
+                            arg_terms
+                                .push(process_term(module_name, Term::Clause(cell, name, terms)));
+
+                            continue;
+                        }
+
+                        let idx = loader.get_or_insert_qualified_code_index(module_name, key);
 
-                index_ptrs.insert(
-                    term_loc,
-                    loader.get_or_insert_qualified_code_index(module_name, key),
-                );
+                        terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
+                        process_term(module_name, Term::Clause(cell, name, terms))
+                    }
+                    Term::Literal(cell, Literal::Atom(name)) => {
+                        let idx = loader.get_or_insert_qualified_code_index(module_name, key);
+
+                        process_term(
+                            module_name,
+                            Term::Clause(
+                                cell,
+                                name,
+                                vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
+                            ),
+                        )
+                    }
+                    term => term,
+                };
+
+                arg_terms.push(term);
+                continue;
             }
         }
+
+        arg_terms.push(term);
     }
 
-    index_ptrs
+    arg_terms
 }
 
 #[inline]
 pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
     loader: &mut Loader<'a, LS>,
-    key: PredicateKey,
-    terms: &TermWriteResult,
-    term: HeapCellValue,
+    name: Atom,
+    mut terms: Vec<Term>,
     call_policy: CallPolicy,
-) -> QueryClause {
-    // supplementary code vector indices are unnecessary for
-    // root-level clauses.
-    blunt_index_ptr(loader.machine_heap(), key, terms.focus);
+) -> QueryTerm {
+    if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
+        // supplementary code vector indices are unnecessary for
+        // root-level clauses.
+        terms.pop();
+    }
 
-    let mut ct = loader.get_clause_type(key.0, key.1);
+    let mut ct = loader.get_clause_type(name, terms.len());
 
     if let ClauseType::Named(arity, name, idx) = ct {
         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);
+            let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
 
-            return QueryClause {
-                ct: ClauseType::Named(key.1, key.0, idx),
-                term,
-                code_indices,
+            return QueryTerm::Clause(
+                Cell::default(),
+                ClauseType::Named(arity, name, idx),
+                terms,
                 call_policy,
-            };
+            );
         }
 
-        ct = ClauseType::Named(key.1, key.0, idx);
+        ct = ClauseType::Named(arity, name, idx);
     }
 
-    QueryClause {
-        ct,
-        term,
-        code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
-        call_policy,
-    }
+    QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
 }
 
 #[inline]
 pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
     loader: &mut Loader<'a, LS>,
-    key: PredicateKey,
     module_name: Atom,
-    terms: &TermWriteResult,
-    term: HeapCellValue,
+    name: Atom,
+    mut terms: Vec<Term>,
     call_policy: CallPolicy,
-) -> QueryClause {
-    // supplementary code vector indices are unnecessary for
-    // root-level clauses.
-    blunt_index_ptr(loader.machine_heap(), key, terms.focus);
+) -> QueryTerm {
+    if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
+        // supplementary code vector indices are unnecessary for
+        // root-level clauses.
+        terms.pop();
+    }
 
-    let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1);
+    let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len());
 
     if let ClauseType::Named(arity, name, idx) = ct {
         if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
-            let code_indices =
-                build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs);
+            let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
 
-            return QueryClause {
-                ct: ClauseType::Named(key.1, key.0, idx),
-                term,
-                code_indices,
+            return QueryTerm::Clause(
+                Cell::default(),
+                ClauseType::Named(arity, name, idx),
+                terms,
                 call_policy,
-            };
+            );
         }
 
-        ct = ClauseType::Named(key.1, key.0, idx);
+        ct = ClauseType::Named(arity, name, idx);
     }
 
-    QueryClause {
-        ct,
-        term,
-        code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
-        call_policy,
-    }
+    QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
 }
 
 #[derive(Debug)]
@@ -642,66 +540,70 @@ impl Preprocessor {
         Preprocessor { settings }
     }
 
-    pub fn setup_fact<'a, LS: LoadState<'a>>(
-        &mut self,
-        loader: &mut Loader<'a, LS>,
-        term: TermWriteResult,
-    ) -> Result<(Fact, VarData), CompilationError> {
-        let heap = loader.machine_heap();
+    fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
+        match term {
+            Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
+                let classifier = VariableClassifier::new(self.settings.default_call_policy());
 
-        if term_predicate_key(heap, term.focus).is_some() {
-            let classifier = VariableClassifier::new(self.settings.default_call_policy());
-            let var_data = classifier.classify_fact(loader, &term)?;
-
-            Ok((
-                Fact {
-                    term_loc: term.focus,
-                },
-                var_data,
-            ))
-        } else {
-            Err(CompilationError::InadmissibleFact)
+                let (head, var_data) = classifier.classify_fact(term)?;
+                Ok((Fact { head }, var_data))
+            }
+            _ => Err(CompilationError::InadmissibleFact),
         }
     }
 
     fn setup_rule<'a, LS: LoadState<'a>>(
         &mut self,
         loader: &mut Loader<'a, LS>,
-        term: TermWriteResult,
+        head: Term,
+        body: Term,
     ) -> Result<(Rule, VarData), CompilationError> {
         let classifier = VariableClassifier::new(self.settings.default_call_policy());
-        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();
+        let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
 
-        if term_predicate_key(heap, head_loc).is_some() {
-            Ok((
+        match head {
+            Term::Clause(_, name, terms) => Ok((
                 Rule {
-                    term_loc: term.focus,
+                    head: (name, terms),
                     clauses,
                 },
                 var_data,
-            ))
-        } else {
-            Err(CompilationError::InvalidRuleHead)
+            )),
+            Term::Literal(_, Literal::Atom(name)) => Ok((
+                Rule {
+                    head: (name, vec![]),
+                    clauses,
+                },
+                var_data,
+            )),
+            _ => Err(CompilationError::InvalidRuleHead),
         }
     }
 
     pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
         &mut self,
         loader: &mut Loader<'a, LS>,
-        term: TermWriteResult,
+        term: Term,
     ) -> Result<PredicateClause, CompilationError> {
-        let heap = &LS::machine_st(&mut loader.payload).heap;
+        match term {
+            Term::Clause(r, name, mut terms) => {
+                let is_rule = name == atom!(":-") && terms.len() == 2;
 
-        match term_predicate_key(heap, term.focus) {
-            Some((atom!(":-"), 2)) => {
-                let (rule, var_data) = self.setup_rule(loader, term)?;
-                Ok(PredicateClause::Rule(rule, var_data))
+                if is_rule {
+                    let tail = terms.pop().unwrap();
+                    let head = terms.pop().unwrap();
+
+                    let (rule, var_data) = self.setup_rule(loader, head, tail)?;
+                    Ok(PredicateClause::Rule(rule, var_data))
+                } else {
+                    let term = Term::Clause(r, name, terms);
+                    let (fact, var_data) = self.setup_fact(term)?;
+                    Ok(PredicateClause::Fact(fact, var_data))
+                }
             }
-            _ => {
-                let (fact, var_data) = self.setup_fact(loader, term)?;
+            term => {
+                let (fact, var_data) = self.setup_fact(term)?;
                 Ok(PredicateClause::Fact(fact, var_data))
             }
         }
index 7e85eff4256a02d00a973a4951c094bbb2dbbf6f..1b5d79fbeb6a570d1d2831df2b0ebea5f8278600 100644 (file)
@@ -24,7 +24,12 @@ pub(crate) struct RawBlock<T: RawBlockTraits> {
 
 impl<T: RawBlockTraits> RawBlock<T> {
     pub(crate) fn new() -> Self {
-        let mut block = Self::uninitialized();
+        let mut block = RawBlock {
+            size: 0,
+            base: ptr::null(),
+            top: ptr::null(),
+            _marker: PhantomData,
+        };
 
         unsafe {
             block.grow();
@@ -33,15 +38,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
         block
     }
 
-    pub(crate) fn uninitialized() -> Self {
-        Self {
-            size: 0,
-            base: ptr::null(),
-            top: ptr::null(),
-            _marker: PhantomData,
-        }
-    }
-
     unsafe fn init_at_size(&mut self, cap: usize) {
         let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
 
index 4d8b970adfd376a597f0fb26c9dd5692d2fb4784..f0b136fa6d6835159d727cca57e931b886f52601 100644 (file)
@@ -168,13 +168,6 @@ impl Stack {
         }
     }
 
-    pub(crate) fn uninitialized() -> Self {
-        Stack {
-            buf: RawBlock::empty_block(),
-            _marker: PhantomData,
-        }
-    }
-
     #[inline(always)]
     unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 {
         loop {
index 356072bc56479297e2743ad887386f8af5596f6c..1f9fae09e944ff26b10930a9b1f5d7feb40e8f93 100644 (file)
@@ -1808,59 +1808,60 @@ impl MachineState {
         let addr = self.store(MachineState::deref(self, addr));
 
         read_heap_cell!(addr,
-                        (HeapCellValueTag::Atom, (name, arity)) => {
-                            debug_assert_eq!(arity, 0);
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                debug_assert_eq!(arity, 0);
 
-                            return match indices.get_stream(name) {
-                                Some(stream) => Ok(stream),
-                                _ => {
-                                    let stub = functor_stub(caller, arity);
-                                    let addr = atom_as_cell!(name);
-
-                                    let existence_error = self.existence_error(ExistenceError::Stream(addr));
+                return match indices.get_stream(name) {
+                    Some(stream) => Ok(stream),
+                    _ => {
+                        let stub = functor_stub(caller, arity);
+                        let addr = atom_as_cell!(name);
 
-                                    Err(self.error_form(existence_error, stub))
-                                }
-                            };
-                        }
-                        (HeapCellValueTag::Str, s) => {
-                            let (name, arity) = cell_as_atom_cell!(self.heap[s])
-                                .get_name_and_arity();
+                        let existence_error = self.existence_error(ExistenceError::Stream(addr));
 
-                            debug_assert_eq!(arity, 0);
+                        Err(self.error_form(existence_error, stub))
+                    }
+                };
+            }
+            (HeapCellValueTag::Str, s) => {
+                let (name, arity) = cell_as_atom_cell!(self.heap[s])
+                    .get_name_and_arity();
 
-                            return match indices.get_stream(name) {
-                                Some(stream) => Ok(stream),
-                                _ => {
-                                    let stub = functor_stub(caller, arity);
-                                    let addr = atom_as_cell!(name);
+                debug_assert_eq!(arity, 0);
 
-                                    let existence_error = self.existence_error(ExistenceError::Stream(addr));
+                return match indices.get_stream(name) {
+                    Some(stream) => Ok(stream),
+                    _ => {
+                        let stub = functor_stub(caller, arity);
+                        let addr = atom_as_cell!(name);
 
-                                    Err(self.error_form(existence_error, stub))
-                                }
-                            };
-                        }
-                        (HeapCellValueTag::Cons, ptr) => {
-                            match_untyped_arena_ptr!(ptr,
-                                (ArenaHeaderTag::Stream, stream) => {
-                                    if stream.is_null_stream() {
-                                        unreachable!("Null streams have no Cons representation");
-                                    }
-                                    return Ok(stream);
-                                }
-                                (ArenaHeaderTag::Dropped, _value) => {
-                                    let stub = functor_stub(caller, arity);
-                                    let err = self.existence_error(ExistenceError::Stream(addr));
+                        let existence_error = self.existence_error(ExistenceError::Stream(addr));
 
-                                    return Err(self.error_form(err, stub));
-                                }
-                                _ => {
-                                }
-                            );
-                        }
-                        _ => {
-                        }
+                        Err(self.error_form(existence_error, stub))
+                    }
+                };
+            }
+            (HeapCellValueTag::Cons, ptr) => {
+                match_untyped_arena_ptr!(ptr,
+                   (ArenaHeaderTag::Stream, stream) => {
+                       return if stream.is_null_stream() {
+                           Err(self.open_permission_error(stream_as_cell!(stream), caller, arity))
+                       } else {
+                           Ok(stream)
+                       };
+                   }
+                   (ArenaHeaderTag::Dropped, _value) => {
+                       let stub = functor_stub(caller, arity);
+                       let err = self.existence_error(ExistenceError::Stream(addr));
+
+                       return Err(self.error_form(err, stub));
+                   }
+                   _ => {
+                   }
+                );
+            }
+            _ => {
+            }
         );
 
         let stub = functor_stub(caller, arity);
@@ -1880,7 +1881,7 @@ impl MachineState {
     ) -> Result<Stream, ParserError> {
         match stream.peek_char() {
             None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
-            Some(Err(e)) => Err(ParserError::IO(e, ParserErrorSrc::default())),
+            Some(Err(e)) => Err(ParserError::IO(e)),
             Some(Ok(c)) => {
                 if c == '\u{feff}' {
                     // skip UTF-8 BOM
@@ -2086,7 +2087,7 @@ impl MachineState {
                         _ => {
                             // assume the OS is out of file descriptors.
                             let stub = functor_stub(atom!("open"), 4);
-                            let err = self.resource_error(ResourceError::OutOfFiles);
+                            let err = Self::resource_error(ResourceError::OutOfFiles);
 
                             return Err(self.error_form(err, stub));
                         }
index ff2a73e42f452ed4c2cf4cd48d3eb9ff54646be5..c85bc7b64779baba78654e240143cc5c631f2a27 100644 (file)
@@ -1,7 +1,3 @@
-use crate::parser::ast::*;
-use crate::parser::lexer::LexerParser;
-use crate::parser::parser::*;
-
 use base64::Engine;
 use dashu::integer::{Sign, UBig};
 use lazy_static::lazy_static;
@@ -29,8 +25,10 @@ use crate::machine::partial_string::*;
 use crate::machine::stack::*;
 use crate::machine::streams::*;
 use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC};
+use crate::parser::ast::*;
 use crate::parser::char_reader::*;
-use crate::parser::dashu::{Integer, Rational};
+use crate::parser::dashu::Integer;
+use crate::parser::parser::*;
 use crate::read::*;
 use crate::types::*;
 use rand::rngs::StdRng;
@@ -41,6 +39,7 @@ use ordered_float::OrderedFloat;
 use fxhash::{FxBuildHasher, FxHasher};
 use indexmap::IndexSet;
 
+use std::cell::Cell;
 use std::cmp::Ordering;
 use std::convert::TryFrom;
 use std::env;
@@ -851,12 +850,10 @@ impl MachineState {
     ) {
         let mut seen_set = IndexSet::new();
 
-        if term.is_ref() {
-            let mut iter = stackful_post_order_iter::<NonListElider>(
-                &mut self.heap,
-                &mut self.stack,
-                term.get_value() as usize,
-            );
+        {
+            self.heap[0] = term;
+            let mut iter =
+                stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
 
             while let Some(value) = iter.next() {
                 if iter.parent_stack_len() >= max_depth {
@@ -874,9 +871,8 @@ impl MachineState {
 
         let outcome = step_or_resource_error!(
             self,
-            sized_iter_to_heap_list(&mut self.heap, seen_set.len(), seen_set.into_iter(),)
+            sized_iter_to_heap_list(&mut self.heap, seen_set.len(), seen_set.into_iter())
         );
-
         unify_fn!(*self, list_of_vars, outcome);
     }
 
@@ -959,7 +955,7 @@ impl MachineState {
         let nx = self.store(self.deref(self.registers[2]));
         let iter = std::io::Cursor::new(string);
 
-        let mut lexer_parser = LexerParser::new(CharReader::new(iter), self);
+        let mut lexer = Lexer::new(CharReader::new(iter), self);
         let mut tokens = vec![];
 
         match lexer.next_number_token() {
@@ -980,58 +976,35 @@ impl MachineState {
         }
 
         loop {
-            match lexer_parser.lookahead_char() {
+            match lexer.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 lexer_parser.read_term(&op_dir, Tokens::Provided(tokens, byte_size)) {
-                        Ok(term) => {
-                            read_heap_cell!(lexer_parser.machine_st.heap[term.focus],
-                                (HeapCellValueTag::Cons, c) => {
-                                    match_untyped_arena_ptr!(c,
-                                       (ArenaHeaderTag::Rational, n) => {
-                                           self.unify_rational(n, nx);
-                                       }
-                                       (ArenaHeaderTag::Integer, n) => {
-                                           self.unify_big_int(n, nx);
-                                       }
-                                       _ => {
-                                           let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src());
-                                           let e = self.syntax_error(e);
-
-                                           return Err(self.error_form(e, stub_gen()));
-                                       }
-                                    )
-                                }
-                                (HeapCellValueTag::F64, n) => {
-                                    self.unify_f64(n, nx);
-                                }
-                                (HeapCellValueTag::Fixnum, n) => {
-                                    self.unify_fixnum(n, nx);
-                                }
-                                _ => {
-                                    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(());
+                    match parser.read_term(&op_dir, Tokens::Provided(tokens)) {
+                        Err(err) => {
+                            let err = self.syntax_error(err);
+                            return Err(self.error_form(err, stub_gen()));
                         }
-                        Err(e) => {
-                            let e = self.syntax_error(e);
-                            return Err(self.error_form(e, stub_gen()));
+                        Ok(Term::Literal(_, cell)) => {
+                            unify!(self, nx, HeapCellValue::from(cell));
+                        }
+                        _ => {
+                            let err = ParserError::ParseBigInt(0, 0);
+                            let err = self.syntax_error(err);
+
+                            return Err(self.error_form(err, stub_gen()));
                         }
                     }
+
+                    return Ok(());
                 }
                 Ok(c) => {
-                    let err_src = lexer_parser.loc_to_err_src();
+                    let (line_num, col_num) = (lexer.line_num, lexer.col_num);
 
-                    let err = ParserError::UnexpectedChar(c, err_src);
+                    let err = ParserError::UnexpectedChar(c, line_num, col_num);
                     let err = self.syntax_error(err);
 
                     return Err(self.error_form(err, stub_gen()));
@@ -1645,12 +1618,12 @@ impl Machine {
 
             let vars: Vec<_> = vars
                 .union(&result.supp_vars) // difference + union does not cancel.
-                .cloned()
+                .map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value()))))
                 .collect();
 
             let helper_clause_loc = self.code.len();
 
-            match self.compile_standalone_clause(temp_v!(1), vars) {
+            match self.compile_standalone_clause(temp_v!(1), &vars) {
                 Err(e) => {
                     let err = self.machine_st.session_error(e);
                     let stub = functor_stub(atom!("call"), result.key.1);
@@ -1996,7 +1969,7 @@ impl Machine {
                         if let Some(name) = entry.file_name().to_str() {
                             let file_string_cell = resource_error_call_result!(
                                 self.machine_st,
-                                self.machine_st.allocate_cstr(name)
+                                self.machine_st.heap.allocate_cstr(name)
                             );
 
                             files.push(file_string_cell);
@@ -2115,7 +2088,7 @@ impl Machine {
 
                     let cstr_cell = step_or_resource_error!(
                         self.machine_st,
-                        self.machine_st.allocate_cstr(&chars_string)
+                        self.machine_st.heap.allocate_cstr(&chars_string)
                     );
 
                     unify!(self.machine_st, cstr_cell, self.machine_st.registers[3]);
@@ -2251,7 +2224,7 @@ impl Machine {
 
             let current_string = resource_error_call_result!(
                 self.machine_st,
-                self.machine_st.allocate_cstr(current)
+                self.machine_st.heap.allocate_cstr(current)
             );
 
             unify!(
@@ -2295,8 +2268,10 @@ impl Machine {
                     }
                 };
 
-                let canonical_string =
-                    resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(cs));
+                let canonical_string = resource_error_call_result!(
+                    self.machine_st,
+                    self.machine_st.heap.allocate_cstr(cs)
+                );
 
                 unify!(
                     self.machine_st,
@@ -2321,7 +2296,7 @@ impl Machine {
 
                 let cell = step_or_resource_error!(
                     self.machine_st,
-                    self.machine_st.allocate_cstr(&*name.as_str())
+                    self.machine_st.heap.allocate_cstr(&*name.as_str())
                 );
 
                 unify!(self.machine_st, self.machine_st.registers[2], cell);
@@ -2522,7 +2497,7 @@ impl Machine {
 
         let pstr_loc_cell = step_or_resource_error!(
             self.machine_st,
-            self.machine_st.allocate_pstr(&*atom.as_str())
+            self.machine_st.heap.allocate_pstr(&*atom.as_str())
         );
 
         let tail_loc = Heap::pstr_tail_idx(atom.as_str().len() + heap_index!(pstr_h));
@@ -2897,7 +2872,7 @@ impl Machine {
 
         let cstr_cell = step_or_resource_error!(
             self.machine_st,
-            self.machine_st.allocate_cstr(string.trim())
+            self.machine_st.heap.allocate_cstr(string.trim())
         );
 
         unify!(self.machine_st, cstr_cell, chs);
@@ -3137,7 +3112,7 @@ impl Machine {
                         let reg = self.machine_st.deref(self.machine_st.heap[s+1]);
                         let upper_str = step_or_resource_error!(
                             self.machine_st,
-                            self.machine_st.allocate_cstr(&c.to_uppercase().to_string())
+                            self.machine_st.heap.allocate_cstr(&c.to_uppercase().to_string())
                         );
                         unify!(self.machine_st, reg, upper_str);
                     }
@@ -3145,7 +3120,7 @@ impl Machine {
                         let reg = self.machine_st.deref(self.machine_st.heap[s+1]);
                         let lower_str = step_or_resource_error!(
                             self.machine_st,
-                            self.machine_st.allocate_cstr(&c.to_uppercase().to_string())
+                            self.machine_st.heap.allocate_cstr(&c.to_uppercase().to_string())
                         );
 
                         unify!(self.machine_st, reg, lower_str);
@@ -3660,12 +3635,7 @@ impl Machine {
                     }
                     Some(Err(e)) => {
                         let stub = functor_stub(atom!("$get_n_chars"), 3);
-                        let err =
-                            self.machine_st
-                                .session_error(SessionError::from(ParserError::IO(
-                                    e,
-                                    ParserErrorSrc::default(),
-                                )));
+                        let err = self.machine_st.session_error(SessionError::from(e));
 
                         return Err(self.machine_st.error_form(err, stub));
                     }
@@ -3677,8 +3647,10 @@ impl Machine {
         };
 
         let output = self.deref_register(3);
-        let cstr_cell =
-            resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&string));
+        let cstr_cell = resource_error_call_result!(
+            self.machine_st,
+            self.machine_st.heap.allocate_cstr(&string)
+        );
 
         unify!(self.machine_st, cstr_cell, output);
         Ok(())
@@ -4403,9 +4375,7 @@ impl Machine {
             Ok(Number::Integer(n)) => match (&*n).try_into() as Result<usize, _> {
                 Ok(n) => n,
                 Err(_) => {
-                    let err = self
-                        .machine_st
-                        .resource_error(ResourceError::FiniteMemory(len));
+                    let err = MachineState::resource_error(ResourceError::FiniteMemory(len));
                     return Err(self.machine_st.error_form(err, stub_gen()));
                 }
             },
@@ -4508,6 +4478,7 @@ impl Machine {
                             let string_cell = resource_error_call_result!(
                                 self.machine_st,
                                 self.machine_st
+                                    .heap
                                     .allocate_cstr(header_value.to_str().unwrap())
                             );
 
@@ -4568,7 +4539,7 @@ impl Machine {
                     }
                 }
 
-                Ok(())
+                Ok::<(), _>(())
             })?;
         } else {
             let err = self
@@ -4758,7 +4729,7 @@ impl Machine {
                         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)
+                            self.machine_st.heap.allocate_cstr(&request.request_data.path)
                         );
 
                         let mut headers = vec![];
@@ -4766,7 +4737,7 @@ impl Machine {
                         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())
+                                self.machine_st.heap.allocate_cstr(header_value.to_str().unwrap())
                             );
 
                             let header_term = functor!(
@@ -4796,7 +4767,7 @@ impl Machine {
                         let query_str  = request.request_data.query;
                         let query_cell = resource_error_call_result!(
                             self.machine_st,
-                            self.machine_st.allocate_cstr(&query_str)
+                            self.machine_st.heap.allocate_cstr(&query_str)
                         );
 
                         let mut stream = Stream::from_http_stream(
@@ -5064,7 +5035,7 @@ impl Machine {
                                 Value::CString(cstr) => {
                                     let str_cell = resource_error_call_result!(
                                         self.machine_st,
-                                        self.machine_st.allocate_cstr(cstr.to_str().unwrap())
+                                        self.machine_st.heap.allocate_cstr(cstr.to_str().unwrap())
                                     );
 
                                     unify!(self.machine_st, str_cell, return_value);
@@ -5208,8 +5179,10 @@ impl Machine {
         let mut args_pstrs = vec![];
 
         for arg in env::args() {
-            let pstr_cell =
-                resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&arg));
+            let pstr_cell = resource_error_call_result!(
+                self.machine_st,
+                self.machine_st.heap.allocate_cstr(&arg)
+            );
 
             args_pstrs.push(pstr_cell);
         }
@@ -5230,8 +5203,10 @@ impl Machine {
     #[inline(always)]
     pub(crate) fn current_time(&mut self) {
         let timestamp = self.systemtime_to_timestamp(SystemTime::now());
-        let cstr_cell =
-            step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&timestamp));
+        let cstr_cell = step_or_resource_error!(
+            self.machine_st,
+            self.machine_st.heap.allocate_cstr(&timestamp)
+        );
 
         unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]);
     }
@@ -6494,7 +6469,7 @@ impl Machine {
     }
 
     #[inline(always)]
-    fn read_term_from_atom(
+    fn read_term_and_write_to_heap(
         &mut self,
         atom_or_string: AtomOrString,
     ) -> Result<Option<TermWriteResult>, MachineStub> {
@@ -6504,15 +6479,16 @@ impl Machine {
         };
 
         let chars = CharReader::new(ByteStream::from_string(string));
-        let mut parser = LexerParser::new(chars, &mut self.machine_st);
+        let mut parser = Parser::new(chars, &mut self.machine_st);
         let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
 
-        let term = parser
+        let term_write_result = parser
             .read_term(&op_dir, Tokens::Default)
-            .map_err(|e| error_after_read_term(e, 0));
+            .map_err(|err| error_after_read_term(err, 0, &parser))
+            .and_then(|term| write_term_to_heap(&term, &mut self.machine_st.heap));
 
-        match term {
-            Ok(term) => Ok(Some(term)),
+        match term_write_result {
+            Ok(term_write_result) => Ok(Some(term_write_result)),
             Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => {
                 let value = self.machine_st.registers[2];
                 self.machine_st.unify_atom(atom!("end_of_file"), value);
@@ -6530,46 +6506,43 @@ impl Machine {
 
     #[inline(always)]
     pub(crate) fn read_from_chars(&mut self) -> CallResult {
-        let atom_or_string = self
+        if let Some(atom_or_string) = self
             .machine_st
             .value_to_str_like(self.machine_st.registers[1])
-            .unwrap();
+        {
+            if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
+                let result = heap_loc_as_cell!(term_write_result.heap_loc);
+                let var = self.deref_register(2).as_var().unwrap();
 
-        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);
+            }
 
-            self.machine_st.bind(var, result);
+            Ok(())
+        } else {
+            unreachable!()
         }
-
-        Ok(())
     }
 
     #[inline(always)]
     pub(crate) fn read_term_from_chars(&mut self) -> CallResult {
-        let atom_or_string = self
+        if let Some(atom_or_string) = self
             .machine_st
             .value_to_str_like(self.machine_st.registers[1])
-            .unwrap();
-
-        let string = match atom_or_string {
-            AtomOrString::Atom(atom!("[]")) => "".to_owned(),
-            _ => atom_or_string.into(),
-        };
-
-        let chars = CharReader::new(ByteStream::from_string(string));
-        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);
-
-                self.machine_st.error_form(e, stub)
-            })?;
+        {
+            if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
+                self.machine_st.read_term_body(term_write_result)
+            } else {
+                if !self.machine_st.fail {
+                    // wrote end_of_file term in this case.
+                    self.machine_st
+                        .write_read_term_options(vec![], empty_list_as_cell!())?;
+                }
 
-        self.machine_st.read_term_body(term)
+                Ok(())
+            }
+        } else {
+            unreachable!()
+        }
     }
 
     #[inline(always)]
@@ -7542,8 +7515,10 @@ impl Machine {
         };
 
         let result = printer.print().result();
-        let chars =
-            resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&result));
+        let chars = resource_error_call_result!(
+            self.machine_st,
+            self.machine_st.heap.allocate_cstr(&result)
+        );
 
         let result_addr = self.deref_register(1);
         let var = result_addr.as_var().unwrap();
@@ -7559,7 +7534,7 @@ impl Machine {
 
         let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown");
         let cstr_cell =
-            step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer));
+            step_or_resource_error!(self.machine_st, self.machine_st.heap.allocate_cstr(&buffer));
 
         unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]);
     }
@@ -8010,7 +7985,10 @@ impl Machine {
             if buffer.is_empty() {
                 empty_list_as_cell!()
             } else {
-                step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer))
+                step_or_resource_error!(
+                    self.machine_st,
+                    self.machine_st.heap.allocate_cstr(&buffer)
+                )
             }
         };
 
@@ -8197,7 +8175,7 @@ impl Machine {
                 Ok(value) => {
                     let cstr = step_or_resource_error!(
                         self.machine_st,
-                        self.machine_st.allocate_cstr(&value)
+                        self.machine_st.heap.allocate_cstr(&value)
                     );
 
                     unify!(self.machine_st, self.machine_st.registers[2], cstr);
@@ -8410,20 +8388,15 @@ impl Machine {
             1,
         )?;
 
-        let mut lexer_parser = LexerParser::new(stream, &mut self.machine_st);
+        let mut parser = Parser::new(stream, &mut self.machine_st);
 
-        match devour_whitespace(&mut lexer_parser) {
+        match devour_whitespace(&mut parser.lexer) {
             Ok(false) => {
-                // not at EOF ...
-                stream.add_lines_read(lexer_parser.line_num());
-
-                // ... unless we are.
-                if stream.at_end_of_stream() {
-                    self.machine_st.fail = true;
-                }
+                // not at EOF.
+                stream.add_lines_read(parser.lines_read());
             }
             Ok(true) => {
-                stream.add_lines_read(lexer_parser.line_num());
+                stream.add_lines_read(parser.lexer.line_num);
                 self.machine_st.fail = true;
             }
             Err(err) => {
@@ -8483,8 +8456,10 @@ impl Machine {
 
         if path.is_dir() {
             if let Some(path) = path.to_str() {
-                let path_string =
-                    step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(path));
+                let path_string = step_or_resource_error!(
+                    self.machine_st,
+                    self.machine_st.heap.allocate_cstr(path)
+                );
 
                 unify!(self.machine_st, self.machine_st.registers[1], path_string);
                 return;
@@ -8557,13 +8532,13 @@ impl Machine {
         node: roxmltree::Node,
     ) -> Result<HeapCellValue, usize> {
         if node.is_text() {
-            self.machine_st.allocate_cstr(node.text().unwrap())
+            self.machine_st.heap.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 = self.machine_st.allocate_cstr(attr.value())?;
+                let value = self.machine_st.heap.allocate_cstr(attr.value())?;
 
                 avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len()));
 
@@ -8610,13 +8585,14 @@ impl Machine {
         match node.value().as_element() {
             None => self
                 .machine_st
+                .heap
                 .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 = self.machine_st.allocate_cstr(attr.1)?;
+                    let value = self.machine_st.heap.allocate_cstr(attr.1)?;
 
                     avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len()));
 
@@ -8669,7 +8645,7 @@ impl Machine {
         if buffer.is_empty() {
             Ok(empty_list_as_cell!())
         } else {
-            self.machine_st.allocate_cstr(&buffer)
+            self.machine_st.heap.allocate_cstr(&buffer)
         }
     }
 }
index f8488af7ed4ec9a836f51394b341629ef4a5c542..a0f5ae22a7008e8f9f1d46f7b83e4e892d8886be 100644 (file)
@@ -21,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<TermWriteResult>,
+    pub(super) clause_clauses: Vec<(Term, Term)>,
 }
 
 pub trait TermStream: Sized {
-    fn next(&mut self, op_dir: &CompositeOpDir) -> Result<TermWriteResult, CompilationError>;
+    fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
     fn eof(&mut self) -> Result<bool, CompilationError>;
     fn listing_src(&self) -> &ListingSource;
 }
@@ -33,7 +33,7 @@ pub trait TermStream: Sized {
 #[derive(Debug)]
 pub struct BootstrappingTermStream<'a> {
     listing_src: ListingSource,
-    pub(super) lexer_parser: LexerParser<'a, Stream>,
+    pub(super) parser: Parser<'a, Stream>,
 }
 
 impl<'a> BootstrappingTermStream<'a> {
@@ -43,9 +43,9 @@ impl<'a> BootstrappingTermStream<'a> {
         machine_st: &'a mut MachineState,
         listing_src: ListingSource,
     ) -> Self {
-        let lexer_parser = LexerParser::new(stream, machine_st);
+        let parser = Parser::new(stream, machine_st);
         Self {
-            lexer_parser,
+            parser,
             listing_src,
         }
     }
@@ -53,18 +53,16 @@ impl<'a> BootstrappingTermStream<'a> {
 
 impl<'a> TermStream for BootstrappingTermStream<'a> {
     #[inline]
-    fn next(&mut self, op_dir: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> {
-        let result = self
-            .lexer_parser
+    fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
+        self.parser.reset();
+        self.parser
             .read_term(op_dir, Tokens::Default)
-            .map_err(CompilationError::from);
-
-        result
+            .map_err(CompilationError::from)
     }
 
     #[inline]
     fn eof(&mut self) -> Result<bool, CompilationError> {
-        devour_whitespace(&mut self.lexer_parser) // eliminate dangling comments before checking for EOF.
+        devour_whitespace(&mut self.parser.lexer) // eliminate dangling comments before checking for EOF.
             .map_err(CompilationError::from)
     }
 
@@ -75,7 +73,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
 }
 
 pub struct LiveTermStream {
-    pub(super) term_queue: VecDeque<TermWriteResult>,
+    pub(super) term_queue: VecDeque<Term>,
     pub(super) listing_src: ListingSource,
 }
 
@@ -111,7 +109,7 @@ impl<TS> LoadStatePayload<TS> {
 
 impl TermStream for LiveTermStream {
     #[inline]
-    fn next(&mut self, _: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> {
+    fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
         Ok(self.term_queue.pop_front().unwrap())
     }
 
@@ -129,10 +127,8 @@ impl TermStream for LiveTermStream {
 pub struct InlineTermStream {}
 
 impl TermStream for InlineTermStream {
-    fn next(&mut self, _: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> {
-        Err(CompilationError::from(ParserError::unexpected_eof(
-            ParserErrorSrc::default(),
-        )))
+    fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
+        Err(CompilationError::from(ParserError::unexpected_eof()))
     }
 
     fn eof(&mut self) -> Result<bool, CompilationError> {
index 899fc3ac56de47579d844be57b7c3c044f396ef6..b9aae0e6ea46accc293504b5918ffa250869aae0 100644 (file)
@@ -133,11 +133,14 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
                 machine_st.partial_string_to_pdl(pstr_loc, l);
             }
             (HeapCellValueTag::PStrLoc, other_pstr_loc) => {
-                let cmp_result = machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc);
-
-                if cmp_result.continue_pstr_compare(&mut machine_st.pdl).is_some() {
-                    debug_assert!(matches!(cmp_result, PStrSegmentCmpResult::Mismatch { .. }));
-                    machine_st.fail = true;
+                match machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc) {
+                    PStrSegmentCmpResult::Continue(v1, v2) => {
+                        machine_st.pdl.push(v1);
+                        machine_st.pdl.push(v2);
+                    }
+                    _ => {
+                        machine_st.fail = true;
+                    }
                 }
             }
             _ => {
@@ -501,10 +504,8 @@ fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellVa
 
     let mut occurs_triggered = false;
 
-    let machine_st: &mut MachineState = unifier.deref_mut();
-    let value = machine_st.store(MachineState::deref(machine_st, value));
-
-    if value.is_ref() && !value.is_stack_var() {
+    if !value.is_constant() {
+        let machine_st: &mut MachineState = unifier.deref_mut();
         machine_st.heap[0] = value;
 
         for cell in
index 4869e4027edd6b7609bf52bce56ff3d1cec0a1a5..6d6a71b8b9ca8aab6a91fcf09795e96cbbe20626 100644 (file)
@@ -287,12 +287,6 @@ macro_rules! read_heap_cell_pat_body {
         #[allow(unused_braces)]
         $code
     }};
-    ($cell:ident, Atom, (_, $arity:ident), $code:expr) => {{
-        let $arity = cell_as_atom_cell!($cell).get_arity();
-        #[allow(unused_braces)]
-        $code
-    }};
-    /*
     ($cell:ident, PStr, $atom:ident, $code:expr) => {{
         let $atom = cell_as_atom!($cell);
         #[allow(unused_braces)]
@@ -313,7 +307,6 @@ 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)]
@@ -489,7 +482,7 @@ macro_rules! step_or_resource_error {
 macro_rules! resource_error_call_result {
     ($machine_st:expr, $val:expr) => {
         step_or_resource_error!($machine_st, $val, {
-            return Err(vec![]); // TODO: return Ok(());
+            return Err(vec![]);
         })
     };
 }
index 2785b0bfcc52e1d30b20906809b409af346880c1..96a0df1ff72f3954a6d22f2da3137c50983cf236 100644 (file)
@@ -2,18 +2,22 @@
 
 use crate::arena::*;
 use crate::atom_table::*;
-use crate::forms::PredicateKey;
-use crate::machine::heap::*;
-use crate::machine::machine_indices::*;
-use crate::types::*;
+use crate::machine::machine_indices::CodeIndex;
+use crate::parser::char_reader::*;
+use crate::types::HeapCellValueTag;
 
+use std::cell::{Cell, Ref, RefCell, RefMut};
 use std::fmt;
 use std::hash::Hash;
+use std::hash::Hasher;
 use std::io::{Error as IOError, ErrorKind};
-use std::ops::Neg;
+use std::ops::{Deref, Neg};
 use std::rc::Rc;
+use std::sync::Arc;
 use std::vec::Vec;
 
+use dashu::Integer;
+use dashu::Rational;
 use fxhash::FxBuildHasher;
 use indexmap::IndexMap;
 use scryer_modular_bitfield::error::OutOfBounds;
@@ -138,16 +142,7 @@ pub const BTERM: u32 = 0x11000;
 pub const NEGATIVE_SIGN: u32 = 0x0200;
 
 macro_rules! fixnum {
-    ($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) => {
+    ($wrapper:tt, $n:expr, $arena:expr) => {
         Fixnum::build_with_checked($n)
             .map(<$wrapper>::Fixnum)
             .unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena)))
@@ -276,6 +271,37 @@ 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)
@@ -373,49 +399,41 @@ pub fn default_op_dir() -> OpDir {
     op_dir
 }
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
 pub enum ArithmeticError {
-    NonEvaluableFunctor(HeapCellValue, usize),
-}
-
-#[derive(Debug, Copy, Clone, Default)]
-pub struct ParserErrorSrc {
-    pub col_num: usize,
-    pub line_num: usize,
+    NonEvaluableFunctor(Literal, usize),
+    UninstantiatedVar,
 }
 
+#[allow(dead_code)]
 #[derive(Debug)]
 pub enum ParserError {
-    BackQuotedString(ParserErrorSrc),
-    IO(IOError, ParserErrorSrc),
-    IncompleteReduction(ParserErrorSrc),
-    InfiniteFloat(ParserErrorSrc),
-    InvalidSingleQuotedCharacter(char, ParserErrorSrc),
-    LexicalError(lexical::Error, ParserErrorSrc),
-    MissingQuote(ParserErrorSrc),
-    NonPrologChar(ParserErrorSrc),
-    ParseBigInt(ParserErrorSrc),
-    ResourceError(ParserErrorSrc),
-    UnexpectedChar(char, ParserErrorSrc),
+    BackQuotedString(usize, usize),
+    IO(IOError),
+    IncompleteReduction(usize, usize),
+    InfiniteFloat(usize, usize),
+    InvalidSingleQuotedCharacter(char),
+    LexicalError(lexical::Error),
+    MissingQuote(usize, usize),
+    NonPrologChar(usize, usize),
+    ParseBigInt(usize, usize),
+    UnexpectedChar(char, usize, usize),
     // UnexpectedEOF,
-    Utf8Error(ParserErrorSrc),
+    Utf8Error(usize, usize),
 }
 
 impl ParserError {
-    pub fn err_src(&self) -> ParserErrorSrc {
+    pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
         match self {
-            &ParserError::BackQuotedString(err_src)
-            | &ParserError::IO(_, err_src)
-            | &ParserError::IncompleteReduction(err_src)
-            | &ParserError::InfiniteFloat(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,
+            &ParserError::BackQuotedString(line_num, col_num)
+            | &ParserError::IncompleteReduction(line_num, col_num)
+            | &ParserError::InfiniteFloat(line_num, col_num)
+            | &ParserError::MissingQuote(line_num, col_num)
+            | &ParserError::NonPrologChar(line_num, col_num)
+            | &ParserError::ParseBigInt(line_num, col_num)
+            | &ParserError::UnexpectedChar(_, line_num, col_num)
+            | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
+            _ => None,
         }
     }
 
@@ -429,31 +447,30 @@ impl ParserError {
            ParserError::InfiniteFloat(..) => {
                atom!("infinite_float")
            }
-            ParserError::IO(e, _) if e.kind() == ErrorKind::UnexpectedEof => {
+            ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
                 atom!("unexpected_end_of_file")
             }
-            ParserError::IO(e, _) if e.kind() == ErrorKind::InvalidData => {
+            ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => {
                 atom!("invalid_data")
             }
-            ParserError::IO(..) => atom!("input_output_error"),
-            ParserError::LexicalError(..) => atom!("lexical_error"),
+            ParserError::IO(_) => atom!("input_output_error"),
+            ParserError::LexicalError(_) => atom!("lexical_error"),
             ParserError::MissingQuote(..) => atom!("missing_quote"),
             ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
             ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
             ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
             ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
-            ParserError::ResourceError(..) => atom!("resource_error"),
         }
     }
 
     #[inline]
-    pub fn unexpected_eof(err_src: ParserErrorSrc) -> Self {
-        ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof), err_src)
+    pub fn unexpected_eof() -> Self {
+        ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof))
     }
 
     #[inline]
     pub fn is_unexpected_eof(&self) -> bool {
-        if let ParserError::IO(e, _) = self {
+        if let ParserError::IO(e) = self {
             e.kind() == ErrorKind::UnexpectedEof
         } else {
             false
@@ -461,9 +478,25 @@ impl ParserError {
     }
 }
 
-impl From<ParserErrorSrc> for ParserError {
-    fn from(err_src: ParserErrorSrc) -> ParserError {
-        ParserError::LexicalError(err_src)
+impl From<lexical::Error> for ParserError {
+    fn from(e: lexical::Error) -> ParserError {
+        ParserError::LexicalError(e)
+    }
+}
+
+impl From<IOError> for ParserError {
+    fn from(e: IOError) -> ParserError {
+        ParserError::IO(e)
+    }
+}
+
+impl From<&IOError> for ParserError {
+    fn from(error: &IOError) -> ParserError {
+        if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
+            ParserError::Utf8Error(0, 0)
+        } else {
+            ParserError::IO(error.kind().into())
+        }
     }
 }
 
@@ -575,8 +608,7 @@ impl Neg for Fixnum {
     }
 }
 
-/*
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum Literal {
     Atom(Atom),
     CodeIndex(CodeIndex),
@@ -584,7 +616,6 @@ pub enum Literal {
     Integer(TypedArenaPtr<Integer>),
     Rational(TypedArenaPtr<Rational>),
     Float(F64Offset),
-    String(Rc<String>),
 }
 
 impl From<F64Ptr> for Literal {
@@ -606,7 +637,6 @@ impl fmt::Display for Literal {
             Literal::Integer(ref n) => write!(f, "{}", n),
             Literal::Rational(ref n) => write!(f, "{}", n),
             Literal::Float(ref n) => write!(f, "{}", *n),
-            Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
         }
     }
 }
@@ -619,38 +649,109 @@ impl Literal {
         }
     }
 }
-*/
 
-pub type Var = Rc<String>;
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct VarPtr(Rc<RefCell<Var>>);
+
+impl Hash for VarPtr {
+    #[inline(always)]
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        self.borrow().hash(hasher)
+    }
+}
 
-pub(crate) fn subterm_index(heap: &impl SizedHeap, subterm_loc: usize) -> (usize, HeapCellValue) {
-    let subterm = heap[subterm_loc];
+impl Deref for VarPtr {
+    type Target = RefCell<Var>;
 
-    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);
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        self.0.deref()
+    }
+}
 
-        let subterm_loc = if subterm.is_ref() {
-            subterm.get_value() as usize
-        } else {
-            subterm_loc
-        };
+impl VarPtr {
+    #[inline(always)]
+    pub(crate) fn borrow(&self) -> Ref<'_, Var> {
+        self.0.borrow()
+    }
 
-        (subterm_loc, subterm)
-    } else {
-        (subterm_loc, subterm)
+    #[inline(always)]
+    pub(crate) fn borrow_mut(&self) -> RefMut<'_, Var> {
+        self.0.borrow_mut()
+    }
+
+    pub(crate) fn to_var_num(&self) -> Option<usize> {
+        match *self.borrow() {
+            Var::Generated(var_num) => Some(var_num),
+            _ => None,
+        }
+    }
+
+    pub(crate) fn set(&self, var: Var) {
+        let mut var_ref = self.borrow_mut();
+        *var_ref = var;
+    }
+}
+
+impl From<Var> for VarPtr {
+    #[inline(always)]
+    fn from(value: Var) -> VarPtr {
+        VarPtr(Rc::new(RefCell::new(value)))
+    }
+}
+
+impl From<String> for VarPtr {
+    #[inline(always)]
+    fn from(value: String) -> VarPtr {
+        VarPtr::from(Var::from(value))
+    }
+}
+
+impl From<&str> for VarPtr {
+    #[inline(always)]
+    fn from(value: &str) -> VarPtr {
+        VarPtr::from(value.to_owned())
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Var {
+    Generated(usize),
+    InSitu(usize),
+    Named(Rc<String>),
+}
+
+impl From<String> for Var {
+    #[inline(always)]
+    fn from(value: String) -> Var {
+        Var::Named(Rc::new(value))
+    }
+}
+
+impl From<&str> for Var {
+    #[inline(always)]
+    fn from(value: &str) -> Var {
+        Var::Named(Rc::new(value.to_owned()))
+    }
+}
+
+impl Var {
+    #[allow(clippy::inherent_to_string)]
+    #[inline(always)]
+    pub fn to_string(&self) -> String {
+        match self {
+            Var::InSitu(n) | Var::Generated(n) => format!("_{}", n),
+            Var::Named(value) => value.as_ref().clone(),
+        }
     }
 }
 
-/*
 #[derive(Debug, Clone)]
 pub enum Term {
     AnonVar,
     Clause(Cell<RegType>, Atom, Vec<Term>),
     Cons(Cell<RegType>, Box<Term>, Box<Term>),
-    Literal(Cell<RegType>, HeapCellValue),
-    // Literal(Cell<RegType>, Literal),
+    Literal(Cell<RegType>, Literal),
     // PartialString wraps a String in anticipation of it absorbing
     // other PartialString variants in as_partial_string.
     PartialString(Cell<RegType>, Rc<String>, Box<Term>),
@@ -668,12 +769,8 @@ impl Term {
 
     pub fn name(&self) -> Option<Atom> {
         match self {
-            Term::Literal(_, cell) => {
-                cell.to_atom()
-            }
-            &Term::Clause(_, atom, ..) => {
-                Some(atom)
-            }
+            &Term::Literal(_, Literal::Atom(atom)) => Some(atom),
+            &Term::Clause(_, atom, ..) => Some(atom),
             _ => None,
         }
     }
@@ -714,281 +811,3 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec<Term> {
     terms.push(term);
     terms
 }
- */
-
-pub(crate) fn fetch_index_ptr(heap: &impl SizedHeap, term_loc: usize) -> Option<CodeIndex> {
-    let index_cell_loc = term_loc.saturating_sub(1);
-
-    read_heap_cell!(heap[index_cell_loc],
-        (HeapCellValueTag::Cons, c) => {
-            match_untyped_arena_ptr!(c,
-               (ArenaHeaderTag::IndexPtr, ptr) => {
-                   return Some(CodeIndex::from(ptr));
-               }
-               _ => {}
-            );
-        }
-        _ => {}
-    );
-
-    None
-}
-
-pub(crate) fn blunt_index_ptr(
-    heap: &mut impl SizedHeapMut,
-    key: PredicateKey,
-    term_loc: usize,
-) -> bool {
-    if fetch_index_ptr(heap, term_loc).is_some() {
-        heap[term_loc] = atom_as_cell!(key.0, key.1);
-        true
-    } else {
-        false
-    }
-}
-
-pub(crate) fn unfold_by_str_once(
-    heap: &mut impl SizedHeapMut,
-    start_term: HeapCellValue,
-    atom: Atom,
-) -> Option<usize> {
-    let start_term = heap_bound_store(heap, heap_bound_deref(heap, start_term));
-
-    if let HeapCellValueTag::Str = start_term.get_tag() {
-        let s = start_term.get_value() as usize;
-
-        let (s_atom, s_arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
-        blunt_index_ptr(heap, (s_atom, s_arity), s);
-
-        if (s_atom, s_arity) == (atom, 2) {
-            return Some(s + 1);
-        }
-    }
-
-    None
-}
-
-pub fn unfold_by_str(
-    heap: &mut impl SizedHeapMut,
-    mut start_term: HeapCellValue,
-    atom: Atom,
-) -> Vec<HeapCellValue> {
-    let mut terms = vec![];
-    start_term = heap_bound_store(heap, heap_bound_deref(heap, start_term));
-
-    while let Some(fst_loc) = unfold_by_str_once(heap, start_term, atom) {
-        let (_, snd) = subterm_index(heap, fst_loc + 1);
-        let (_, fst) = subterm_index(heap, fst_loc);
-        terms.push(fst);
-        start_term = snd;
-    }
-
-    terms
-}
-
-/*
-pub fn unfold_by_str_locs(
-    heap: &mut [HeapCellValue],
-    mut term_loc: usize,
-    atom: Atom,
-) -> Vec<(HeapCellValue, usize)> {
-    let mut terms = vec![];
-    let mut current_term = heap_bound_store(
-        heap,
-        heap_bound_deref(heap, heap[term_loc]),
-    );
-
-    while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) {
-        (term_loc, current_term) = subterm_index(heap, fst_loc + 1);
-        let (fst_loc, fst) = subterm_index(heap, fst_loc);
-        terms.push((fst, fst_loc));
-    }
-
-    terms.push((current_term, term_loc));
-    terms
-}
-*/
-
-pub fn unfold_by_str_locs(
-    heap: &mut impl SizedHeapMut,
-    mut term_loc: usize,
-    atom: Atom,
-) -> Vec<(HeapCellValue, usize)> {
-    let mut terms = vec![];
-    let mut current_term = heap[term_loc];
-
-    while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) {
-        term_loc = fst_loc + 1;
-        current_term = heap[term_loc];
-        let fst = heap[fst_loc];
-        terms.push((fst, fst_loc));
-    }
-
-    terms.push((current_term, term_loc));
-    terms
-}
-
-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, arity));
-            }
-            (HeapCellValueTag::Str, s) => {
-                term_loc = s;
-            }
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                if h != term_loc {
-                    term_loc = h;
-                } else {
-                    return None;
-                }
-            }
-            _ => {
-                return None;
-            }
-        );
-    }
-}
-
-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());
-
-    for term in iter {
-        if term.is_var() {
-            let var_count = occurrence_set.entry(term).or_insert(0);
-            *var_count += 1;
-        }
-    }
-
-    let mut inverse_var_locs = InverseVarLocs::default();
-
-    for (var, count) in occurrence_set {
-        let var_loc = var.get_value() as usize;
-
-        if count > 1 {
-            inverse_var_locs.insert(var_loc, Rc::new(format!("_{}", var_loc)));
-        }
-    }
-
-    inverse_var_locs
-}
-
-/*
-pub fn term_deref(heap: &[HeapCellValue], mut term_loc: usize) -> HeapCellValue {
-    loop {
-        read_heap_cell!(heap[term_loc],
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                if h != term_loc {
-                    term_loc = h;
-                } else {
-                    return heap[h];
-                }
-            }
-            _ => {
-                return heap[term_loc];
-            }
-        )
-    }
-}
-*/
-
-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) => {
-                return if cell_as_atom_cell!(heap[s]).get_arity() >= n {
-                    Some(s+n)
-                } else {
-                    None
-                };
-            }
-            (HeapCellValueTag::Atom, (_name, arity)) => {
-                return if arity >= n {
-                    Some(term_loc + n)
-                } else {
-                    None
-                };
-            }
-            (HeapCellValueTag::Lis, l) => {
-                return if 1 <= n && n <= 2 {
-                    Some(l+n-1)
-                } else if n == 0 {
-                    Some(term_loc)
-                } else {
-                    None
-                };
-            }
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                if h != term_loc {
-                    term_loc = h;
-                } else {
-                    return None;
-                }
-            }
-            _ => {
-                return None;
-            }
-        );
-    }
-}
-
-#[derive(Debug)]
-pub struct TermWriteResult {
-    pub focus: usize,
-    pub inverse_var_locs: InverseVarLocs,
-}
-
-pub type VarLocs = IndexMap<Var, HeapCellValue, FxBuildHasher>;
-pub type InverseVarLocs = IndexMap<usize, Var, FxBuildHasher>;
-
-#[derive(Debug)]
-pub struct FocusedHeapRefMut<'a> {
-    pub heap: &'a mut Heap,
-    pub focus: usize,
-}
-
-impl<'a> FocusedHeapRefMut<'a> {
-    #[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 {
-        self.predicate_key(term_loc)
-            .map(|(_, arity)| arity)
-            .unwrap_or(0)
-    }
-
-    pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue {
-        let cell = self.heap[term_loc];
-        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 Heap, cell: HeapCellValue) -> Self {
-        let focus = read_heap_cell!(cell,
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                h
-            }
-            _ => {
-                let h = heap.len();
-                heap.push_cell(cell).unwrap();
-
-                h
-            }
-        );
-
-        Self { heap, focus }
-    }
-    */
-}
index e1be5c46f2881ac902845330438313b182318769..01a122a5d6db0ad7499378aff3074d5cc52f69c2 100644 (file)
@@ -1,15 +1,12 @@
 use crate::arena::F64Ptr;
 use crate::arena::TypedArenaPtr;
-use lexical::{FromLexical, parse};
 
 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;
@@ -35,7 +32,7 @@ struct LayoutInfo {
 
 #[derive(Debug, PartialEq)]
 pub enum Token {
-    Literal(HeapCellValue),
+    Literal(Literal),
     Var(String),
     String(String),
     Open,              // '('
@@ -51,26 +48,6 @@ 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)
@@ -126,14 +103,14 @@ macro_rules! try_nt {
     }};
 }
 
-pub(crate) struct LexerParser<'a, R> {
+pub(crate) struct Lexer<'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 LexerParser<'a, R> {
+impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("LexerParser")
             .field("reader", &"&'a mut R") // Hacky solution.
@@ -143,9 +120,9 @@ impl<'a, R: fmt::Debug> fmt::Debug for LexerParser<'a, R> {
     }
 }
 
-impl<'a, R: CharRead> LexerParser<'a, R> {
+impl<'a, R: CharRead> Lexer<'a, R> {
     pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
-        LexerParser {
+        Self {
             reader: src,
             machine_st,
             line_num: 0,
@@ -156,14 +133,14 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
     pub fn lookahead_char(&mut self) -> Result<char, ParserError> {
         match self.reader.peek_char() {
             Some(Ok(c)) => Ok(c),
-            _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())),
+            _ => Err(ParserError::unexpected_eof()),
         }
     }
 
     pub fn read_char(&mut self) -> Result<char, ParserError> {
         match self.reader.read_char() {
             Some(Ok(c)) => Ok(c),
-            _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())),
+            _ => Err(ParserError::unexpected_eof()),
         }
     }
 
@@ -238,7 +215,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
 
             match comment_loop() {
                 Err(e) if e.is_unexpected_eof() => {
-                    return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+                    return Err(ParserError::IncompleteReduction(
+                        self.line_num,
+                        self.col_num,
+                    ));
                 }
                 Err(e) => {
                     return Err(e);
@@ -250,7 +230,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
                 self.skip_char(c);
                 Ok(true)
             } else {
-                Err(ParserError::NonPrologChar(self.loc_to_err_src()))
+                Err(ParserError::NonPrologChar(self.line_num, self.col_num))
             }
         } else {
             self.return_char('/');
@@ -267,7 +247,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
 
             if !back_quote_char!(c2) {
                 self.return_char(c);
-                Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+                Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
             } else {
                 self.skip_char(c2);
                 Ok(c2)
@@ -292,7 +272,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
                 Ok(None)
             } else {
                 self.return_char(c);
-                Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+                Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
             }
         } else {
             self.get_back_quoted_char().map(Some)
@@ -314,10 +294,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
                 self.skip_char(c);
                 Ok(token)
             } else {
-                Err(ParserError::MissingQuote(self.loc_to_err_src()))
+                Err(ParserError::MissingQuote(self.line_num, self.col_num))
             }
         } else {
-            Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+            Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
         }
     }
 
@@ -348,7 +328,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
 
             if !single_quote_char!(c2) {
                 self.return_char(c);
-                Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+                Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
             } else {
                 self.skip_char(c2);
                 Ok(c2)
@@ -389,7 +369,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
 
             if !double_quote_char!(c2) {
                 self.return_char(c);
-                Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+                Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
             } else {
                 self.skip_char(c2);
                 Ok(c2)
@@ -413,7 +393,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
             't' => '\t',
             'n' => '\n',
             'r' => '\r',
-            c => return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())),
+            c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)),
         };
 
         self.skip_char(c);
@@ -431,7 +411,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
         if hexadecimal_digit_char!(c) {
             self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
         } else {
-            Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
+            Err(ParserError::IncompleteReduction(
+                self.line_num,
+                self.col_num,
+            ))
         }
     }
 
@@ -457,11 +440,17 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
         if backslash_char!(c) {
             self.skip_char(c);
             u32::from_str_radix(&token, radix).map_or_else(
-                |_| Err(ParserError::ParseBigInt(self.loc_to_err_src())),
-                |n| char::try_from(n).map_err(|_| ParserError::Utf8Error(self.loc_to_err_src())),
+                |_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)),
+                |n| {
+                    char::try_from(n)
+                        .map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num))
+                },
             )
         } else {
-            Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
+            Err(ParserError::IncompleteReduction(
+                self.line_num,
+                self.col_num,
+            ))
         }
     }
 
@@ -473,7 +462,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
             Ok(c)
         } else {
             if !backslash_char!(c) {
-                return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()));
+                return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num));
             }
 
             self.skip_char(c);
@@ -504,7 +493,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
             self.skip_char(c);
             Ok(token)
         } else {
-            Err(ParserError::MissingQuote(self.loc_to_err_src()))
+            Err(ParserError::MissingQuote(self.line_num, self.col_num))
         }
     }
 
@@ -529,7 +518,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
                 .map(NumberToken::Number)
         } else {
             self.return_char(start);
-            Err(ParserError::ParseBigInt(self.loc_to_err_src()))
+            Err(ParserError::ParseBigInt(self.line_num, self.col_num))
         }
     }
 
@@ -554,7 +543,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
                 .map(NumberToken::Number)
         } else {
             self.return_char(start);
-            Err(ParserError::ParseBigInt(self.loc_to_err_src()))
+            Err(ParserError::ParseBigInt(self.line_num, self.col_num))
         }
     }
 
@@ -579,7 +568,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
                 .map(NumberToken::Number)
         } else {
             self.return_char(start);
-            Err(ParserError::ParseBigInt(self.loc_to_err_src()))
+            Err(ParserError::ParseBigInt(self.line_num, self.col_num))
         }
     }
 
@@ -646,42 +635,37 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
 
                 if !token.is_empty() && token.chars().nth(1).is_none() {
                     if let Some(c) = token.chars().next() {
-                        return Ok(Token::Literal(char_as_cell!(c)));
+                        return Ok(Token::Literal(Literal::Atom(
+                            AtomCell::new_char_inlined(c).get_name(),
+                        )));
                     }
                 }
             } else {
-                return Err(ParserError::InvalidSingleQuotedCharacter(
-                    self.loc_to_err_src(),
-                ));
+                return Err(ParserError::InvalidSingleQuotedCharacter(c));
             }
         } else {
             match self.get_back_quoted_string() {
-                Ok(_) => return Err(ParserError::BackQuotedString(self.loc_to_err_src())),
+                Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)),
                 Err(e) => return Err(e),
             }
         }
 
         if token.as_str() == "[]" {
-            Ok(Token::Literal(empty_list_as_cell!()))
+            Ok(Token::Literal(Literal::Atom(atom!("[]"))))
         } else {
-            Ok(Token::Literal(atom_as_cell!(AtomTable::build_with(
+            Ok(Token::Literal(Literal::Atom(AtomTable::build_with(
                 &self.machine_st.atom_tbl,
                 &token,
             ))))
         }
     }
 
-    fn parse_lossy_wrapper<T: FromLexical>(&self, token: &str) -> Result<T, ParserError> {
-        match parse::<T, _>(token.as_bytes()) {
-            Ok(n) => Ok(n),
-            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(HeapCellValue::from(float_alloc!(
+
+        let n = parse_float_lossy(&token)?;
+
+        Ok(Token::Literal(Literal::from(float_alloc!(
             n,
             self.machine_st.arena
         ))))
@@ -698,7 +682,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
             if decimal_digit_char!(c) {
                 Ok(c)
             } else {
-                Err(ParserError::ParseBigInt(self.loc_to_err_src()))
+                Err(ParserError::ParseBigInt(self.line_num, self.col_num))
             }
         } else {
             Ok(c)
@@ -810,8 +794,8 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
                             }
                         }
 
-                        let n = self.parse_lossy_wrapper::<f64>(&token)?;
-                        Ok(Token::Literal(HeapCellValue::from(float_alloc!(
+                        let n = parse_float_lossy(&token)?;
+                        Ok(Token::Literal(Literal::from(float_alloc!(
                             n,
                             self.machine_st.arena
                         ))))
@@ -819,8 +803,8 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
                         return self.vacate_with_float(token).map(NumberToken::Number);
                     }
                 } else {
-                    let n = self.parse_lossy_wrapper::<f64>(&token)?;
-                    Ok(Token::Literal(HeapCellValue::from(float_alloc!(
+                    let n = parse_float_lossy(&token)?;
+                    Ok(Token::Literal(Literal::from(float_alloc!(
                         n,
                         self.machine_st.arena
                     ))))
@@ -1057,14 +1041,14 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
 
                     return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes {
                         let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s);
-                        Ok(Token::Literal(atom_as_cell!(atom)))
+                        Ok(Token::Literal(Literal::Atom(atom)))
                     } else {
                         Ok(Token::String(s))
                     };
                 }
 
                 if c == '\u{0}' {
-                    return Err(ParserError::unexpected_eof(self.loc_to_err_src()));
+                    return Err(ParserError::unexpected_eof());
                 }
 
                 self.name_token(c)
@@ -1073,3 +1057,13 @@ impl<'a, R: CharRead> LexerParser<'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 0dcff8a7fb2096ebe5cdbb8a5039eb3ed465a402..a6ec70075ff876fe6a96bb73682dd1e668e473ce 100644 (file)
@@ -3,19 +3,18 @@ use dashu::Rational;
 
 use crate::arena::*;
 use crate::atom_table::*;
-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::cell::Cell;
+use std::mem;
 use std::ops::Neg;
 use std::rc::Rc;
 
 #[derive(Debug, Clone, Copy, PartialEq)]
 enum TokenType {
-    Term { heap_loc: HeapCellValue },
+    Term,
     Open,
     OpenCT,
     OpenList,          // '['
@@ -28,23 +27,6 @@ enum TokenType {
     End,
 }
 
-impl TokenType {
-    fn sep_to_atom(self) -> Option<Atom> {
-        match self {
-            TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
-            TokenType::Close => Some(atom!(")")),
-            TokenType::OpenList => Some(atom!("[")),
-            TokenType::CloseList => Some(atom!("]")),
-            TokenType::OpenCurly => Some(atom!("{")),
-            TokenType::CloseCurly => Some(atom!("}")),
-            TokenType::HeadTailSeparator => Some(atom!("|")),
-            TokenType::Comma => Some(atom!(",")),
-            TokenType::End => Some(atom!(".")),
-            _ => None,
-        }
-    }
-}
-
 /*
 Specifies whether the token sequence should be read from the lexer or
 provided via the Provided variant.
@@ -52,7 +34,7 @@ provided via the Provided variant.
 #[derive(Debug)]
 pub enum Tokens {
     Default,
-    Provided(Vec<Token>, usize),
+    Provided(Vec<Token>),
 }
 
 impl TokenType {
@@ -80,6 +62,80 @@ struct TokenDesc {
     unfold_bounds: usize,
 }
 
+pub(crate) fn as_partial_string(
+    head: Term,
+    mut tail: Term,
+) -> Result<(String, Option<Box<Term>>), Term> {
+    let mut string = match &head {
+        Term::Literal(_, Literal::Atom(atom)) => {
+            if let Some(c) = atom.as_char() {
+                c.to_string()
+            } else {
+                return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
+            }
+        }
+        _ => {
+            return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
+        }
+    };
+
+    let mut orig_tail = Box::new(tail);
+    let mut tail_ref = &mut orig_tail;
+
+    loop {
+        match &mut **tail_ref {
+            Term::Cons(_, prev, succ) => {
+                match prev.as_ref() {
+                    Term::Literal(_, Literal::Atom(atom)) => {
+                        if let Some(c) = atom.as_char() {
+                            string.push(c);
+                        } else {
+                            return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
+                        }
+                    }
+                    _ => {
+                        tail = Term::Cons(
+                            Cell::default(),
+                            Box::new((**prev).clone()),
+                            Box::new((**succ).clone()),
+                        );
+                        break;
+                    }
+                }
+
+                tail_ref = succ;
+            }
+            Term::PartialString(_, pstr, tail) => {
+                string += pstr;
+                tail_ref = tail;
+            }
+            Term::CompleteString(_, cstr) => {
+                string += &*cstr.as_str();
+                tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
+                break;
+            }
+            tail_ref => {
+                tail = mem::replace(tail_ref, Term::AnonVar);
+                break;
+            }
+        }
+    }
+
+    match tail {
+        Term::AnonVar | Term::Var(..) => Ok((string, Some(Box::new(tail)))),
+        Term::Literal(_, Literal::Atom(atom!("[]"))) => Ok((string, None)),
+        Term::CompleteString(_, tail) => {
+            string += &tail;
+            Ok((string, None))
+        }
+        Term::PartialString(_, tail_string, tail) => {
+            string += &tail_string;
+            Ok((string, Some(tail)))
+        }
+        _ => Ok((string, Some(Box::new(tail)))),
+    }
+}
+
 pub fn get_op_desc(name: Atom, op_dir: &CompositeOpDir) -> Option<CompositeOpDesc> {
     let mut op_desc = CompositeOpDesc {
         pre: 0,
@@ -175,29 +231,20 @@ pub struct CompositeOpDesc {
 }
 
 #[derive(Debug)]
-struct Parser<'a> {
+pub struct Parser<'a, R> {
+    pub lexer: Lexer<'a, R>,
     tokens: Vec<Token>,
     stack: Vec<TokenDesc>,
-    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,
+    terms: Vec<Term>,
 }
 
-pub fn read_tokens<R: CharRead>(
-    lexer: &mut LexerParser<R>,
-) -> Result<(Vec<Token>, usize), ParserError> {
+pub fn read_tokens<R: CharRead>(lexer: &mut Lexer<'_, R>) -> Result<Vec<Token>, 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 {
@@ -205,7 +252,10 @@ pub fn read_tokens<R: CharRead>(
                 }
             }
             Err(e) if e.is_unexpected_eof() && !tokens.is_empty() => {
-                return Err(ParserError::IncompleteReduction(lexer.loc_to_err_src()));
+                return Err(ParserError::IncompleteReduction(
+                    lexer.line_num,
+                    lexer.col_num,
+                ));
             }
             Err(e) => {
                 return Err(e);
@@ -214,142 +264,78 @@ pub fn read_tokens<R: CharRead>(
     }
 
     tokens.reverse();
+    Ok(tokens)
+}
 
-    Ok((tokens, term_size))
+fn atomize_term(term: &Term) -> Option<Atom> {
+    match term {
+        &Term::Literal(_, Literal::Atom(c)) => Some(c),
+        _ => None,
+    }
 }
 
-pub(crate) fn as_partial_string(
-    heap: &impl SizedHeap,
-    head: HeapCellValue,
-    tail: HeapCellValue,
-) -> Option<(String, Option<HeapCellValue>)> {
-    let head = heap_bound_store(heap, heap_bound_deref(heap, head));
-    let mut tail = heap_bound_store(heap, heap_bound_deref(heap, tail));
-
-    let mut string = read_heap_cell!(head,
-       (HeapCellValueTag::Atom, (atom, arity)) => {
-           if arity == 0 {
-               if let Some(c) = atom.as_char() {
-                   c.to_string()
-               } else {
-                   return None;
-               }
-           } else {
-               return None;
-           }
-       }
-       _ => {
-           return None;
-       }
-    );
+impl TokenType {
+    fn sep_to_atom(&mut self) -> Option<Atom> {
+        match self {
+            TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
+            TokenType::Close => Some(atom!(")")),
+            TokenType::OpenList => Some(atom!("[")),
+            TokenType::CloseList => Some(atom!("]")),
+            TokenType::OpenCurly => Some(atom!("{")),
+            TokenType::CloseCurly => Some(atom!("}")),
+            TokenType::HeadTailSeparator => Some(atom!("|")),
+            TokenType::Comma => Some(atom!(",")),
+            TokenType::End => Some(atom!(".")),
+            _ => None,
+        }
+    }
+}
 
-    loop {
-        read_heap_cell!(tail,
-           (HeapCellValueTag::Lis, l) => {
-               read_heap_cell!(heap[l],
-                   (HeapCellValueTag::Atom, (atom, arity)) => {
-                       if arity == 0 {
-                           if let Some(c) = atom.as_char() {
-                               string.push(c);
-                           } else {
-                               return None;
-                           }
-                       } else {
-                           break;
-                       }
-                   }
-                   _ => {
-                       return None;
-                   }
-               );
-
-               tail = heap[l+1];
-           }
-           (HeapCellValueTag::PStrLoc, l) => {
-               let HeapStringScan { string: pstr, tail_idx } = heap.scan_slice_to_str(l);
-               string += pstr;
-               tail = heap[tail_idx];
-           }
-           (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-               if heap[h] != tail {
-                   tail = heap[h];
-               } else {
-                   break;
-               }
-           }
-           _ => {
-               // Anon
-               break;
-           }
-        );
+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![],
+        }
     }
 
-    read_heap_cell!(tail,
-       (HeapCellValueTag::Var) => {
-           Some((string, Some(tail)))
-       }
-       (HeapCellValueTag::Atom, (atom, arity)) => {
-           if atom == atom!("[]") && arity == 0 {
-               Some((string, None))
-           } else {
-               Some((string, Some(tail)))
-           }
-       }
-       _ => {
-           Some((string, Some(tail)))
-       }
-    )
-}
+    pub fn from_lexer(lexer: Lexer<'a, R>) -> Self {
+        Parser {
+            lexer,
+            tokens: vec![],
+            stack: vec![],
+            terms: vec![],
+        }
+    }
 
-impl<'a> Parser<'a> {
-    fn get_term_name(&self, td: TokenDesc) -> Option<Atom> {
+    fn get_term_name(&mut 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_predicate_key(&self.terms, heap_loc.get_value() as usize).map(|key| key.0)
-                } else {
+            TokenType::Term => match self.terms.pop() {
+                Some(Term::Literal(_, Literal::Atom(atom))) => Some(atom),
+                Some(term) => {
+                    self.terms.push(term);
                     None
                 }
-            }
+                _ => None,
+            },
             _ => None,
         }
     }
 
-    fn push_binary_op(
-        &mut self,
-        op: TokenDesc,
-        operand_1: TokenDesc,
-        operand_2: TokenDesc,
-        spec: Specifier,
-    ) {
-        if let TokenDesc {
-            tt: TokenType::Term { heap_loc: arg2 },
-            ..
-        } = operand_2
-        {
-            if let TokenDesc {
-                tt: TokenType::Term { heap_loc: arg1 },
-                ..
-            } = operand_1
-            {
-                if let Some(name) = self.get_term_name(op) {
-                    let str_loc = self.terms.cell_len();
-
-                    self.terms.write_with(|section| {
-                        section.push_cell(atom_as_cell!(name, 2));
-                        section.push_cell(arg1);
-                        section.push_cell(arg2);
-
-                        section.push_cell(str_loc_as_cell!(str_loc));
-                    });
+    fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) {
+        if let Some(arg2) = self.terms.pop() {
+            if let Some(name) = self.get_term_name(td) {
+                if let Some(arg1) = self.terms.pop() {
+                    let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]);
 
+                    self.terms.push(term);
                     self.stack.push(TokenDesc {
-                        tt: TokenType::Term {
-                            heap_loc: heap_loc_as_cell!(str_loc + 3),
-                        },
-                        priority: op.priority,
+                        tt: TokenType::Term,
+                        priority: td.priority,
                         spec,
                         unfold_bounds: 0,
                     });
@@ -358,31 +344,20 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn push_unary_op(&mut self, op: TokenDesc, operand: TokenDesc, spec: Specifier) {
-        if let TokenDesc {
-            tt: TokenType::Term { heap_loc: arg1 },
-            ..
-        } = operand
-        {
-            if let TokenDesc {
-                tt: TokenType::Term { .. },
-                ..
-            } = op
-            {
-                if let Some(name) = self.get_term_name(op) {
-                    let str_loc = self.terms.cell_len();
+    fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: OpDeclSpec) {
+        if let Some(mut arg1) = self.terms.pop() {
+            if let Some(mut name) = self.terms.pop() {
+                if assoc.is_postfix() {
+                    mem::swap(&mut arg1, &mut name);
+                }
 
-                    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));
-                    });
+                if let Term::Literal(_, Literal::Atom(name)) = name {
+                    let term = Term::Clause(Cell::default(), name, vec![arg1]);
 
+                    self.terms.push(term);
                     self.stack.push(TokenDesc {
-                        tt: TokenType::Term {
-                            heap_loc: heap_loc_as_cell!(str_loc + 2),
-                        },
-                        priority: op.priority,
+                        tt: TokenType::Term,
+                        priority: td.priority,
                         spec,
                         unfold_bounds: 0,
                     });
@@ -392,13 +367,10 @@ impl<'a> Parser<'a> {
     }
 
     fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) {
-        let h = self.terms.cell_len();
         self.terms
-            .write_with(|section| section.push_cell(atom_as_cell!(atom)));
+            .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
         self.stack.push(TokenDesc {
-            tt: TokenType::Term {
-                heap_loc: heap_loc_as_cell!(h),
-            },
+            tt: TokenType::Term,
             priority,
             spec: assoc,
             unfold_bounds: 0,
@@ -406,90 +378,42 @@ impl<'a> Parser<'a> {
     }
 
     fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
-        let heap_loc = heap_loc_as_cell!(self.terms.cell_len());
-
         let tt = match token {
-            Token::String(s) if self.flags.double_quotes.is_codes() => {
-                let mut list = empty_list_as_cell!();
-
-                self.terms.write_with(|section| {
-                    for c in s.as_str().chars().rev() {
-                        let h = section.cell_len();
-
-                        section.push_cell(fixnum_as_cell!(Fixnum::build_with(c as i64)));
-                        section.push_cell(list);
-
-                        list = list_loc_as_cell!(h);
-                    }
-
-                    section.push_cell(list);
-                });
+            Token::String(s) if self.lexer.machine_st.flags.double_quotes.is_codes() => {
+                let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
+
+                for c in s.as_str().chars().rev() {
+                    list = Term::Cons(
+                        Cell::default(),
+                        Box::new(Term::Literal(
+                            Cell::default(),
+                            Literal::Fixnum(Fixnum::build_with(c as i64)),
+                        )),
+                        Box::new(list),
+                    );
+                }
 
-                TokenType::Term { heap_loc: list }
+                self.terms.push(list);
+                TokenType::Term
             }
             Token::String(s) => {
-                debug_assert!(self.flags.double_quotes.is_chars());
-                let mut pstr_cell = heap_loc;
-
-                if s == "\u{0}" {
-                    let h = self.terms.cell_len();
-
-                    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,
-                    }
-                }
+                debug_assert!(self.lexer.machine_st.flags.double_quotes.is_chars());
+                self.terms
+                    .push(Term::CompleteString(Cell::default(), Rc::new(s)));
+                TokenType::Term
             }
             Token::Literal(c) => {
-                self.terms.write_with(|section| section.push_cell(c));
-                TokenType::Term { heap_loc }
+                self.terms.push(Term::Literal(Cell::default(), c));
+                TokenType::Term
             }
-            Token::Var(var_string) => {
-                let var = Rc::new(var_string);
-
-                match self.var_locs.get(&var).cloned() {
-                    Some(heap_loc) => {
-                        self.terms.write_with(|section| section.push_cell(heap_loc));
-                        TokenType::Term { heap_loc }
-                    }
-                    None => {
-                        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
-                        // anonymous.
-
-                        if var.trim() != "_" {
-                            self.var_locs.insert(var.clone(), heap_loc);
-                            self.inverse_var_locs
-                                .insert(heap_loc.get_value() as usize, var);
-                        }
-
-                        TokenType::Term { heap_loc }
-                    }
+            Token::Var(v) => {
+                if v.trim() == "_" {
+                    self.terms.push(Term::AnonVar);
+                } else {
+                    self.terms.push(Term::Var(Cell::default(), VarPtr::from(v)));
                 }
+
+                TokenType::Term
             }
             Token::Comma => TokenType::Comma,
             Token::Open => TokenType::Open,
@@ -519,10 +443,10 @@ impl<'a> Parser<'a> {
                         if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1)
                             || is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1)
                         {
-                            self.push_binary_op(desc2, desc3, desc1, LTERM);
+                            self.push_binary_op(desc2, LTERM);
                             continue;
                         } else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) {
-                            self.push_binary_op(desc2, desc3, desc1, TERM);
+                            self.push_binary_op(desc2, TERM);
                             continue;
                         } else {
                             self.stack.push(desc3);
@@ -530,16 +454,16 @@ impl<'a> Parser<'a> {
                     }
 
                     if is_yf!(desc1.spec) && affirm_yf(desc1, desc2) {
-                        self.push_unary_op(desc1, desc2, LTERM);
+                        self.push_unary_op(desc1, LTERM, YF);
                         continue;
                     } else if is_xf!(desc1.spec) && affirm_xf(desc1, desc2) {
-                        self.push_unary_op(desc1, desc2, LTERM);
+                        self.push_unary_op(desc1, LTERM, XF);
                         continue;
                     } else if is_fy!(desc2.spec) && affirm_fy(priority, desc1, desc2) {
-                        self.push_unary_op(desc2, desc1, TERM);
+                        self.push_unary_op(desc2, TERM, FY);
                         continue;
                     } else if is_fx!(desc2.spec) && affirm_fx(priority, desc1, desc2) {
-                        self.push_unary_op(desc2, desc1, TERM);
+                        self.push_unary_op(desc2, TERM, FX);
                         continue;
                     } else {
                         self.stack.push(desc2);
@@ -583,14 +507,6 @@ impl<'a> Parser<'a> {
         None
     }
 
-    fn term_from_stack(&self, idx: usize) -> Option<HeapCellValue> {
-        if let TokenType::Term { heap_loc } = self.stack[idx].tt {
-            Some(heap_loc)
-        } else {
-            None
-        }
-    }
-
     fn reduce_term(&mut self) -> bool {
         if self.stack.is_empty() {
             return false;
@@ -617,94 +533,39 @@ impl<'a> Parser<'a> {
             return false;
         }
 
-        if self.terms.cell_len() < arity {
+        if self.terms.len() < 1 + arity {
             return false;
         }
 
         let stack_len = self.stack.len() - 2 * arity - 1;
-        let term_idx = self.terms.cell_len();
-
-        let push_structure = |parser: &mut Self, name: Atom| -> TokenType {
-            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
-                    .write_with(|section| section.push_cell(subterm));
-            }
-
-            let str_loc_idx = parser.terms.cell_len();
-            parser
-                .terms
-                .write_with(|section| section.push_cell(str_loc_as_cell!(term_idx)));
+        let idx = self.terms.len() - arity;
 
-            TokenType::Term {
-                heap_loc: heap_loc_as_cell!(str_loc_idx),
-            }
-        };
-
-        if let TokenDesc {
-            tt: TokenType::Term { heap_loc },
-            ..
-        } = self.stack[stack_len]
+        if TokenType::Term == self.stack[stack_len].tt
+            && atomize_term(&self.terms[idx - 1]).is_some()
         {
-            let idx = heap_loc.get_value() as usize;
+            self.stack.truncate(stack_len + 1);
+
+            let mut subterms: Vec<_> = self.terms.drain(idx..).collect();
 
-            if let Some((name, arity)) = term_predicate_key(&self.terms, idx) {
+            if let Some(name) = self.terms.pop().and_then(|t| atomize_term(&t)) {
                 // 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, tail_opt)) => {
-                            let HeapSectionWriteResult { bytes_written, .. } =
-                                self.terms.write_with(|section| {
-                                    if let Some(pstr_cell) = section.push_pstr(&string_buf) {
-                                        section
-                                            .push_cell(tail_opt.unwrap_or(empty_list_as_cell!()));
-                                        section.push_cell(pstr_cell);
-                                    } else {
-                                        section.push_cell(empty_list_as_cell!());
-                                    }
-                                });
-
-                            if cell_index!(bytes_written) > 1 {
-                                TokenType::Term {
-                                    heap_loc: heap_loc_as_cell!(
-                                        cell_index!(bytes_written) - 1 + cell_len
-                                    ),
-                                }
-                            } else {
-                                TokenType::Term {
-                                    heap_loc: heap_loc_as_cell!(cell_len),
-                                }
-                            }
+                if name == atom!(".") && subterms.len() == 2 {
+                    let tail = subterms.pop().unwrap();
+                    let head = subterms.pop().unwrap();
+
+                    self.terms.push(match as_partial_string(head, tail) {
+                        Ok((string_buf, Some(tail))) => {
+                            Term::PartialString(Cell::default(), Rc::new(string_buf), tail)
                         }
-                        None => {
-                            let HeapSectionWriteResult { 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!(
-                                    cell_len + cell_index!(bytes_written) - 1
-                                ),
-                            }
+                        Ok((string_buf, None)) => {
+                            Term::CompleteString(Cell::default(), Rc::new(string_buf))
                         }
-                    }
+                        Err(term) => term,
+                    });
                 } else {
-                    push_structure(self, name)
-                };
-
-                self.stack.truncate(stack_len + 1);
+                    self.terms
+                        .push(Term::Clause(Cell::default(), name, subterms));
+                }
 
                 if let Some(&mut TokenDesc {
                     ref mut tt,
@@ -717,56 +578,38 @@ impl<'a> Parser<'a> {
                         return false;
                     }
 
-                    *tt = new_tt;
+                    *tt = TokenType::Term;
                     *priority = 0;
                     *spec = TERM;
                     *unfold_bounds = 0;
                 }
-            } else {
-                return false;
-            };
 
-            return true;
+                return true;
+            }
         }
 
         false
     }
 
-    fn loc_to_err_src(&self) -> ParserErrorSrc {
-        ParserErrorSrc {
-            line_num: *self.line_num,
-            col_num: *self.col_num,
-        }
+    pub fn reset(&mut self) {
+        self.stack.clear()
     }
 
     fn expand_comma_compacted_terms(&mut self, index: usize) -> usize {
-        if let Some(term) = self.term_from_stack(index - 1) {
+        if let Some(mut term) = self.terms.pop() {
             let mut op_desc = self.stack[index - 1];
-            let mut term = heap_bound_store(&self.terms, heap_bound_deref(&self.terms, term));
 
-            if term.is_ref()
-                && 0 < op_desc.priority
-                && op_desc.priority < self.stack[index].priority
-            {
+            if 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 key_opt = term_predicate_key(&self.terms, focus);
-
-                if key_opt == Some((atom!(","), 2)) {
+                if let (Some(atom!(",")), 2) = (term.name(), term.arity()) {
                     let terms = if op_desc.unfold_bounds == 0 {
-                        unfold_by_str(&mut self.terms, term, atom!(","))
+                        unfold_by_str(term, atom!(","))
                     } else {
                         let mut terms = vec![];
 
-                        while let Some(fst_loc) =
-                            unfold_by_str_once(&mut self.terms, term, atom!(","))
-                        {
-                            let (_, snd) = subterm_index(&self.terms, fst_loc + 1);
-                            let (_, fst) = subterm_index(&self.terms, fst_loc);
-
+                        while let Some((fst, snd)) = unfold_by_str_once(&mut term, atom!(",")) {
                             terms.push(fst);
                             term = snd;
 
@@ -782,16 +625,13 @@ impl<'a> Parser<'a> {
                     };
 
                     let arity = terms.len() - 1;
-                    self.stack
-                        .extend(terms.into_iter().map(|heap_loc| TokenDesc {
-                            tt: TokenType::Term { heap_loc },
-                            priority: 0,
-                            spec: 0,
-                            unfold_bounds: 0,
-                        }));
+
+                    self.terms.extend(terms);
                     return arity;
                 }
             }
+
+            self.terms.push(term);
         }
 
         0
@@ -831,18 +671,13 @@ impl<'a> Parser<'a> {
         }
 
         if let Some(ref mut td) = self.stack.last_mut() {
-            // parsed an empty list token
             if td.tt == TokenType::OpenList {
-                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 {
-                    heap_loc: heap_loc_as_cell!(h),
-                };
+                td.tt = TokenType::Term;
                 td.priority = 0;
 
+                self.terms
+                    .push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))));
                 return Ok(true);
             }
         }
@@ -856,99 +691,65 @@ impl<'a> Parser<'a> {
 
         // we know that self.stack.len() >= 2 by this point.
         let idx = self.stack.len() - 2;
-        let list_start_idx = self.stack.len() - 2 * arity;
+        let list_len = self.stack.len() - 2 * arity;
 
-        let mut tail_term = if self.stack[idx].tt != TokenType::HeadTailSeparator {
-            empty_list_as_cell!()
+        let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator {
+            Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))
         } else {
-            let tail_term = match self.term_from_stack(idx + 1) {
+            let term = match self.terms.pop() {
                 Some(term) => term,
-                None => {
-                    return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+                _ => {
+                    return Err(ParserError::IncompleteReduction(
+                        self.lexer.line_num,
+                        self.lexer.col_num,
+                    ))
                 }
             };
 
-            self.stack.pop();
-
             if self.stack[idx].priority > 1000 {
                 arity += self.expand_comma_compacted_terms(idx);
             }
 
-            // decrement for the removal of tail term.
-            arity -= 1;
-            tail_term
-        };
-
-        if arity > self.terms.cell_len() {
-            return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
-        }
-
-        let pre_terms_len = self.terms.cell_len();
-
-        while let Some(token_desc) = self.stack.pop() {
-            let subterm = match token_desc.tt {
-                TokenType::Term { heap_loc } => heap_loc,
-                _ => {
-                    continue;
-                }
-            };
-
             arity -= 1;
 
-            let link_cell = list_loc_as_cell!(self.terms.cell_len() + 1);
-
-            self.terms.write_with(|section| {
-                section.push_cell(link_cell);
-                section.push_cell(subterm);
-                section.push_cell(tail_term);
-            });
-
-            tail_term = link_cell;
+            term
+        };
 
-            if arity == 0 {
-                break;
-            }
+        if arity > self.terms.len() {
+            return Err(ParserError::IncompleteReduction(
+                self.lexer.line_num,
+                self.lexer.col_num,
+            ));
         }
 
-        debug_assert_eq!(arity, 0);
-
-        self.stack.truncate(list_start_idx);
-
-        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, tail_opt)) => {
-                self.terms.truncate(pre_terms_len);
+        let idx = self.terms.len() - arity;
 
-                let HeapSectionWriteResult { bytes_written, .. } =
-                    self.terms.write_with(|section| {
-                        if let Some(pstr_cell) = section.push_pstr(&string_buf) {
-                            section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!()));
-                            section.push_cell(pstr_cell);
-                        }
-                    });
+        let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| {
+            Term::Cons(Cell::default(), Box::new(t), Box::new(acc))
+        });
 
-                if bytes_written > 0 {
-                    heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1)
-                } else {
-                    empty_list_as_cell!()
-                }
-            }
-            None => {
-                heap_loc_as_cell!(list_loc) // head_term
-            }
-        };
+        self.stack.truncate(list_len);
 
         self.stack.push(TokenDesc {
-            tt: TokenType::Term { heap_loc },
+            tt: TokenType::Term,
             priority: 0,
             spec: TERM,
             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(), Rc::new(string_buf), tail)
+                }
+                Ok((string_buf, None)) => {
+                    Term::CompleteString(Cell::default(), Rc::new(string_buf))
+                }
+                Err(term) => term,
+            },
+            term => term,
+        });
+
         Ok(true)
     }
 
@@ -959,17 +760,13 @@ impl<'a> Parser<'a> {
 
         if let Some(ref mut td) = self.stack.last_mut() {
             if td.tt == TokenType::OpenCurly {
-                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),
-                };
+                td.tt = TokenType::Term;
                 td.priority = 0;
                 td.spec = TERM;
 
+                let term = Term::Literal(Cell::default(), Literal::Atom(atom!("{}")));
+
+                self.terms.push(term);
                 return Ok(true);
             }
         }
@@ -979,43 +776,29 @@ impl<'a> Parser<'a> {
         if self.stack.len() > 1 {
             if let Some(td) = self.stack.pop() {
                 if let Some(ref mut oc) = self.stack.last_mut() {
-                    if !matches!(td.tt, TokenType::Term { .. }) {
+                    if td.tt != TokenType::Term {
                         return Ok(false);
                     }
 
                     if oc.tt == TokenType::OpenCurly {
-                        if let TokenType::Term { heap_loc } = td.tt {
-                            let curly_idx = self.terms.cell_len();
-
-                            oc.tt = TokenType::Term {
-                                heap_loc: heap_loc_as_cell!(curly_idx + 2),
-                            };
-                            oc.priority = 0;
-                            oc.spec = TERM;
-
-                            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() {
-                                Some(term) => term,
-                                _ => {
-                                    return Err(ParserError::IncompleteReduction(
-                                        self.lexer.line_num,
-                                        self.lexer.col_num,
-                                    ))
-                                }
-                            };
-
-                            self.terms
-                                .push(Term::Clause(Cell::default(), atom!("{}"), vec![term]));
-                            */
-
-                            return Ok(true);
-                        }
+                        oc.tt = TokenType::Term;
+                        oc.priority = 0;
+                        oc.spec = TERM;
+
+                        let term = match self.terms.pop() {
+                            Some(term) => term,
+                            _ => {
+                                return Err(ParserError::IncompleteReduction(
+                                    self.lexer.line_num,
+                                    self.lexer.col_num,
+                                ))
+                            }
+                        };
+
+                        self.terms
+                            .push(Term::Clause(Cell::default(), atom!("{}"), vec![term]));
+
+                        return Ok(true);
                     }
                 }
             }
@@ -1035,9 +818,8 @@ impl<'a> Parser<'a> {
             return false;
         }
 
-        match self.stack.last().map(|token| token.tt) {
-            Some(TokenType::Open | TokenType::OpenCT) => return false,
-            _ => {}
+        if let Some(TokenType::Open | TokenType::OpenCT) = self.stack.last().map(|token| token.tt) {
+            return false;
         }
 
         let idx = self.stack.len() - 2;
@@ -1049,14 +831,13 @@ impl<'a> Parser<'a> {
                     return false;
                 }
 
-                let term = if self.stack[idx].tt.sep_to_atom().is_some() {
-                    atom_as_cell!(atom!("|"))
-                } else {
-                    self.term_from_stack(idx).unwrap()
-                };
+                if let Some(atom) = self.stack[idx].tt.sep_to_atom() {
+                    self.terms
+                        .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
+                }
 
                 self.stack[idx].spec = BTERM;
-                self.stack[idx].tt = TokenType::Term { heap_loc: term };
+                self.stack[idx].tt = TokenType::Term;
                 self.stack[idx].priority = 0;
 
                 true
@@ -1074,11 +855,7 @@ impl<'a> Parser<'a> {
         }) = get_op_desc(name, op_dir)
         {
             if (pre > 0 && inf + post > 0) || is_negate!(spec) {
-                match self
-                    .tokens
-                    .last()
-                    .ok_or(ParserError::unexpected_eof(self.loc_to_err_src()))?
-                {
+                match self.tokens.last().ok_or(ParserError::unexpected_eof())? {
                     // do this when layout hasn't been inserted,
                     // ie. why we don't match on Token::Open.
                     Token::OpenCT => {
@@ -1133,33 +910,31 @@ impl<'a> Parser<'a> {
     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) -> HeapCellValue,
+        ToLiteral: Fn(N, &mut Arena) -> Literal,
     {
-        match self.stack.last().cloned() {
-            Some(
-                td @ TokenDesc {
-                    tt: TokenType::Term { .. },
-                    spec,
-                    ..
-                },
-            ) => {
-                if let Some(name) = self.get_term_name(td) {
-                    if name == atom!("-") && (is_prefix!(spec) || is_negate!(spec)) {
+        if let Some(desc) = self.stack.last().cloned() {
+            if let Some(term) = self.terms.last().cloned() {
+                match term {
+                    Term::Literal(_, Literal::Atom(name))
+                        if name == atom!("-")
+                            && (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
+                    {
                         self.stack.pop();
+                        self.terms.pop();
 
-                        let arena = &mut self.arena;
+                        let arena = &mut self.lexer.machine_st.arena;
                         let literal = constr(negator(n, arena), arena);
 
                         self.shift(Token::Literal(literal), 0, TERM);
 
                         return;
                     }
+                    _ => {}
                 }
             }
-            _ => {}
         }
 
-        let literal = constr(n, &mut self.arena);
+        let literal = constr(n, &mut self.lexer.machine_st.arena);
         self.shift(Token::Literal(literal), 0, TERM);
     }
 
@@ -1180,58 +955,62 @@ impl<'a> Parser<'a> {
             Token::String(string) => {
                 self.shift(Token::String(string), 0, TERM);
             }
-            Token::Literal(c) => 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)) if n.is_infinite() => {
-                   return Err(ParserError::InfiniteFloat(
-                       self.loc_to_err_src(),
-                   ));
-               }
-                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 {
+            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)) if n.as_ptr().is_infinite() => {
+               return Err(ParserError::InfiniteFloat(
+                   self.lexer.line_num,
+                   self.lexer.col_num,
+               ));
+            }
+            Token::Literal(Literal::Float(n)) => self.negate_number(
+                **n.as_ptr(),
+                |n, _| -n,
+                |n, arena| Literal::from(float_alloc!(n, arena)),
+            ),
+            Token::Literal(Literal::Fixnum(n)) => {
+                self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n))
+            }
+            Token::Literal(c) => {
+                if let Literal::Atom(name) = c {
+                    if !self.shift_op(name, op_dir)? {
                         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),
             Token::Open => self.shift(Token::Open, 1300, DELIMITER),
             Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER),
             Token::Close => {
                 if !self.reduce_term() && !self.reduce_brackets() {
-                    return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+                    return Err(ParserError::IncompleteReduction(
+                        self.lexer.line_num,
+                        self.lexer.col_num,
+                    ));
                 }
             }
             Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER),
             Token::CloseList => {
                 if !self.reduce_list()? {
-                    return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+                    return Err(ParserError::IncompleteReduction(
+                        self.lexer.line_num,
+                        self.lexer.col_num,
+                    ));
                 }
             }
             Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER),
             Token::CloseCurly => {
                 if !self.reduce_curly()? {
-                    return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+                    return Err(ParserError::IncompleteReduction(
+                        self.lexer.line_num,
+                        self.lexer.col_num,
+                    ));
                 }
             }
             Token::HeadTailSeparator => {
@@ -1265,7 +1044,10 @@ impl<'a> Parser<'a> {
                 | Some(TokenType::OpenCurly)
                 | Some(TokenType::HeadTailSeparator)
                 | Some(TokenType::Comma) => {
-                    return Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
+                    return Err(ParserError::IncompleteReduction(
+                        self.lexer.line_num,
+                        self.lexer.col_num,
+                    ))
                 }
                 _ => {}
             },
@@ -1273,19 +1055,15 @@ impl<'a> Parser<'a> {
 
         Ok(())
     }
-}
 
-impl<'a, R: CharRead> LexerParser<'a, R> {
     #[inline]
-    pub fn line_num(&self) -> usize {
-        self.line_num
+    pub fn add_lines_read(&mut self, lines_read: usize) {
+        self.lexer.line_num += lines_read;
     }
 
-    pub fn loc_to_err_src(&self) -> ParserErrorSrc {
-        ParserErrorSrc {
-            line_num: self.line_num,
-            col_num: self.col_num,
-        }
+    #[inline]
+    pub fn lines_read(&self) -> usize {
+        self.lexer.line_num
     }
 
     // on success, returns the parsed term and the number of lines read.
@@ -1293,66 +1071,39 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
         &mut self,
         op_dir: &CompositeOpDir,
         tokens: Tokens,
-    ) -> Result<TermWriteResult, ParserError> {
-        let (tokens, term_byte_size) = match tokens {
-            Tokens::Default => read_tokens(self)?,
-            Tokens::Provided(tokens, size) => (tokens, size),
+    ) -> Result<Term, ParserError> {
+        self.tokens = match tokens {
+            Tokens::Default => read_tokens(&mut self.lexer)?,
+            Tokens::Provided(tokens) => tokens,
         };
 
-        // the parser uses conditional indirection in many places so
-        // the reserved size should be at least 4 * term_byte_size
-        // so all cells are accounted for.
-        let writer = match self
-            .machine_st
-            .heap
-            .reserve(cell_index!(4 * term_byte_size))
-        {
-            Ok(term) => term,
-            Err(_err_loc) => {
-                return Err(ParserError::ResourceError(self.loc_to_err_src()));
-            }
-        };
-
-        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)?;
+        while let Some(token) = self.tokens.pop() {
+            self.shift_token(token, op_dir)?;
         }
 
-        parser_impl.reduce_op(1400);
-
-        let after_len = parser_impl.terms.cell_len();
-
-        debug_assert!(after_len - before_len <= cell_index!(4 * term_byte_size));
+        self.reduce_op(1400);
 
-        if parser_impl.stack.len() > 1 || parser_impl.terms.is_empty() {
+        if self.terms.len() > 1 || self.stack.len() > 1 {
             return Err(ParserError::IncompleteReduction(
-                parser_impl.loc_to_err_src(),
+                self.lexer.line_num,
+                self.lexer.col_num,
             ));
         }
 
-        match parser_impl.stack.pop() {
-            Some(TokenDesc {
-                tt: TokenType::Term { heap_loc },
-                ..
-            }) => Ok(TermWriteResult {
-                focus: heap_loc.get_value() as usize,
-                inverse_var_locs: parser_impl.inverse_var_locs,
-            }),
+        match self.terms.pop() {
+            Some(term) => {
+                if self.terms.is_empty() {
+                    Ok(term)
+                } else {
+                    Err(ParserError::IncompleteReduction(
+                        self.lexer.line_num,
+                        self.lexer.col_num,
+                    ))
+                }
+            }
             _ => Err(ParserError::IncompleteReduction(
-                parser_impl.loc_to_err_src(),
+                self.lexer.line_num,
+                self.lexer.col_num,
             )),
         }
     }
index 9e3b4a7baff6f2d6a2cc23e859b59f12a6cc2051..da75741529e6147210000537978aeb1f7a01a7bf 100644 (file)
@@ -19,7 +19,7 @@ pub struct RawBlock<T: RawBlockTraits> {
 
 impl<T: RawBlockTraits> RawBlock<T> {
     #[inline]
-    pub(crate) fn empty_block() -> Self {
+    fn empty_block() -> Self {
         RawBlock {
             base: ptr::null(),
             top: ptr::null(),
index 549cdef0e5ff4fdc95f4f8dd5d914da873191af5..7b476b3e792266c8ca21b669b8d7dee2ba34b05a 100644 (file)
@@ -1,14 +1,21 @@
 use crate::parser::ast::*;
+use crate::parser::lexer::Lexer;
 use crate::parser::parser::*;
 
 use crate::atom_table::*;
+use crate::forms::*;
+use crate::iterators::*;
+use crate::machine::heap::*;
 use crate::machine::machine_errors::*;
+use crate::machine::machine_indices::*;
 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;
+use crate::types::*;
+
+use fxhash::FxBuildHasher;
 
 #[cfg(feature = "repl")]
 use rustyline::error::ReadlineError;
@@ -17,13 +24,16 @@ use rustyline::history::DefaultHistory;
 #[cfg(feature = "repl")]
 use rustyline::{Config, Editor};
 
+use std::collections::VecDeque;
 use std::io::{Cursor, Read};
 #[cfg(feature = "repl")]
 use std::io::{Error, ErrorKind};
 use std::sync::Arc;
 
+type SubtermDeque = VecDeque<(usize, usize)>;
+
 pub(crate) fn devour_whitespace<R: CharRead>(
-    lexer: &mut LexerParser<'_, R>,
+    lexer: &mut Lexer<'_, R>,
 ) -> Result<bool, ParserError> {
     match lexer.scan_for_layout() {
         Err(e) if e.is_unexpected_eof() => Ok(true),
@@ -32,16 +42,18 @@ pub(crate) fn devour_whitespace<R: CharRead>(
     }
 }
 
-pub(crate) fn error_after_read_term(
+pub(crate) fn error_after_read_term<R>(
     err: ParserError,
     prior_num_lines_read: usize,
+    parser: &Parser<R>,
 ) -> CompilationError {
     if err.is_unexpected_eof() {
-        let ParserErrorSrc { line_num, col_num } = err.err_src();
+        let line_num = parser.lexer.line_num;
+        let col_num = parser.lexer.col_num;
 
         // rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here
         if !(line_num == prior_num_lines_read && col_num == 0) {
-            return CompilationError::from(ParserError::IncompleteReduction(err.err_src()));
+            return CompilationError::from(ParserError::IncompleteReduction(line_num, col_num));
         }
     }
 
@@ -49,37 +61,27 @@ pub(crate) fn error_after_read_term(
 }
 
 impl MachineState {
-    pub(crate) fn read<R: CharRead>(
+    pub(crate) fn read(
         &mut self,
-        inner: R,
+        mut inner: Stream,
         op_dir: &OpDir,
-    ) -> Result<(TermWriteResult, usize), ParserError> {
-        let mut lexer_parser = LexerParser::new(inner, self);
-        let op_dir = CompositeOpDir::new(op_dir, None);
+    ) -> Result<TermWriteResult, CompilationError> {
+        let (term, num_lines_read) = {
+            let prior_num_lines_read = inner.lines_read();
+            let mut parser = Parser::new(inner, self);
+            let op_dir = CompositeOpDir::new(op_dir, None);
 
-        let term_result = lexer_parser.read_term(&op_dir, Tokens::Default);
-        let lines_read = lexer_parser.line_num();
+            parser.add_lines_read(prior_num_lines_read);
 
-        term_result.map(|term| (term, lines_read))
-    }
+            let term = parser
+                .read_term(&op_dir, Tokens::Default)
+                .map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from
 
-    pub(crate) fn read_to_heap(
-        &mut self,
-        mut inner: Stream,
-        op_dir: &OpDir,
-    ) -> Result<TermWriteResult, CompilationError> {
-        let prior_num_lines_read = inner.lines_read();
-        let term = match self.read(inner, op_dir) {
-            Ok((term, num_lines_read)) => {
-                inner.add_lines_read(num_lines_read);
-                term
-            }
-            Err(e) => {
-                return Err(error_after_read_term(e, prior_num_lines_read));
-            }
+            (term, parser.lines_read() - prior_num_lines_read)
         };
 
-        Ok(term)
+        inner.add_lines_read(num_lines_read);
+        write_term_to_heap(&term, &mut self.heap)
     }
 }
 
@@ -278,6 +280,7 @@ impl CharRead for ReadlineStream {
             }
         }
     }
+
     #[inline]
     fn consume(&mut self, nread: usize) {
         self.pending_input.consume(nread);
@@ -288,3 +291,217 @@ impl CharRead for ReadlineStream {
         self.pending_input.put_back_char(c);
     }
 }
+
+#[inline]
+pub(crate) fn write_term_to_heap(
+    term: &Term,
+    heap: &mut Heap,
+) -> Result<TermWriteResult, CompilationError> {
+    let term_writer = TermWriter::new(heap);
+    term_writer.write_term_to_heap(term)
+}
+
+#[derive(Debug)]
+struct TermWriter<'a> {
+    heap: &'a mut Heap,
+    queue: SubtermDeque,
+    var_dict: HeapVarDict,
+}
+
+#[derive(Debug)]
+pub struct TermWriteResult {
+    pub heap_loc: usize,
+    pub var_dict: HeapVarDict,
+}
+
+impl<'a> TermWriter<'a> {
+    #[inline]
+    fn new(heap: &'a mut Heap) -> Self {
+        TermWriter {
+            heap,
+            queue: SubtermDeque::new(),
+            var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
+        }
+    }
+
+    #[inline]
+    fn modify_head_of_queue(&mut self, term: &TermRef, h: usize) {
+        if let Some((arity, site_h)) = self.queue.pop_front() {
+            self.heap[site_h] = self.term_as_addr(term, h);
+
+            if arity > 1 {
+                self.queue.push_front((arity - 1, site_h + 1));
+            }
+        }
+    }
+
+    #[inline]
+    fn push_stub_addr(&mut self) -> Result<(), CompilationError> {
+        let h = self.heap.cell_len();
+        self.push_cell(heap_loc_as_cell!(h))
+    }
+
+    #[inline]
+    fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), CompilationError> {
+        self.heap
+            .push_cell(cell)
+            .map_err(|h| CompilationError::FiniteMemoryInHeap(h))
+    }
+
+    fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue {
+        match term {
+            &TermRef::Cons(..) => list_loc_as_cell!(h),
+            &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
+            TermRef::PartialString(..) | TermRef::CompleteString(..) => heap_loc_as_cell!(h),
+            &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal),
+            &TermRef::Clause(_, _, _, subterms) if subterms.is_empty() => heap_loc_as_cell!(h),
+            &TermRef::Clause(..) => str_loc_as_cell!(h),
+        }
+    }
+
+    fn write_term_to_heap(mut self, term: &Term) -> Result<TermWriteResult, CompilationError> {
+        let heap_loc = self.heap.cell_len();
+
+        for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
+            let h = self.heap.cell_len();
+
+            match &term {
+                &TermRef::Cons(Level::Root, ..) => {
+                    self.queue.push_back((2, h + 1));
+                    self.push_cell(list_loc_as_cell!(h + 1))?;
+
+                    self.push_stub_addr()?;
+                    self.push_stub_addr()?;
+
+                    continue;
+                }
+                &TermRef::Cons(..) => {
+                    self.queue.push_back((2, h));
+
+                    self.push_stub_addr()?;
+                    self.push_stub_addr()?;
+                }
+                &TermRef::Clause(Level::Root, _, name, subterms) => {
+                    if subterms.len() > MAX_ARITY {
+                        return Err(CompilationError::ExceededMaxArity);
+                    }
+
+                    self.push_cell(if subterms.is_empty() {
+                        heap_loc_as_cell!(heap_loc + 1)
+                    } else {
+                        str_loc_as_cell!(heap_loc + 1)
+                    })?;
+
+                    self.queue.push_back((subterms.len(), h + 2));
+                    let named = atom_as_cell!(name, subterms.len());
+
+                    self.push_cell(named)?;
+
+                    for _ in 0..subterms.len() {
+                        self.push_stub_addr()?;
+                    }
+
+                    continue;
+                }
+                &TermRef::Clause(_, _, name, subterms) => {
+                    self.queue.push_back((subterms.len(), h + 1));
+                    let named = atom_as_cell!(name, subterms.len());
+
+                    self.push_cell(named)?;
+
+                    for _ in 0..subterms.len() {
+                        self.push_stub_addr()?;
+                    }
+                }
+                &TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => {
+                    let addr = self.term_as_addr(&term, h);
+                    self.push_cell(addr)?;
+                }
+                &TermRef::Var(Level::Root, _, ref var_ptr) => {
+                    let addr = self.term_as_addr(&term, h);
+                    self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr);
+                    self.push_cell(addr)?;
+                }
+                &TermRef::AnonVar(_) => {
+                    if let Some((arity, site_h)) = self.queue.pop_front() {
+                        self.var_dict
+                            .insert(VarKey::AnonVar(h), heap_loc_as_cell!(site_h));
+
+                        if arity > 1 {
+                            self.queue.push_front((arity - 1, site_h + 1));
+                        }
+                    }
+
+                    continue;
+                }
+                TermRef::CompleteString(lvl, _, src) => {
+                    let cell = self
+                        .heap
+                        .allocate_cstr(src)
+                        .map_err(CompilationError::FiniteMemoryInHeap)?;
+
+                    let h = self.heap.cell_len();
+                    self.push_cell(cell)?;
+
+                    if !matches!(lvl, Level::Root) {
+                        self.modify_head_of_queue(&term, h);
+                    }
+
+                    continue;
+                }
+                TermRef::PartialString(lvl, _, src, _) => {
+                    if let Level::Root = lvl {
+                        self.push_stub_addr()?;
+                    }
+
+                    let cell = self
+                        .heap
+                        .allocate_pstr(src)
+                        .map_err(CompilationError::FiniteMemoryInHeap)?;
+
+                    let tail_h = self.heap.cell_len();
+                    self.push_stub_addr()?;
+
+                    if let Level::Root = lvl {
+                        self.heap[h] = cell;
+                    } else {
+                        self.push_cell(cell)?;
+                    };
+
+                    self.queue.push_back((1, tail_h));
+
+                    if !matches!(lvl, Level::Root) {
+                        self.modify_head_of_queue(&term, tail_h + 1);
+                    }
+
+                    continue;
+                }
+                TermRef::Var(.., var) => {
+                    if let Some((arity, site_h)) = self.queue.pop_front() {
+                        let var_key = VarKey::VarPtr(var.clone());
+
+                        if let Some(addr) = self.var_dict.get(&var_key).cloned() {
+                            self.heap[site_h] = addr;
+                        } else {
+                            self.var_dict.insert(var_key, heap_loc_as_cell!(site_h));
+                        }
+
+                        if arity > 1 {
+                            self.queue.push_front((arity - 1, site_h + 1));
+                        }
+                    }
+
+                    continue;
+                }
+                _ => {}
+            };
+
+            self.modify_head_of_queue(&term, h);
+        }
+
+        Ok(TermWriteResult {
+            heap_loc,
+            var_dict: self.var_dict,
+        })
+    }
+}
index bea12f5c8c28bae03070f98dbb2ee4f043d1086b..dbb036c2d74f533aabf80c6a37cc5f64777f6bcf 100644 (file)
@@ -3,6 +3,7 @@ use crate::parser::ast::*;
 use crate::atom_table::*;
 use crate::forms::*;
 use crate::instructions::*;
+use crate::iterators::*;
 use crate::types::*;
 
 use std::rc::Rc;
@@ -11,7 +12,11 @@ pub(crate) struct FactInstruction;
 pub(crate) struct QueryInstruction;
 
 pub(crate) trait CompilationTarget<'a> {
-    fn to_constant(lvl: Level, cell: HeapCellValue, r: RegType) -> Instruction;
+    type Iterator: Iterator<Item = TermRef<'a>>;
+
+    fn iter(term: &'a Term) -> Self::Iterator;
+
+    fn to_constant(lvl: Level, constant: Literal, r: RegType) -> Instruction;
     fn to_list(lvl: Level, r: RegType) -> Instruction;
     fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction;
 
@@ -22,7 +27,7 @@ pub(crate) trait CompilationTarget<'a> {
 
     fn incr_void_instr(instr: &mut Instruction);
 
-    fn constant_subterm(literal: HeapCellValue) -> Instruction;
+    fn constant_subterm(literal: Literal) -> Instruction;
 
     fn argument_to_variable(r: RegType, r: usize) -> Instruction;
     fn argument_to_value(r: RegType, val: usize) -> Instruction;
@@ -38,8 +43,14 @@ pub(crate) trait CompilationTarget<'a> {
 }
 
 impl<'a> CompilationTarget<'a> for FactInstruction {
-    fn to_constant(lvl: Level, cell: HeapCellValue, reg: RegType) -> Instruction {
-        Instruction::GetConstant(lvl, cell, reg)
+    type Iterator = FactIterator<'a>;
+
+    fn iter(term: &'a Term) -> Self::Iterator {
+        breadth_first_iter(term, RootIterationPolicy::NotIterated)
+    }
+
+    fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
+        Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
     }
 
     fn to_structure(lvl: Level, name: Atom, arity: usize, reg: RegType) -> Instruction {
@@ -68,8 +79,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
         }
     }
 
-    fn constant_subterm(constant: HeapCellValue) -> Instruction {
-        Instruction::UnifyConstant(constant)
+    fn constant_subterm(constant: Literal) -> Instruction {
+        Instruction::UnifyConstant(HeapCellValue::from(constant))
     }
 
     fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
@@ -106,8 +117,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
 }
 
 impl<'a> CompilationTarget<'a> for QueryInstruction {
-    fn to_constant(lvl: Level, constant: HeapCellValue, reg: RegType) -> Instruction {
-        Instruction::PutConstant(lvl, constant, reg)
+    type Iterator = QueryIterator<'a>;
+
+    fn iter(term: &'a Term) -> Self::Iterator {
+        post_order_iter(term)
     }
 
     fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction {
@@ -136,8 +149,12 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
         }
     }
 
-    fn constant_subterm(constant: HeapCellValue) -> Instruction {
-        Instruction::SetConstant(constant)
+    fn constant_subterm(constant: Literal) -> Instruction {
+        Instruction::SetConstant(HeapCellValue::from(constant))
+    }
+
+    fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
+        Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
     }
 
     fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
index 1a437413696dd21f6c1c7b0b570ddabf2dbd5848..a87fc22a99ed7f661ee1ab2e12edf4f23a944ddf 100644 (file)
@@ -46,7 +46,7 @@ test_queries_on_builtins :-
     \+ float([1,2,_]),
     \+ (X is 3 rdiv 4, float(X)),
     \+ \+ (X is 3 rdiv 4, rational(X)),
-    rational(3),
+    \+ rational(3),
     \+ rational(f(_)),
     \+ rational("sdfa"),
     \+ rational(atom),
index 7a0930196638e6a9690690b907977960f2263b21..18fda2ddc58ba6b6fe868b65aa95b0923789d571 100644 (file)
@@ -30,7 +30,7 @@ test_queries_on_call_with_inference_limit :-
             [true, 4],
             [!, 5]]),
     findall([R,X],
-           (call_with_inference_limit(g(X), 2, R), call(true)),
+           (call_with_inference_limit(g(X), 5, R), call(true)),
            [[true, 1],
             [true, 2],
             [inference_limit_exceeded, _]]),
index 67e482cc9b15f0236f4e19597fbff073906cc9d9..188f0974e393193425c036085dc3df2a339805f8 100644 (file)
@@ -7,6 +7,7 @@ use crate::machine::heap::*;
 use crate::machine::machine_indices::*;
 use crate::machine::streams::*;
 use crate::parser::ast::Fixnum;
+use crate::parser::ast::Literal;
 
 use std::cmp::Ordering;
 use std::convert::TryFrom;
@@ -14,6 +15,8 @@ use std::fmt;
 use std::mem;
 use std::ops::{Add, Sub, SubAssign};
 
+use dashu::{Integer, Rational};
+
 #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 #[repr(u8)]
 #[bits = 6]
@@ -307,6 +310,67 @@ impl fmt::Debug for HeapCellValue {
     }
 }
 
+impl From<Literal> for HeapCellValue {
+    #[inline]
+    fn from(literal: Literal) -> Self {
+        match literal {
+            Literal::Atom(name) => atom_as_cell!(name),
+            Literal::CodeIndex(ptr) => {
+                untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr))
+            }
+            Literal::Fixnum(n) => fixnum_as_cell!(n),
+            Literal::Integer(bigint_ptr) => {
+                typed_arena_ptr_as_cell!(bigint_ptr)
+            }
+            Literal::Rational(bigint_ptr) => {
+                typed_arena_ptr_as_cell!(bigint_ptr)
+            }
+            Literal::Float(f) => HeapCellValue::from(f.as_ptr()),
+        }
+    }
+}
+
+impl TryFrom<HeapCellValue> for Literal {
+    type Error = ();
+
+    fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
+        read_heap_cell!(value,
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                if arity == 0 {
+                    Ok(Literal::Atom(name))
+                } else {
+                    Err(())
+                }
+            }
+            (HeapCellValueTag::Fixnum, n) => {
+                Ok(Literal::Fixnum(n))
+            }
+            (HeapCellValueTag::F64, f) => {
+                Ok(Literal::Float(f.as_offset()))
+            }
+            (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(())
+                     }
+                )
+            }
+            _ => {
+                Err(())
+            }
+        )
+    }
+}
+
 impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue
 where
     T::Payload: Sized,
index a22e5be18785059606efc2b4928aea180f7ed70f..c918067e4e5c961452d633fd2ce1ff2ec5197e6a 100644 (file)
@@ -88,10 +88,7 @@ pub enum VarAlloc {
         safety: VarSafetyStatus,
         to_perm_var_num: Option<usize>,
     },
-    Perm {
-        reg: usize,
-        allocation: PermVarAllocation,
-    }, // stack offset, allocation info
+    Perm(usize, PermVarAllocation), // stack offset, allocation info
 }
 
 impl VarAlloc {
@@ -99,14 +96,14 @@ impl VarAlloc {
     pub(crate) fn as_reg_type(&self) -> RegType {
         match *self {
             VarAlloc::Temp { temp_reg, .. } => RegType::Temp(temp_reg),
-            VarAlloc::Perm { reg, .. } => RegType::Perm(reg),
+            VarAlloc::Perm(r, _) => RegType::Perm(r),
         }
     }
 
     #[inline]
     pub(crate) fn set_register(&mut self, reg_num: usize) {
         match self {
-            VarAlloc::Perm { ref mut reg, .. } => *reg = reg_num,
+            VarAlloc::Perm(ref mut p, _) => *p = reg_num,
             VarAlloc::Temp {
                 ref mut temp_reg, ..
             } => *temp_reg = reg_num,
@@ -155,10 +152,7 @@ pub struct VariableRecord {
 impl Default for VariableRecord {
     fn default() -> Self {
         VariableRecord {
-            allocation: VarAlloc::Perm {
-                reg: 0,
-                allocation: PermVarAllocation::Pending,
-            },
+            allocation: VarAlloc::Perm(0, PermVarAllocation::Pending),
             num_occurrences: 0,
             running_count: 0,
         }
index 10b85c10dae2acd6314d1b430f3ae4dad81a37cd..eea347ccd96050f1b3977e42ce0ef441aa814204 100644 (file)
@@ -761,7 +761,8 @@ test_171 :- writeq_term_to_chars("a", C),
 
 test_229 :- test_syntax_error("\"\\z.\"", syntax_error(missing_quote)).
 
-test_300 :- writeq_term_to_chars("\0\", C),
+test_300 :- '$debug_hook',
+            writeq_term_to_chars("\0\", C),
             C == "['\\x0\\']".
 
 test_172 :- X is 10.0** -323,
index a187f14d50d3d1340e427b06f8c03df065c9177c..f0edd5d866c6fb529f8e19391e2d980e1ef96d57 100644 (file)
@@ -35,7 +35,7 @@ fn hello_world() {
 fn syntax_error() {
     load_module_test(
         "tests-pl/syntax_error.pl",
-        "   error(syntax_error(incomplete_reduction),read_term/3:3).\n",
+        "   error(syntax_error(incomplete_reduction),read_term/3:6).\n",
     );
 }