]> Repositorios git - scryer-prolog.git/commitdiff
variable revision
authorMark Thom <[email protected]>
Wed, 31 Jul 2024 20:04:55 +0000 (14:04 -0600)
committerMark Thom <[email protected]>
Wed, 23 Apr 2025 06:32:32 +0000 (23:32 -0700)
22 files changed:
build/instructions_template.rs
src/allocator.rs
src/arithmetic.rs
src/codegen.rs
src/debray_allocator.rs
src/forms.rs
src/heap_print.rs
src/iterators.rs
src/machine/arithmetic_ops.rs
src/machine/compile.rs
src/machine/disjuncts.rs
src/machine/gc.rs
src/machine/lib_machine/mod.rs
src/machine/loader.rs
src/machine/machine_errors.rs
src/machine/machine_state.rs
src/machine/mock_wam.rs
src/parser/ast.rs
src/parser/parser.rs
src/read.rs
src/tests/call_with_inference_limit.pl
src/variable_records.rs

index eaf1881cecdb1fc4e32a59eae9aab43c0866c07b..84d0abadbcc82ac788ac20f143c46df4688edc87 100644 (file)
@@ -911,7 +911,7 @@ fn generate_instruction_preface() -> TokenStream {
                         functor!(atom!("intermediate"), [fixnum(i)])
                     }
                     ArithmeticTerm::Number(n) => {
-                        vec![HeapCellValue::from((n, arena))]
+                        functor!(atom!("number"), [cell(HeapCellValue::from((n, arena)))])
                     }
                 }
             }
index cd32f41fed6e47f568ab4fcb3e5f76900b85a6ff..27def1d670d922ec2311ac1ff4509e351990deb9 100644 (file)
@@ -12,7 +12,7 @@ pub(crate) trait Allocator {
         lvl: Level,
         context: GenContext,
         code: &mut CodeDeque,
-    );
+    ) -> RegType;
 
     fn mark_non_var<'a, Target: CompilationTarget<'a>>(
         &mut self,
index c26d3cec7cfa055eb5b02b036592c91b61dae916..9253ee49b3bd65444c86303a9b1a0bfef12b6265 100644 (file)
@@ -7,6 +7,7 @@ use crate::debray_allocator::*;
 use crate::forms::*;
 use crate::instructions::*;
 use crate::iterators::*;
+use crate::machine::disjuncts::*;
 use crate::machine::stack::Stack;
 use crate::parser::ast::FocusedHeap;
 use crate::targets::QueryInstruction;
@@ -173,7 +174,7 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: Literal) -> Result<(), Arit
         Literal::Atom(name) if name == atom!("epsilon") => interm.push(ArithmeticTerm::Number(
             Number::Float(OrderedFloat(f64::EPSILON)),
         )),
-        _ => return Err(ArithmeticError::NonEvaluableFunctor(c, 0)),
+        _ => return Err(ArithmeticError::NonEvaluableFunctor(HeapCellValue::from(c), 0)),
     }
 
     Ok(())
@@ -216,7 +217,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(Literal::Atom(name), 1)),
+            _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 1)),
         }
     }
 
@@ -248,7 +249,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(Literal::Atom(name), 2)),
+            _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 2)),
         }
     }
 
@@ -304,7 +305,7 @@ impl<'a> ArithmeticEvaluator<'a> {
                 self.get_binary_instr(name, a1, a2, ninterm)
             }
             _ => Err(ArithmeticError::NonEvaluableFunctor(
-                Literal::Atom(name),
+                atom_as_cell!(name),
                 arity,
             )),
         }
@@ -321,30 +322,38 @@ impl<'a> ArithmeticEvaluator<'a> {
         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, h) => {
+                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
                     let lvl = iter.level();
-                    let var_ptr = src.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                    let var_num = var_ptr.to_var_num().unwrap();
-                    let old_r = self.marker.get_var_binding(var_num);
-
-                    let r = 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
+
+                    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)
                         }
-                    } else {
-                        self.marker.increment_running_count(var_num);
-                        old_r
                     };
 
                     self.interm.push(ArithmeticTerm::Reg(r));
@@ -359,7 +368,7 @@ impl<'a> ArithmeticEvaluator<'a> {
                 _ => {
                     match Literal::try_from(term) {
                         Ok(lit) => push_literal(&mut self.interm, lit)?,
-                        _ => unreachable!()
+                        _ => return Err(ArithmeticError::NonEvaluableFunctor(term, 0)),
                     }
                 }
             );
@@ -547,6 +556,7 @@ impl Div<Number> for Number {
     }
 }
 
+
 impl PartialEq for Number {
     fn eq(&self, rhs: &Self) -> bool {
         match (self, rhs) {
@@ -630,6 +640,7 @@ impl PartialOrd for Number {
     }
 }
 
+
 impl Ord for Number {
     fn cmp(&self, rhs: &Number) -> Ordering {
         match (self, rhs) {
index 24f90c8b771e45f5cb1d74357823dff89f248e90..06d8c8e4c09c74d8fca9372f6e1ac21394e7be21 100644 (file)
@@ -420,28 +420,27 @@ impl<'b> CodeGenerator<'b> {
     fn subterm_to_instr<'a, Target: crate::targets::CompilationTarget<'a>>(
         &mut self,
         subterm: HeapCellValue,
-        var_locs: &mut VarLocs,
         heap_loc: usize,
         context: GenContext,
         index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
         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, h) => {
-                let var_ptr = var_locs.read_next_var_ptr_at_key(h).unwrap();
-
-                if var_ptr.is_anon() {
-                    Self::add_or_increment_void_instr::<Target>(target);
-                } else {
-                    let var_num = var_ptr.to_var_num().unwrap();
-
-                    self.deep_var_instr::<Target>(
-                        var_num,
-                        context,
-                        target,
-                    );
+            (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
@@ -482,7 +481,6 @@ impl<'b> CodeGenerator<'b> {
         &mut self,
         mut iter: Iter,
         index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
-        var_locs: &mut VarLocs,
         context: GenContext,
     ) -> CodeDeque
     where
@@ -491,29 +489,33 @@ impl<'b> CodeGenerator<'b> {
         CodeGenerator<'b>: 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, h) => {
+                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
                     if lvl == Level::Shallow {
-                        let var_ptr = var_locs.read_next_var_ptr_at_key(h).unwrap();
-
-                        if var_ptr.is_anon() {
-                            if let GenContext::Head = context {
-                                self.marker.advance_arg();
-                            } else {
-                                self.marker.mark_anon_var::<Target>(lvl, context, &mut target);
+                        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);
+                                }
                             }
-                        } else {
-                            self.marker.mark_var::<Target>(
-                                var_ptr.to_var_num().unwrap(),
-                                lvl,
-                                context,
-                                &mut target,
-                            );
                         }
                     }
                 }
@@ -544,7 +546,7 @@ impl<'b> CodeGenerator<'b> {
                                 let (subterm_loc, subterm) = subterm_index(iter.deref(), subterm_loc);
 
                                 self.subterm_to_instr::<Target>(
-                                    subterm, var_locs, subterm_loc, context, index_ptrs, &mut target,
+                                    subterm, subterm_loc, context, index_ptrs, &mut target,
                                 )
                             })
                             .collect();
@@ -580,7 +582,6 @@ impl<'b> CodeGenerator<'b> {
 
                     let head_r_opt = self.subterm_to_instr::<Target>(
                         head,
-                        var_locs,
                         head_loc,
                         context,
                         index_ptrs,
@@ -589,7 +590,6 @@ impl<'b> CodeGenerator<'b> {
 
                     let tail_r_opt = self.subterm_to_instr::<Target>(
                         tail,
-                        var_locs,
                         tail_loc,
                         context,
                         index_ptrs,
@@ -623,7 +623,7 @@ impl<'b> CodeGenerator<'b> {
 
                     let (tail_loc, tail) = subterm_index(iter.deref(), heap_loc + 1);
                     self.subterm_to_instr::<Target>(
-                        tail, var_locs, tail_loc, context, index_ptrs, &mut target,
+                        tail, tail_loc, context, index_ptrs, &mut target,
                     );
                 }
                 (HeapCellValueTag::PStrOffset, l) => {
@@ -644,7 +644,7 @@ impl<'b> CodeGenerator<'b> {
                     target.push_back(Target::to_pstr(lvl, pstr_offset_atom, r, true));
 
                     self.subterm_to_instr::<Target>(
-                        tail, var_locs, tail_loc, context, index_ptrs, &mut target,
+                        tail, tail_loc, context, index_ptrs, &mut target,
                     );
                 }
                 _ if lvl == Level::Shallow => {
@@ -693,21 +693,53 @@ impl<'b> CodeGenerator<'b> {
         context: GenContext,
         code: &mut CodeDeque,
     ) -> Result<(), CompilationError> {
-        let term = terms.heap[terms.nth_arg(term_loc, 1).unwrap()];
+        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) =
-                    self.compile_arith_expr(terms, term_loc + 1, 1, context, 1)?;
-
-                if !terms.deref_loc(term_loc + 1).is_var() {
-                    self.marker.advance_arg();
-                }
+                    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 rcode, at_2) =
-                    self.compile_arith_expr(terms, term_loc + 2, 2, context, 2)?;
+                    self.compile_arith_expr(terms, first_arg_loc + 1, 2, context, 2)?;
 
                 code.append(&mut lcode);
                 code.append(&mut rcode);
@@ -717,299 +749,200 @@ impl<'b> CodeGenerator<'b> {
 
                 compare_number_instr!(cmp, at_1, at_2)
             }
-            InlinedClauseType::IsAtom(..) => read_heap_cell!(term,
-                (HeapCellValueTag::Atom, (_name, arity)) => {
-                    if arity == 0 {
-                        instr!("$succeed")
-                    } else {
-                        instr!("$fail")
-                    }
-                }
-                (HeapCellValueTag::Char) => {
-                    instr!("$succeed")
-                }
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                    let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                    self.marker.reset_arg(1);
-
-                    if var_ptr.is_anon() {
-                        instr!("$fail")
-                    } else {
-                        let r = self.marker.mark_non_callable(
-                            var_ptr.to_var_num().unwrap(),
-                            1,
-                            context,
-                            code,
-                        );
-
-                        instr!("atom", r)
-                    }
-                }
-                _ => {
-                    instr!("$fail")
-                }
-            ),
-            InlinedClauseType::IsAtomic(..) => read_heap_cell!(term,
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                    let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-
-                    if var_ptr.is_anon() {
-                        instr!("$fail")
-                    } else {
-                        self.marker.reset_arg(1);
-
-                        let r = self.marker.mark_non_callable(
-                            var_ptr.to_var_num().unwrap(),
-                            1,
-                            context,
-                            code,
-                        );
+            InlinedClauseType::IsAtom(..) => {
+                self.marker.reset_arg(1);
 
-                        instr!("atomic", r)
-                    }
-                }
-                (HeapCellValueTag::Fixnum |
-                 HeapCellValueTag::Char |
-                 HeapCellValueTag::F64) => {
-                    instr!("$succeed")
-                }
-                (HeapCellValueTag::Cons, cons_ptr) => {
-                    match cons_ptr.get_tag() {
-                        ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => {
+                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")
+                            }
+                        }
+                        (HeapCellValueTag::Char) => {
                             instr!("$succeed")
                         }
                         _ => {
                             instr!("$fail")
                         }
-                    }
+                    )
                 }
-                (HeapCellValueTag::Atom, (_name, arity)) => {
-                    if arity == 0 {
-                        instr!("$succeed")
-                    } else {
-                        instr!("$fail")
-                    }
-                }
-                (HeapCellValueTag::Lis
-                 | HeapCellValueTag::Str
-                 | HeapCellValueTag::PStrLoc
-                 | HeapCellValueTag::CStr) => {
-                    instr!("$fail")
-                }
-                _ => {
-                    if Literal::try_from(term).is_ok() {
-                        instr!("$succeed")
-                    } else {
-                        instr!("$fail")
-                    }
+            }
+            InlinedClauseType::IsAtomic(..) => {
+                self.marker.reset_arg(1);
+
+                if let Some(r) = variable_marker(&mut self.marker) {
+                    instr!("atomic", r)
+                } else {
+                   read_heap_cell!(first_arg,
+                       (HeapCellValueTag::Fixnum |
+                        HeapCellValueTag::Char |
+                        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
+                        | HeapCellValueTag::CStr) => {
+                           instr!("$fail")
+                       }
+                       _ => {
+                           if Literal::try_from(first_arg).is_ok() {
+                               instr!("$succeed")
+                           } else {
+                               instr!("$fail")
+                           }
+                       }
+                   )
                 }
-            ),
+            }
             InlinedClauseType::IsCompound(..) => {
-                read_heap_cell!(term,
-                    (HeapCellValueTag::Atom, (_, arity)) => {
-                        if arity > 0 {
+                self.marker.reset_arg(1);
+
+                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
+                         | HeapCellValueTag::CStr) => {
                             instr!("$succeed")
-                        } else {
-                            instr!("$fail")
                         }
-                    }
-                    (HeapCellValueTag::Lis
-                     | HeapCellValueTag::Str
-                     | HeapCellValueTag::PStrLoc
-                     | HeapCellValueTag::CStr) => {
-                        instr!("$succeed")
-                    }
-                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                        let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-
-                        if var_ptr.is_anon() {
+                        _ => {
                             instr!("$fail")
-                        } else {
-                            self.marker.reset_arg(1);
-
-                            let r = self.marker.mark_non_callable(
-                                var_ptr.to_var_num().unwrap(),
-                                1,
-                                context,
-                                code,
-                            );
-
-                            instr!("compound", r)
                         }
-                    }
-                    _ => {
-                        instr!("$fail")
-                    }
-                )
+                    )
+                }
             }
             InlinedClauseType::IsRational(..) => {
-                read_heap_cell!(term,
-                    (HeapCellValueTag::Cons, cons_ptr) => {
-                        match cons_ptr.get_tag() {
-                            ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => {
-                                instr!("$succeed")
-                            }
-                            _ => {
-                                instr!("$fail")
+                self.marker.reset_arg(1);
+
+                if let Some(r) = variable_marker(&mut self.marker) {
+                    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")
-                    }
-                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                        let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                        self.marker.reset_arg(1);
-
-                        if var_ptr.is_anon() {
+                        (HeapCellValueTag::Fixnum) => {
+                            instr!("$succeed")
+                        }
+                        _ => {
                             instr!("$fail")
-                        } else {
-                            let r = self.marker.mark_non_callable(
-                                var_ptr.to_var_num().unwrap(),
-                                1,
-                                context,
-                                code,
-                            );
-
-                            instr!("rational", r)
                         }
-                    }
-                    _ => {
-                        instr!("$fail")
-                    }
-                )
-            }
-            InlinedClauseType::IsFloat(..) => read_heap_cell!(term,
-                (HeapCellValueTag::F64) => {
-                    instr!("$succeed")
-                }
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                    let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                    self.marker.reset_arg(1);
-
-                    if var_ptr.is_anon() {
-                        instr!("$fail")
-                    } else {
-                        let r = self.marker.mark_non_callable(
-                            var_ptr.to_var_num().unwrap(),
-                            1,
-                            context,
-                            code,
-                        );
-
-                        instr!("float", r)
-                    }
-                }
-                _ => {
-                    instr!("$fail")
+                    )
                 }
-            ),
-            InlinedClauseType::IsNumber(..) => read_heap_cell!(term,
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                    let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                    self.marker.reset_arg(1);
-
-                    if var_ptr.is_anon() {
-                        instr!("$fail")
-                    } else {
-                        let r = self.marker.mark_non_callable(
-                            var_ptr.to_var_num().unwrap(),
-                            1,
-                            context,
-                            code,
-                        );
+            }
+            InlinedClauseType::IsFloat(..) => {
+                self.marker.reset_arg(1);
 
-                        instr!("number", r)
-                    }
+                if let Some(r) = variable_marker(&mut self.marker) {
+                    instr!("float", r)
+                } else {
+                    read_heap_cell!(first_arg,
+                        (HeapCellValueTag::F64) => {
+                            instr!("$succeed")
+                        }
+                        _ => {
+                            instr!("$fail")
+                        }
+                    )
                 }
-                _ => {
-                    if Number::try_from(term).is_ok() {
+            }
+            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!("$succeed")
                     } else {
                         instr!("$fail")
                     }
                 }
-            ),
-            InlinedClauseType::IsNonVar(..) => read_heap_cell!(term,
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                    let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                    self.marker.reset_arg(1);
+            }
+            InlinedClauseType::IsNonVar(..) => {
+                self.marker.reset_arg(1);
 
-                    if var_ptr.is_anon() {
+                if let Some(r) = variable_marker(&mut self.marker) {
+                    instr!("nonvar", r)
+                } else {
+                    if first_arg.is_var() {
                         instr!("$fail")
                     } else {
-                        let r = self.marker.mark_non_callable(
-                            var_ptr.to_var_num().unwrap(),
-                            1,
-                            context,
-                            code,
-                        );
-
-                        instr!("nonvar", r)
+                        instr!("$succeed")
                     }
                 }
-                _ => {
-                    instr!("$succeed")
-                }
-            ),
+            }
             InlinedClauseType::IsInteger(..) => {
-                read_heap_cell!(term,
-                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                        let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                        self.marker.reset_arg(1);
+                self.marker.reset_arg(1);
 
-                        if var_ptr.is_anon() {
-                            instr!("$fail")
-                        } else {
-                            let r = self.marker.mark_non_callable(
-                                var_ptr.to_var_num().unwrap(),
-                                1,
-                                context,
-                                code,
-                            );
-
-                            instr!("integer", r)
+                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")
                         }
-                    }
-                    _ => {
-                        match Number::try_from(term) {
-                            Ok(Number::Integer(_) | Number::Fixnum(_)) => {
-                                instr!("$succeed")
-                            }
-                            _ => {
-                                instr!("$fail")
-                            }
+                        _ => {
+                            instr!("$fail")
                         }
                     }
-                )
-            }
-            InlinedClauseType::IsVar(..) => read_heap_cell!(term,
-                (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                    let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                    self.marker.reset_arg(1);
+                }
+            },
+            InlinedClauseType::IsVar(..) => {
+                self.marker.reset_arg(1);
 
-                    if var_ptr.is_anon() {
+                if let Some(r) = variable_marker(&mut self.marker) {
+                    instr!("var", r)
+                } else {
+                    if first_arg.is_var() {
                         instr!("$succeed")
                     } else {
-                        let r = self.marker.mark_non_callable(
-                            var_ptr.to_var_num().unwrap(),
-                            1,
-                            context,
-                            code,
-                        );
-
-                        instr!("var", r)
+                        instr!("$fail")
                     }
                 }
-                _ => {
-                    instr!("$fail")
-                }
-            ),
+            },
         };
 
         // inlined predicates are never counted, so this overrides nothing.
         self.add_call(code, call_instr, CallPolicy::Counted);
-
         Ok(())
     }
 
@@ -1052,34 +985,15 @@ impl<'b> CodeGenerator<'b> {
         };
 
         let at = read_heap_cell!(var,
-            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
-                let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                let var_num = var_ptr.to_var_num().unwrap();
-
-                if self.marker.var_data.records[var_num].num_occurrences > 1 {
-                    self.marker.mark_var::<QueryInstruction>(
-                        var_num,
-                        Level::Shallow,
-                        context,
-                        code,
-                    );
-
-                    self.marker.mark_safe_var_unconditionally(var_num);
-                    compile_expr!(self, terms, context, code)
-                } else {
-                    /*
-                    if var.is_var() {
-                        let h = var.get_value() as usize;
-
-                        let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
-                        let var_num = var_ptr.to_var_num().unwrap();
-
-                        // if var is an anonymous variable, insert
-                        // is/2 call so that an instantiation error is
-                        // thrown when the predicate is run.
+            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
+                let chunk_num = context.chunk_num();
 
+                match self.marker.var_data.var_locs_to_nums.get(
+                    VarPtrIndex { chunk_num, term_loc },
+                ) {
+                    VarPtr::Numbered(var_num) => {
                         if self.marker.var_data.records[var_num].num_occurrences > 1 {
-                            let r = self.marker.mark_var::<QueryInstruction>(
+                            self.marker.mark_var::<QueryInstruction>(
                                 var_num,
                                 Level::Shallow,
                                 context,
@@ -1087,17 +1001,12 @@ impl<'b> CodeGenerator<'b> {
                             );
 
                             self.marker.mark_safe_var_unconditionally(var_num);
-
-                            let at = ArithmeticTerm::Reg(r);
-                            self.add_call(code, instr!("$get_number", at), call_policy);
-
-                            return Ok(());
                         }
                     }
-                    */
+                    VarPtr::Anon => {}
+                };
 
-                    compile_expr!(self, terms, context, code)
-                }
+                compile_expr!(self, terms, context, code)
             }
             _ => {
                 if Number::try_from(var).is_ok() {
@@ -1115,25 +1024,23 @@ impl<'b> CodeGenerator<'b> {
 
         let at = at.unwrap_or(interm!(1));
         self.add_call(code, instr!("is", temp_v!(1), at), call_policy);
-
         Ok(())
     }
 
     fn compile_seq(
         &mut self,
-        terms: &mut FocusedHeap,
+        focused_heap: &mut FocusedHeap,
         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) => {
-                    for (idx, term) in chunk.iter().enumerate() {
-                        let context = if idx + 1 < chunk.len() {
+                ClauseItem::Chunk { chunk_num, terms } => {
+                    for (idx, term) in terms.iter().enumerate() {
+                        let context = if idx + 1 < terms.len() {
                             GenContext::Mid(chunk_num)
                         } else {
                             self.marker.in_tail_position = clause_iter.in_tail_position();
@@ -1201,7 +1108,7 @@ impl<'b> CodeGenerator<'b> {
                                     ..
                                 },
                             ) => self.compile_is_call(
-                                terms,
+                                focused_heap,
                                 clause.term_loc(),
                                 branch_code_stack.code(code),
                                 context,
@@ -1214,7 +1121,7 @@ impl<'b> CodeGenerator<'b> {
                                 },
                             ) => self.compile_inlined(
                                 ct,
-                                terms,
+                                focused_heap,
                                 clause.term_loc(),
                                 context,
                                 branch_code_stack.code(code),
@@ -1241,7 +1148,7 @@ impl<'b> CodeGenerator<'b> {
                             }
                             QueryTerm::Clause(clause) => {
                                 self.compile_query_line(
-                                    terms,
+                                    focused_heap,
                                     clause,
                                     context,
                                     branch_code_stack.code(code),
@@ -1254,7 +1161,6 @@ impl<'b> CodeGenerator<'b> {
                         }
                     }
 
-                    chunk_num += 1;
                     self.marker.in_tail_position = false;
                     self.marker.reset_contents();
                 }
@@ -1324,7 +1230,6 @@ impl<'b> CodeGenerator<'b> {
         let fact = self.compile_target::<FactInstruction, _>(
             iter,
             &IndexMap::with_hasher(FxBuildHasher::default()),
-            &mut term.var_locs,
             GenContext::Head,
         );
 
@@ -1360,7 +1265,6 @@ impl<'b> CodeGenerator<'b> {
         let compiled_fact = self.compile_target::<FactInstruction, _>(
             iter,
             &IndexMap::with_hasher(FxBuildHasher::default()),
-            &mut fact.term.var_locs,
             GenContext::Head,
         );
 
@@ -1389,7 +1293,6 @@ impl<'b> CodeGenerator<'b> {
         let query = self.compile_target::<QueryInstruction, _>(
             iter,
             &clause.code_indices,
-            &mut term.var_locs,
             context,
         );
 
index b473d9d134522ee0dd9621e342e3761230cb8d0c..4577b1e6268a76670a9150d38c77a1cad3dac8da 100644 (file)
@@ -1,9 +1,9 @@
 use crate::allocator::*;
 use crate::atom_table::*;
 use crate::codegen::SubsumedBranchHits;
-use crate::forms::Level;
+use crate::forms::{GenContext, Level};
 use crate::instructions::*;
-use crate::machine::disjuncts::VarData;
+use crate::machine::disjuncts::*;
 use crate::machine::heap::{heap_bound_deref, heap_bound_store};
 use crate::parser::ast::*;
 use crate::targets::*;
@@ -556,7 +556,10 @@ impl DebrayAllocator {
             VarAlloc::Temp { safety, .. } => {
                 *safety = VarSafetyStatus::unneeded(branch_designator);
             }
-            _ => unreachable!(),
+            _ => {
+                // the (permanent) variable might have been freed by
+                // this point, in which case we do nothing.
+            }
         }
     }
 
@@ -703,7 +706,7 @@ impl Allocator for DebrayAllocator {
         lvl: Level,
         context: GenContext,
         code: &mut CodeDeque,
-    ) {
+    ) -> RegType {
         let r = RegType::Temp(self.alloc_reg_to_non_var());
 
         match lvl {
@@ -720,6 +723,8 @@ impl Allocator for DebrayAllocator {
                 code.push_back(Target::argument_to_variable(r, k));
             }
         };
+
+        r
     }
 
     fn mark_non_var<'a, Target: CompilationTarget<'a>>(
@@ -934,17 +939,23 @@ impl Allocator for DebrayAllocator {
                             continue;
                         }
 
-                        let h = var.get_value() as usize;
-                        let var_ptr = term.var_locs.peek_next_var_ptr_at_key(h).unwrap();
-                        let var_num = var_ptr.to_var_num().unwrap();
-                        let r = self.get_var_binding(var_num);
-
-                        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);
+                        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(idx + 1);
+                                    self.shallow_temp_mappings.insert(idx + 1, var_num);
+                                    self.var_data.records[var_num]
+                                        .allocation
+                                        .set_register(idx + 1);
+                                }
+                            }
+                            VarPtr::Anon => {}
                         }
                     }
                 }
index 4dee7439dec45dd0e65327ce9d558ceca05fce29..be96e30c5ee3266eb0ab0fd0fa8a138d4b6c18ba 100644 (file)
@@ -72,6 +72,37 @@ pub enum CallPolicy {
     Counted,
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum GenContext {
+    Head,
+    Mid(usize),
+    Last(usize), // Mid & Last: chunk_num
+}
+
+impl GenContext {
+    #[inline]
+    pub fn chunk_num(&self) -> usize {
+        match self {
+            GenContext::Head => 0,
+            &GenContext::Mid(cn) | &GenContext::Last(cn) => cn,
+        }
+    }
+
+    #[inline]
+    pub fn 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(_))
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ChunkType {
     Head,
@@ -98,12 +129,14 @@ impl ChunkType {
 #[derive(Debug)]
 pub enum ChunkedTerms {
     Branch(Vec<VecDeque<ChunkedTerms>>),
-    Chunk(VecDeque<QueryTerm>),
+    Chunk { chunk_num: usize, 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 {
@@ -128,6 +161,8 @@ impl ChunkedTermVec {
     pub fn new() -> Self {
         Self {
             chunk_vec: VecDeque::new(),
+            current_chunk_num: 0,
+            current_chunk_type: ChunkType::Mid,
         }
     }
 
@@ -136,24 +171,70 @@ impl ChunkedTermVec {
             .push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
     }
 
+    pub fn push_branch_arm(&mut self, branch: VecDeque<ChunkedTerms>) {
+        match self.chunk_vec.back_mut().unwrap() {
+            ChunkedTerms::Branch(branches) => {
+                branches.push(branch);
+            }
+            ChunkedTerms::Chunk { .. } => {
+                self.chunk_vec.push_back(ChunkedTerms::Branch(vec![branch]));
+            }
+        }
+    }
+
+    pub fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
+        if self.current_chunk_type.is_last() {
+            self.current_chunk_type = ChunkType::Mid;
+            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) {
-        self.chunk_vec
-            .push_back(ChunkedTerms::Chunk(VecDeque::from(vec![])));
+        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(_)) => {
-                self.chunk_vec
-                    .push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
+                let chunk = ChunkedTerms::Chunk {
+                    chunk_num: self.current_chunk_num,
+                    terms: VecDeque::from(vec![term]),
+                };
+
+                self.chunk_vec.push_back(chunk);
             }
-            Some(ChunkedTerms::Chunk(chunk)) => {
-                chunk.push_back(term);
+            Some(ChunkedTerms::Chunk { terms, .. }) => {
+                terms.push_back(term);
             }
             None => {
-                self.chunk_vec
-                    .push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
+                let chunk = ChunkedTerms::Chunk {
+                    chunk_num: self.current_chunk_num,
+                    terms: VecDeque::from(vec![term]),
+                };
+
+                self.chunk_vec.push_back(chunk);
             }
         }
     }
index 26f48cb3b6f831092926c46aad998c945a73d8fe..8d434b15b13431b6adda46cfa3e55690f1ad2a38 100644 (file)
@@ -479,7 +479,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, VarPtr>,
+    pub var_names: IndexMap<HeapCellValue, Var>,
     pub numbervars_offset: Integer,
     pub numbervars: bool,
     pub quoted: bool,
@@ -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.borrow().to_string());
+                   return Some(var.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.borrow().to_string();
+                        let var_str = var.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.borrow().to_string();
+                                    let var_str = var.to_string();
 
                                     push_space_if_amb!(self, &var_str, {
                                         append_str!(self, &var_str);
@@ -1924,7 +1924,7 @@ mod tests {
 
             printer
                 .var_names
-                .insert(list_loc_as_cell!(1), VarPtr::from("L"));
+                .insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
 
             let output = printer.print();
 
@@ -1993,7 +1993,7 @@ mod tests {
 
             printer
                 .var_names
-                .insert(list_loc_as_cell!(1), VarPtr::from("L"));
+                .insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
 
             let output = printer.print();
 
index 030daf8150577b70518d94e36d756f9d95527ba5..c139f006de8b762ae9f7660db4e38925d68b3a62 100644 (file)
@@ -232,7 +232,7 @@ pub(crate) enum ClauseItem<'a> {
     FirstBranch(usize),
     NextBranch,
     BranchEnd(usize),
-    Chunk(&'a VecDeque<QueryTerm>),
+    Chunk { chunk_num: usize, terms: &'a VecDeque<QueryTerm> },
 }
 
 #[derive(Debug)]
@@ -275,9 +275,10 @@ impl<'a> ClauseIterator<'a> {
 
         while let Some(state) = self.state_stack.pop() {
             match state {
-                ClauseIteratorState::RemainingBranches(terms, focus) if terms.len() == focus => {
-                    depth += 1;
-                }
+                ClauseIteratorState::RemainingBranches(terms, focus)
+                    if terms.len() == focus => {
+                        depth += 1;
+                    }
                 _ => {
                     self.state_stack.push(state);
                     break;
@@ -295,24 +296,25 @@ impl<'a> Iterator for ClauseIterator<'a> {
     fn next(&mut self) -> Option<Self::Item> {
         while let Some(state) = self.state_stack.pop() {
             match state {
-                ClauseIteratorState::RemainingChunks(chunks, focus) if focus < chunks.len() => {
-                    if focus + 1 < chunks.len() {
-                        self.state_stack
-                            .push(ClauseIteratorState::RemainingChunks(chunks, focus + 1));
-                    } else {
-                        self.remaining_chunks_on_stack -= 1;
-                    }
-
-                    match &chunks[focus] {
-                        ChunkedTerms::Branch(branches) => {
+                ClauseIteratorState::RemainingChunks(chunks, focus)
+                    if focus < chunks.len() => {
+                        if focus + 1 < chunks.len() {
                             self.state_stack
-                                .push(ClauseIteratorState::RemainingBranches(branches, 0));
+                                .push(ClauseIteratorState::RemainingChunks(chunks, focus + 1));
+                        } else {
+                            self.remaining_chunks_on_stack -= 1;
                         }
-                        ChunkedTerms::Chunk(chunk) => {
-                            return Some(ClauseItem::Chunk(chunk));
+
+                        match &chunks[focus] {
+                            ChunkedTerms::Branch(branches) => {
+                                self.state_stack
+                                    .push(ClauseIteratorState::RemainingBranches(branches, 0));
+                            }
+                            &ChunkedTerms::Chunk { chunk_num, ref terms } => {
+                                return Some(ClauseItem::Chunk { chunk_num, terms });
+                            }
                         }
                     }
-                }
                 ClauseIteratorState::RemainingChunks(chunks, focus) => {
                     debug_assert_eq!(chunks.len(), focus);
                 }
index cdd7c5151978b9c238a4fde880381970965b7c4d..496007bd7aaa8d3e3537b73e6ca1f43141af0267 100644 (file)
@@ -1156,7 +1156,7 @@ impl MachineState {
     ) -> Result<Number, MachineStub> {
         let stub_gen = || functor_stub(atom!("is"), 2);
 
-        let root_loc = if value.is_ref() {
+        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);
index 4ddf1f33fe0d9dc106abb010dbc65530b758d0c9..983f59615eb4c848a561209905a54a7b14127b40 100644 (file)
@@ -2283,40 +2283,36 @@ impl Machine {
         term_reg: RegType,
         vars: Vec<HeapCellValue>,
     ) -> Result<(), SessionError> {
-        let cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg]));
-
-        // append the variables of vars.
-        let focus      = cell.get_value() as usize;
-        let header_loc = term_nth_arg(&self.machine_st.heap, focus, 0).unwrap();
-        let name       = term_name(&self.machine_st.heap, header_loc).unwrap();
-        let old_arity  = term_arity(&self.machine_st.heap, header_loc);
+        let body_cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg]));
 
         let new_header_loc = self.machine_st.heap.len();
-        let new_arity = old_arity + vars.len();
-
-        self.machine_st.heap.push(atom_as_cell!(name, new_arity));
+        let arity = vars.len();
 
-        for idx in header_loc + 1 .. header_loc + 1 + old_arity {
-            self.machine_st.heap.push(self.machine_st.heap[idx]);
-        }
+        self.machine_st.heap.push(atom_as_cell!(atom!(""), arity));
 
         for var in vars {
             self.machine_st.heap.push(var);
         }
 
-        let value = if new_arity > 0 {
+        let head_loc = if arity > 0 {
             str_loc_as_cell!(new_header_loc)
         } else {
             heap_loc_as_cell!(new_header_loc)
         };
 
-        let mut compile = |cell| {
+        let term_loc = self.machine_st.heap.len();
+
+        self.machine_st.heap.push(atom_as_cell!(atom!(":-"), 2));
+        self.machine_st.heap.push(head_loc);
+        self.machine_st.heap.push(body_cell);
+
+        let mut compile = || {
             use crate::heap_iter::eager_stackful_preorder_iter;
 
             let mut loader: Loader<'_, InlineLoadState<'_>> =
                 Loader::new(self, InlineTermStream {});
 
-            let mut term = loader.copy_term_from_heap(cell);
+            let mut term = loader.copy_term_from_heap(str_loc_as_cell!(term_loc));
 
             let settings = CodeGenSettings {
                 global_clock_tick: None,
@@ -2326,14 +2322,14 @@ impl Machine {
 
             let value = term.heap[term.focus];
 
-            term.var_locs = var_locs_from_iter(
+            term.inverse_var_locs = inverse_var_locs_from_iter(
                 eager_stackful_preorder_iter(&mut term.heap, value),
             );
 
             loader.compile_standalone_clause(term, settings)
         };
 
-        let StandaloneCompileResult { clause_code, .. } = compile(value)?;
+        let StandaloneCompileResult { clause_code, .. } = compile()?;
         self.code.extend(clause_code);
 
         Ok(())
index 801ce078ed4068c650da7b4e653e5143d3c9c7ed..d7f351554af2134a328d3119b2d398e17574620f 100644 (file)
@@ -80,9 +80,34 @@ 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_ptr: VarPtr,
+    var: ClassifiedVar,
     chunk_type: ChunkType,
     classify_info: ClassifyInfo,
     lvl: Level,
@@ -90,7 +115,6 @@ 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>,
@@ -111,7 +135,7 @@ impl BranchInfo {
     }
 }
 
-type BranchMapInt = IndexMap<VarPtr, Vec<BranchInfo>>;
+type BranchMapInt = IndexMap<ClassifiedVar, Vec<BranchInfo>>;
 
 #[derive(Debug, Clone)]
 pub struct BranchMap(BranchMapInt);
@@ -174,8 +198,6 @@ 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,
@@ -183,11 +205,42 @@ 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 {
@@ -211,10 +264,13 @@ impl VarData {
 
             match build_stack.front_mut() {
                 Some(ChunkedTerms::Branch(_)) => {
-                    build_stack.push_front(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
+                    build_stack.push_front(ChunkedTerms::Chunk {
+                        chunk_num: 0,
+                        terms: VecDeque::from(vec![term]),
+                    });
                 }
-                Some(ChunkedTerms::Chunk(chunk)) => {
-                    chunk.push_front(term);
+                Some(ChunkedTerms::Chunk { terms, .. }) => {
+                    terms.push_front(term);
                 }
                 None => {
                     unreachable!()
@@ -256,8 +312,6 @@ 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,
@@ -276,7 +330,7 @@ impl VariableClassifier {
         Ok(self.branch_map.separate_and_classify_variables(
             self.var_num,
             self.global_cut_var_num,
-            self.current_chunk_num,
+            0,
         ))
     }
 
@@ -298,7 +352,7 @@ impl VariableClassifier {
         let mut var_data = self.branch_map.separate_and_classify_variables(
             self.var_num,
             self.global_cut_var_num,
-            self.current_chunk_num,
+            query_terms.current_chunk_num,
         );
 
         var_data.emit_initial_get_level(&mut query_terms);
@@ -327,32 +381,13 @@ impl VariableClassifier {
         }
     }
 
-    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
-        }
-    }
-
-    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
-        }
-    }
-
     fn probe_body_term(
         &mut self,
         arg_c: usize,
         arity: usize,
         term: &mut FocusedHeap,
         term_loc: usize,
+        context: GenContext,
     ) {
         let classify_info = ClassifyInfo { arg_c, arity };
 
@@ -372,23 +407,24 @@ impl VariableClassifier {
             }
 
             let var_loc = subterm.get_value() as usize;
-            let var_ptr = term.var_locs.read_next_var_ptr_at_key(var_loc).unwrap();
-
-            self.probe_body_var(VarInfo {
-                var_ptr: var_ptr.clone(),
-                lvl,
-                classify_info,
-                chunk_type: self.current_chunk_type,
-            });
+            let var = to_classified_var(&term.inverse_var_locs, var_loc);
+
+            self.probe_body_var(
+                context,
+                VarInfo {
+                    var,
+                    lvl,
+                    classify_info,
+                    chunk_type: context.chunk_type(),
+                },
+            );
         }
     }
 
-    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();
+    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();
 
         let needs_new_branch = if let Some(last_bi) = branch_info_v.last() {
             !self.root_set.contains(&last_bi.branch_num)
@@ -403,15 +439,14 @@ 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.chunk_num != self.current_chunk_num
+            last_ci.term_loc.chunk_num() != chunk_num
         } else {
             true
         };
 
         if needs_new_chunk {
             branch_info.chunks.push(ChunkInfo {
-                chunk_num: self.current_chunk_num,
-                term_loc,
+                term_loc: context,
                 vars: vec![],
             });
         }
@@ -420,17 +455,17 @@ impl VariableClassifier {
         chunk_info.vars.push(var_info);
     }
 
-    fn probe_in_situ_var(&mut self, var_num: usize) {
+    fn probe_in_situ_var(&mut self, context: GenContext, var_num: usize) {
         let classify_info = ClassifyInfo { arg_c: 1, arity: 1 };
 
         let var_info = VarInfo {
-            var_ptr: VarPtr::from(Var::InSitu(var_num)),
+            var: ClassifiedVar::InSitu { var_num },
             classify_info,
-            chunk_type: self.current_chunk_type,
+            chunk_type: context.chunk_type(),
             lvl: Level::Shallow,
         };
 
-        self.probe_body_var(var_info);
+        self.probe_body_var(context, var_info);
     }
 
     fn classify_head_variables(
@@ -473,13 +508,13 @@ impl VariableClassifier {
                         continue;
                     }
 
-                    let h = subterm.get_value() as usize;
-                    let var_ptr = term.var_locs.read_next_var_ptr_at_key(h).unwrap().clone();
+                    let term_loc = subterm.get_value() as usize;
+                    let var = to_classified_var(&term.inverse_var_locs, term_loc);
 
                     // 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 branch_info_v = self.branch_map.entry(var).or_default();
                     let needs_new_branch = branch_info_v.is_empty();
 
                     if needs_new_branch {
@@ -491,7 +526,6 @@ impl VariableClassifier {
 
                     if needs_new_chunk {
                         branch_info.chunks.push(ChunkInfo {
-                            chunk_num: self.current_chunk_num,
                             term_loc: GenContext::Head,
                             vars: vec![],
                         });
@@ -499,9 +533,9 @@ impl VariableClassifier {
 
                     let chunk_info = branch_info.chunks.last_mut().unwrap();
                     let var_info = VarInfo {
-                        var_ptr,
+                        var,
                         classify_info,
-                        chunk_type: self.current_chunk_type,
+                        chunk_type: ChunkType::Head,
                         lvl,
                     };
 
@@ -515,7 +549,7 @@ impl VariableClassifier {
         Ok(())
     }
 
-    fn new_cut_state(&mut self) -> TraversalState {
+    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 {
@@ -529,7 +563,7 @@ impl VariableClassifier {
             (var_num, true)
         };
 
-        self.probe_in_situ_var(var_num);
+        self.probe_in_situ_var(context, var_num);
 
         TraversalState::Cut { var_num, is_global }
     }
@@ -546,8 +580,6 @@ impl VariableClassifier {
         }];
         let mut build_stack = ChunkedTermVec::new();
 
-        self.current_chunk_type = ChunkType::Mid;
-
         'outer: while let Some(traversal_st) = state_stack.pop() {
             match traversal_st {
                 TraversalState::AddBranchNum(branch_num) => {
@@ -568,21 +600,22 @@ impl VariableClassifier {
                 TraversalState::BuildDisjunct(preceding_len) => {
                     flatten_into_disjunct(&mut build_stack, preceding_len);
 
-                    self.current_chunk_type = ChunkType::Mid;
-                    self.current_chunk_num += 1;
+                    build_stack.current_chunk_type = ChunkType::Mid;
+                    build_stack.current_chunk_num += 1;
                 }
                 TraversalState::BuildFinalDisjunct(preceding_len) => {
                     flatten_into_disjunct(&mut build_stack, preceding_len);
 
-                    self.current_chunk_type = ChunkType::Mid;
-                    self.current_chunk_num += 1;
+                    build_stack.current_chunk_type = ChunkType::Mid;
+                    build_stack.current_chunk_num += 1;
                 }
                 TraversalState::GetCutPoint { var_num, prev_b } => {
-                    if self.try_set_chunk_at_inlined_boundary() {
+                    if build_stack.try_set_chunk_at_inlined_boundary() {
                         build_stack.add_chunk();
                     }
 
-                    self.probe_in_situ_var(var_num);
+                    let context = build_stack.current_gen_context();
+                    self.probe_in_situ_var(context, var_num);
                     build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
                 }
                 TraversalState::OverrideGlobalCutVar(var_num) => {
@@ -592,11 +625,12 @@ impl VariableClassifier {
                     self.global_cut_var_num_override = old_override;
                 }
                 TraversalState::Cut { var_num, is_global } => {
-                    if self.try_set_chunk_at_inlined_boundary() {
+                    if build_stack.try_set_chunk_at_inlined_boundary() {
                         build_stack.add_chunk();
                     }
 
-                    self.probe_in_situ_var(var_num);
+                    let context = build_stack.current_gen_context();
+                    self.probe_in_situ_var(context, var_num);
 
                     build_stack.push_chunk_term(if is_global {
                         QueryTerm::GlobalCut(var_num)
@@ -608,11 +642,12 @@ impl VariableClassifier {
                     });
                 }
                 TraversalState::CutPrev(var_num) => {
-                    if self.try_set_chunk_at_inlined_boundary() {
+                    if build_stack.try_set_chunk_at_inlined_boundary() {
                         build_stack.add_chunk();
                     }
 
-                    self.probe_in_situ_var(var_num);
+                    let context = build_stack.current_gen_context();
+                    self.probe_in_situ_var(context, var_num);
 
                     build_stack.push_chunk_term(QueryTerm::LocalCut {
                         var_num,
@@ -630,24 +665,26 @@ impl VariableClassifier {
                     mut term_loc,
                 } => {
                     // return true iff new chunk should be added.
-                    let update_chunk_data = |classifier: &mut Self, key: PredicateKey| {
+                    let update_chunk_data = |build_stack: &mut ChunkedTermVec, key: PredicateKey| {
                         if ClauseType::is_inlined(key.0, key.1) {
-                            classifier.try_set_chunk_at_inlined_boundary()
+                            build_stack.try_set_chunk_at_inlined_boundary()
                         } else {
-                            classifier.try_set_chunk_at_call_boundary()
+                            build_stack.try_set_chunk_at_call_boundary()
                         }
                     };
 
                     macro_rules! add_chunk {
-                        ($classifier:ident, $key:expr, $tag:expr, $term_loc:expr) => {{
-                            if update_chunk_data($classifier, $key) {
+                        ($key:expr, $tag:expr, $term_loc:expr) => {{
+                            if update_chunk_data(&mut build_stack, $key) {
                                 build_stack.add_chunk();
                             }
 
+                            let context = build_stack.current_gen_context();
+
                             for (arg_c, term_loc) in
                                 ($term_loc + 1 ..= $term_loc + $key.1).enumerate()
                             {
-                                $classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
+                                self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context);
                             }
 
                             build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
@@ -655,21 +692,23 @@ impl VariableClassifier {
                                 $key,
                                 terms.as_ref_mut($term_loc),
                                 HeapCellValue::build_with($tag, $term_loc as u64),
-                                $classifier.call_policy,
+                                self.call_policy,
                             )));
                         }};
                     }
 
                     macro_rules! add_qualified_chunk {
-                        ($classifier:ident, $module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{
-                            if update_chunk_data($classifier, $key) {
+                        ($module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{
+                            if update_chunk_data(&mut build_stack, $key) {
                                 build_stack.add_chunk();
                             }
 
+                            let context = build_stack.current_gen_context();
+
                             for (arg_c, term_loc) in
                                 ($term_loc + 1..$term_loc + $key.1 + 1).enumerate()
                             {
-                                $classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
+                                self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context);
                             }
 
                             build_stack.push_chunk_term(QueryTerm::Clause(
@@ -679,7 +718,7 @@ impl VariableClassifier {
                                     $module_name,
                                     terms.as_ref_mut($term_loc),
                                     HeapCellValue::build_with($tag, $term_loc as u64),
-                                    $classifier.call_policy,
+                                    self.call_policy,
                                 ),
                             ));
                         }};
@@ -698,7 +737,7 @@ impl VariableClassifier {
                                             continue;
                                         }
 
-                                        add_chunk!(self, (name, 2), HeapCellValueTag::Str, subterm_loc);
+                                        add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc);
                                     }
                                     (atom!(","), 2) => {
                                         let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
@@ -764,8 +803,8 @@ impl VariableClassifier {
                                                 TraversalState::BuildFinalDisjunct(build_stack_len);
                                         }
 
-                                        self.current_chunk_type = ChunkType::Mid;
-                                        self.current_chunk_num += 1;
+                                        build_stack.current_chunk_type = ChunkType::Mid;
+                                        build_stack.current_chunk_num += 1;
                                     }
                                     (atom!("->"), 2) => {
                                         let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
@@ -841,8 +880,8 @@ impl VariableClassifier {
                                         });
                                         state_stack.push(TraversalState::AddBranchNum(branch_num));
 
-                                        self.current_chunk_type = ChunkType::Mid;
-                                        self.current_chunk_num += 1;
+                                        build_stack.current_chunk_type = ChunkType::Mid;
+                                        build_stack.current_chunk_num += 1;
 
                                         self.var_num += 1;
                                     }
@@ -862,7 +901,6 @@ impl VariableClassifier {
                                                                 .get_name_and_arity();
 
                                                             add_qualified_chunk!(
-                                                                self,
                                                                 module_name,
                                                                 key,
                                                                 HeapCellValueTag::Str,
@@ -874,7 +912,6 @@ impl VariableClassifier {
                                                             let key = (predicate_name, predicate_arity);
 
                                                             add_qualified_chunk!(
-                                                                self,
                                                                 module_name,
                                                                 key,
                                                                 HeapCellValueTag::Str,
@@ -890,12 +927,14 @@ impl VariableClassifier {
                                             _ => {}
                                         );
 
-                                        if update_chunk_data(self, (atom!("call"), 2)) {
+                                        if update_chunk_data(&mut build_stack, (atom!("call"), 2)) {
                                             build_stack.add_chunk();
                                         }
 
-                                        self.probe_body_term(1, 0, terms, module_name_loc);
-                                        self.probe_body_term(2, 0, terms, predicate_term_loc);
+                                        let context = build_stack.current_gen_context();
+
+                                        self.probe_body_term(1, 0, terms, module_name_loc, context);
+                                        self.probe_body_term(2, 0, terms, predicate_term_loc, context);
 
                                         let h = terms.heap.len();
 
@@ -920,7 +959,7 @@ impl VariableClassifier {
                                         self.call_policy = CallPolicy::Counted;
                                     }
                                     (name, arity) => {
-                                        add_chunk!(self, (name, arity), HeapCellValueTag::Str, subterm_loc);
+                                        add_chunk!((name, arity), HeapCellValueTag::Str, subterm_loc);
                                     }
                                 }
                             }
@@ -928,14 +967,16 @@ impl VariableClassifier {
                                 debug_assert_eq!(arity, 0);
 
                                 if name == atom!("!") {
-                                    state_stack.push(self.new_cut_state());
+                                    let context = build_stack.current_gen_context();
+                                    state_stack.push(self.new_cut_state(context));
                                 } else {
-                                    add_chunk!(self, (name, 0), HeapCellValueTag::Var, term_loc);
+                                    add_chunk!((name, 0), HeapCellValueTag::Var, term_loc);
                                 }
                             }
                             (HeapCellValueTag::Char, c) => {
                                 if c == '!' {
-                                    state_stack.push(self.new_cut_state());
+                                    let context = build_stack.current_gen_context();
+                                    state_stack.push(self.new_cut_state(context));
                                 } else {
                                     return Err(CompilationError::InadmissibleQueryTerm);
                                 }
@@ -947,7 +988,7 @@ impl VariableClassifier {
                                     continue;
                                 }
 
-                                add_chunk!(self, (atom!("call"), 1), HeapCellValueTag::Var, h);
+                                add_chunk!((atom!("call"), 1), HeapCellValueTag::Var, h);
                             }
                             _ => {
                                 return Err(CompilationError::InadmissibleQueryTerm);
@@ -975,13 +1016,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) = if let Var::InSitu(var_num) = *var.borrow() {
-                (var_num, false)
-            } else {
-                (var_data.records.len(), true)
+            let (mut var_num, var_num_incr) = match var {
+                &ClassifiedVar::InSitu { var_num} => (var_num, false),
+                _ => (var_data.records.len(), true)
             };
 
             for branch in branches.iter_mut() {
@@ -999,10 +1040,13 @@ impl BranchMap {
 
                     for var_info in chunk.vars.iter_mut() {
                         if var_info.lvl == Level::Shallow {
-                            let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num);
+                            let context = var_info
+                                .chunk_type
+                                .to_gen_context(chunk.term_loc.chunk_num());
+
                             temp_var_data
                                 .use_set
-                                .insert((term_loc, var_info.classify_info.arg_c));
+                                .insert((context, var_info.classify_info.arg_c));
                         }
                     }
 
@@ -1018,9 +1062,13 @@ impl BranchMap {
                 for chunk in branch.chunks.iter_mut() {
                     var_data.records[var_num].num_occurrences += chunk.vars.len();
 
-                    for var_info in chunk.vars.iter_mut() {
-                        let is_anon = var_info.var_ptr.is_anon();
-                        var_info.var_ptr.set(Var::Generated { is_anon, var_num });
+                    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,
+                        );
                     }
                 }
             }
index 4d3d45ec04eab187692bb76780adc896d40f23bf..456f075fe9773dc406cdb05444778d60bd885a2e 100644 (file)
@@ -33,10 +33,12 @@ pub(crate) trait UnmarkPolicy {
     }
 }
 
+#[cfg(test)]
 pub(crate) struct IteratorUMP {
     mark_phase: bool,
 }
 
+#[cfg(test)]
 fn invert_marker<UMP: UnmarkPolicy>(iter: &mut StacklessPreOrderHeapIter<UMP>) {
     if iter.heap[iter.start].get_forwarding_bit() {
         while !iter.backward() {}
@@ -50,6 +52,7 @@ fn invert_marker<UMP: UnmarkPolicy>(iter: &mut StacklessPreOrderHeapIter<UMP>) {
     while iter.forward().is_some() {}
 }
 
+#[cfg(test)]
 impl UnmarkPolicy for IteratorUMP {
     #[inline(always)]
     fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> {
@@ -150,8 +153,8 @@ impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> {
     }
 }
 
+#[cfg(test)]
 impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> {
-    #[cfg(test)]
     pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self {
         heap[start].set_forwarding_bit(true);
         let next = heap[start].get_value();
index 5e8d887fbb40e588a362d32d094ea7075bb644e4..bd4ea36ebe1017b38770ee2c79c094c422b9745b 100644 (file)
@@ -467,11 +467,20 @@ impl Iterator for QueryState<'_> {
             // this should halt the search for solutions as it
             // does in the Scryer top-level. the exception term is
             // contained in self.machine_st.ball.
-            let h = machine.machine_st.heap.len();
-            machine
+            let h = machine.machine_st.heap.cell_len();
+
+            if let Err(resource_err_loc) = machine
                 .machine_st
                 .heap
-                .extend(machine.machine_st.ball.stub.clone());
+                .append(&machine.machine_st.ball.stub)
+            {
+                return Some(Err(Term::from_heapcell(
+                    machine,
+                    machine.machine_st.heap[resource_err_loc],
+                    &mut IndexMap::new(),
+                )));
+            }
+
             let exception_term =
                 Term::from_heapcell(machine, machine.machine_st.heap[h], &mut var_names.clone());
 
@@ -487,7 +496,7 @@ impl Iterator for QueryState<'_> {
         }
 
         if machine.machine_st.p == LIB_QUERY_SUCCESS {
-            if term_write_result.var_dict.is_empty() {
+            if term_write_result.inverse_var_locs.is_empty() {
                 self.machine.machine_st.backtrack();
                 return Some(Ok(LeafAnswer::True));
             }
@@ -496,47 +505,39 @@ impl Iterator for QueryState<'_> {
         }
 
         let mut bindings: BTreeMap<String, Term> = BTreeMap::new();
+        let inverse_var_locs = &term_write_result.inverse_var_locs;
 
-        let var_dict = &term_write_result.var_dict;
-
-        for (var_key, term_to_be_printed) in var_dict.iter() {
-            let mut var_name = var_key.to_string();
+        for (var_loc, var_name) in inverse_var_locs.iter() {
             if var_name.starts_with('_') {
-                let should_print = var_names.values().any(|x| match x.borrow().clone() {
-                    Var::Named(v) => v == var_name,
-                    _ => false,
-                });
+                let should_print = var_names.values().any(|v| v == var_name);
                 if !should_print {
                     continue;
                 }
             }
 
-            let mut term =
-                Term::from_heapcell(machine, *term_to_be_printed, &mut var_names.clone());
+            let var_loc = *var_loc;
+            let term =
+                Term::from_heapcell(machine, heap_loc_as_cell!(var_loc), &mut var_names.clone());
 
             if let Term::Var(ref term_str) = term {
-                if *term_str == var_name {
+                if *term_str == **var_name {
                     continue;
                 }
 
-                // Var dict is in the order things appear in the query. If var_name appears
-                // after term in the query, switch their places.
-                let var_name_idx = var_dict
-                    .get_index_of(&VarKey::VarPtr(Var::Named(var_name.clone()).into()))
-                    .unwrap();
-                let term_idx =
-                    var_dict.get_index_of(&VarKey::VarPtr(Var::Named(term_str.clone()).into()));
-                if let Some(idx) = term_idx {
-                    if idx < var_name_idx {
-                        let new_term = Term::Var(var_name);
-                        let new_var_name = term_str.into();
-                        term = new_term;
-                        var_name = new_var_name;
-                    }
+                // 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;
                 }
             }
 
-            bindings.insert(var_name, term);
+            bindings.insert(var_name.to_string(), term);
         }
 
         // NOTE: there are outstanding choicepoints, backtrack
@@ -605,27 +606,10 @@ 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, &self.machine_st.atom_tbl)
-                .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_write_result.heap_loc];
-
+        self.machine_st.registers[1] = self.machine_st.heap[term.focus];
         self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
+
         let call_index_p = self
             .indices
             .code_dir
@@ -634,12 +618,22 @@ 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_write_result,
+            term,
             stub_b,
             var_names,
             called: false,
index 5b96fe37fcb7e4c5d79ea2890f2311cb1730217c..40800f9760843ee31abd6be0684f9ddd517a3425 100644 (file)
@@ -499,7 +499,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         let machine_st = LS::machine_st(&mut self.payload);
 
         term.copy_term_from_machine_heap(machine_st, cell);
-        term.var_locs = var_locs_from_iter(
+        term.inverse_var_locs = inverse_var_locs_from_iter(
             fact_iterator::<false>(
                 &mut term.heap,
                 &mut stack,
@@ -1107,7 +1107,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         );
 
         let value = term.heap[term.focus];
-        term.var_locs = var_locs_from_iter(eager_stackful_preorder_iter(&mut term.heap, value));
+        term.inverse_var_locs = inverse_var_locs_from_iter(
+            eager_stackful_preorder_iter(&mut term.heap, value),
+        );
         Ok(term)
     }
 
index 511695d9cd049dbf5af3b8aad02beeb7d9b97123..ea8db552c352c5e212655ee25a406e1ef4458ec6 100644 (file)
@@ -472,8 +472,8 @@ impl MachineState {
     fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
         match err {
             ArithmeticError::UninstantiatedVar => self.instantiation_error(),
-            ArithmeticError::NonEvaluableFunctor(literal, arity) => {
-                let culprit = functor!(atom!("/"), [literal(literal), fixnum(arity)]);
+            ArithmeticError::NonEvaluableFunctor(cell, arity) => {
+                let culprit = functor!(atom!("/"), [cell(cell), fixnum(arity)]);
 
                 self.type_error(ValidType::Evaluable, culprit)
             }
index bd2b217fe73900c255da7e3674f152e6f703eb57..1c18f16a71b6d8a1ca50518677de2b678d1a3aa7 100644 (file)
@@ -22,6 +22,7 @@ use indexmap::IndexMap;
 use std::convert::TryFrom;
 use std::fmt;
 use std::ops::{Index, IndexMut};
+use std::rc::Rc;
 use std::sync::Arc;
 
 pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
@@ -202,13 +203,13 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
 
 fn push_var_eq_functors(
     heap: &mut Heap,
-    iter: impl Iterator<Item = (usize, VarPtr)>, // (&'a VarPtr, &'a HeapCellValue)>,
+    iter: impl Iterator<Item = (usize, Var)>,
     atom_tbl: &AtomTable,
 ) -> Vec<HeapCellValue> {
     let mut list_of_var_eqs = vec![];
 
-    for (var_loc, var_ptr) in iter { // (var, binding) in iter {
-        let var_atom = AtomTable::build_with(atom_tbl, &*var_ptr.borrow().to_string());
+    for (var_loc, var) in iter { // (var, binding) in iter {
+        let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
         let h = heap.len();
         let binding = heap[var_loc];
 
@@ -541,20 +542,15 @@ impl MachineState {
 
     pub fn write_read_term_options(
         &mut self,
-        mut var_list: Vec<(VarPtr, HeapCellValue, usize)>,
+        mut var_list: Vec<(Var, HeapCellValue, usize)>,
         singleton_var_list: Vec<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().filter_map(|(var_ptr, var, _)| {
-                if var_ptr.is_anon() {
-                    None
-                } else {
-                    let var_loc = var.get_value() as usize;
-                    Some((var_loc, var_ptr.clone()))
-                }
+            var_list.iter().map(|(var_name, var, _)| {
+                (var.get_value() as usize, var_name.clone())
             }),
             &self.atom_tbl,
         );
@@ -630,20 +626,14 @@ impl MachineState {
 
         let singleton_var_list = push_var_eq_functors(
             &mut self.heap,
-            term.var_locs
+            term.inverse_var_locs
                 .iter()
-                .filter_map(|(var_loc, var_ptrs)| {
-                    let var_ptr = var_ptrs.front().unwrap();
-
-                    if var_ptr.is_anon() {
-                        return None;
-                    }
-
+                .filter_map(|(var_loc, var_name)| {
                     // add h to offset the term variable into its heap location.
-                    let r = Ref::heap_cell(var_loc);
+                    let r = Ref::heap_cell(*var_loc);
 
                     if singleton_var_set.get(&r).cloned().unwrap_or(false) {
-                        Some((var_loc, var_ptr.clone()))
+                        Some((*var_loc, var_name.clone()))
                     } else {
                         None
                     }
@@ -659,13 +649,12 @@ impl MachineState {
 
         let mut var_list = Vec::with_capacity(singleton_var_set.len());
 
-        for (var_loc, var_ptrs) in term.var_locs.iter() {
-            let var_ptr = var_ptrs.front().unwrap().clone();
+        for (var_loc, var_name) in term.inverse_var_locs {
             let r = Ref::heap_cell(var_loc);
             let cell = self.heap[var_loc];
 
             if let Some(idx) = singleton_var_set.get_index_of(&r) {
-                var_list.push((var_ptr, cell, idx));
+                var_list.push((var_name, cell, idx));
             }
         }
 
@@ -787,7 +776,7 @@ impl MachineState {
 
         let printer = match self.try_from_list(self.registers[6], stub_gen) {
             Ok(addrs) => {
-                let mut var_names: IndexMap<HeapCellValue, VarPtr> = IndexMap::new();
+                let mut var_names: IndexMap<HeapCellValue, Var> = IndexMap::new();
 
                 for addr in addrs {
                     read_heap_cell!(addr,
@@ -805,18 +794,18 @@ impl MachineState {
 
                                 read_heap_cell!(atom,
                                     (HeapCellValueTag::Char, c) => {
-                                        var_names.insert(var, VarPtr::from(c.to_string()));
+                                        var_names.insert(var, Rc::new(c.to_string()));
                                     }
                                     (HeapCellValueTag::Atom, (name, _arity)) => {
                                         debug_assert_eq!(_arity, 0);
-                                        var_names.insert(var, VarPtr::from(&*name.as_str()));
+                                        var_names.insert(var, Rc::new(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, VarPtr::from(&*name.as_str()));
+                                        var_names.insert(var, Rc::new(name.as_str().to_owned()));
                                     }
                                     _ => {
                                         unreachable!();
index 5b0096fceca1d8815eec1043838cdab62449bfd7..badd62552ab309acf44b8895051918ec5ab7b4f0 100644 (file)
@@ -59,10 +59,10 @@ impl MockWAM {
         print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
 
         let var_names = term_write_result
-            .var_locs
+            .inverse_var_locs
             .iter()
-            .map(|(var_loc, var_ptrs)| {
-                (self.machine_st.heap[var_loc], var_ptrs.front().unwrap().clone())
+            .map(|(var_loc, var_name)| {
+                (self.machine_st.heap[*var_loc], var_name.clone())
             })
             .collect();
 
index 39259656c7b50ccad747d030e8f662c849d47d28..477e93826a6f1ce8d6a2726bcf8f4bd2e89ce83f 100644 (file)
@@ -9,12 +9,10 @@ use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
 use crate::types::*;
 
-use std::cell::{Ref, RefCell, RefMut};
-use std::collections::VecDeque;
 use std::fmt;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
 use std::io::{Error as IOError, ErrorKind};
-use std::ops::{Deref, Neg, RangeBounds};
+use std::ops::Neg;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::vec::Vec;
@@ -311,26 +309,11 @@ macro_rules! temp_v {
     };
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum GenContext {
-    Head,
-    Mid(usize),
-    Last(usize), // Mid & Last: chunk_num
-}
-
-impl GenContext {
-    #[inline]
-    pub fn chunk_num(self) -> usize {
-        match self {
-            GenContext::Head => 0,
-            GenContext::Mid(cn) | GenContext::Last(cn) => cn,
-        }
-    }
-
-    #[inline]
-    pub fn is_last(self) -> bool {
-        matches!(self, GenContext::Last(_))
-    }
+#[macro_export]
+macro_rules! perm_v {
+    ($x:expr) => {
+        $crate::parser::ast::RegType::Perm($x)
+    };
 }
 
 #[bitfield]
@@ -426,7 +409,7 @@ pub fn default_op_dir() -> OpDir {
 
 #[derive(Debug, Clone)]
 pub enum ArithmeticError {
-    NonEvaluableFunctor(Literal, usize),
+    NonEvaluableFunctor(HeapCellValue, usize),
     UninstantiatedVar,
 }
 
@@ -680,111 +663,7 @@ impl Literal {
     }
 }
 
-#[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)
-    }
-}
-
-impl Deref for VarPtr {
-    type Target = RefCell<Var>;
-
-    #[inline(always)]
-    fn deref(&self) -> &Self::Target {
-        self.0.deref()
-    }
-}
-
-impl VarPtr {
-    #[inline]
-    pub(crate) fn is_anon(&self) -> bool {
-        match *self.borrow() {
-            Var::Anon | Var::Generated { is_anon: true, .. } => true,
-            _ => false,
-        }
-    }
-
-    #[inline(always)]
-    pub(crate) fn borrow(&self) -> Ref<'_, Var> {
-        self.0.borrow()
-    }
-
-    #[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 {
-    Anon,
-    Generated { is_anon: bool, var_num: usize },
-    InSitu(usize),
-    Named(String),
-}
-
-impl From<String> for Var {
-    #[inline(always)]
-    fn from(value: String) -> Var {
-        Var::Named(value)
-    }
-}
-
-impl From<&str> for Var {
-    #[inline(always)]
-    fn from(value: &str) -> Var {
-        Var::Named(value.to_owned())
-    }
-}
-
-impl Var {
-    #[allow(clippy::inherent_to_string)]
-    #[inline(always)]
-    pub fn to_string(&self) -> String {
-        match self {
-            Var::Anon => "_".to_owned(),
-            Var::InSitu(var_num) | Var::Generated { var_num, .. } => format!("_{}", var_num),
-            Var::Named(value) => value.to_owned(),
-        }
-    }
-}
+pub type Var = Rc<String>;
 
 pub(crate) fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) {
     let subterm = heap[subterm_loc];
@@ -1045,7 +924,7 @@ pub fn term_arity(heap: &[HeapCellValue], mut term_loc: usize) -> usize {
     }
 }
 
-pub fn var_locs_from_iter<I: Iterator<Item = HeapCellValue>>(iter: I) -> VarLocs {
+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());
 
@@ -1056,21 +935,20 @@ pub fn var_locs_from_iter<I: Iterator<Item = HeapCellValue>>(iter: I) -> VarLocs
         }
     }
 
-    VarLocs(
-        occurrence_set
-        .into_iter()
-        .map(|(var, count)| {
-            let key = var.get_value() as usize;
-            let queue = if count > 1 {
-                (0 .. count).map(|_| VarPtr::from(format!("_{}", key))).collect()
-            } else {
-                (0 .. count).map(|_| VarPtr::from(Var::Anon)).collect()
-            };
+    let mut inverse_var_locs = InverseVarLocs::default();
 
-            (key, queue)
-        })
-        .collect()
-    )
+    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
 }
 
 /*
@@ -1132,82 +1010,14 @@ pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Op
     }
 }
 
-pub type VarNamesToLocs = IndexMap<String, HeapCellValue, FxBuildHasher>;
-
-#[derive(Debug, Default)]
-pub struct VarLocs(IndexMap<usize, VecDeque<VarPtr>, FxBuildHasher>);
-
-impl VarLocs {
-    pub fn get(&self, key: usize) -> Option<&VarPtr> {
-        self.0.get(&key)
-            .and_then(|queue| {
-                queue.front()
-            })
-    }
-
-    // if a queue of VarPtr's is stored at location key, pop the front
-    // if it exists and pass it along to wrapper, returning a value of
-    // type R. A return value of None indicates that the key doesn't
-    // exist (the map containing a key necessarily means its queue
-    // value is non-empty).
-    fn rotate_latest_mut<R>(
-        &mut self,
-        key: usize,
-        wrapper: impl FnOnce(&VarPtr) -> R,
-    ) -> Option<R> {
-        self.0.get_mut(&key)
-            .and_then(move |queue| {
-                if let Some(var_ptr) = queue.pop_front() {
-                    let result = wrapper(&var_ptr);
-                    queue.push_back(var_ptr);
-                    Some(result)
-                } else {
-                    None
-                }
-            })
-    }
-
-    pub fn peek_next_var_ptr_at_key(&self, key: usize) -> Option<&VarPtr> {
-        self.0.get(&key).and_then(|queue| queue.front())
-    }
-
-    pub fn read_next_var_ptr_at_key(&mut self, key: usize) -> Option<VarPtr> {
-        self.rotate_latest_mut(key, VarPtr::clone)
-    }
-
-    pub fn push_at_key(&mut self, key: usize, var_ptr: VarPtr) {
-        let entry = self.0.entry(key).or_default();
-        entry.push_back(var_ptr);
-    }
-
-    #[inline]
-    pub fn iter(&self) -> impl Iterator<Item = (usize, &VecDeque<VarPtr>)> {
-        self.0.iter().map(|(&k, v)| (k, v))
-    }
-
-    #[inline]
-    pub fn is_empty(&self) -> bool {
-        self.0.is_empty()
-    }
-
-    #[inline]
-    pub fn drain<R>(&mut self, range: R) -> indexmap::map::Drain<usize, VecDeque<VarPtr>>
-        where R: RangeBounds<usize>
-    {
-        self.0.drain(range)
-    }
-
-    #[inline]
-    pub fn insert(&mut self, key: usize, var_ptrs: VecDeque<VarPtr>) {
-        self.0.insert(key, var_ptrs);
-    }
-}
+pub type VarLocs = IndexMap<Var, HeapCellValue, FxBuildHasher>;
+pub type InverseVarLocs = IndexMap<usize, Var, FxBuildHasher>;
 
 #[derive(Debug)]
 pub struct FocusedHeap {
     pub heap: Vec<HeapCellValue>,
     pub focus: usize,
-    pub var_locs: VarLocs,
+    pub inverse_var_locs: InverseVarLocs,
 }
 
 impl FocusedHeap {
@@ -1215,7 +1025,7 @@ impl FocusedHeap {
         Self {
             heap: vec![],
             focus: 0,
-            var_locs: VarLocs::default(),
+            inverse_var_locs: InverseVarLocs::default(),
         }
     }
 
@@ -1246,7 +1056,6 @@ impl FocusedHeap {
         FocusedHeapRefMut {
             heap: &mut self.heap,
             focus,
-            // var_locs: &self.var_locs,
         }
     }
 
index bffc71670e4863993e6a3bd0a6140a5b2154cbcb..5271b4a047209e8a82cd732efb1005a5d3daa330 100644 (file)
@@ -10,11 +10,9 @@ use crate::parser::char_reader::*;
 use crate::parser::lexer::*;
 use crate::types::*;
 
-use fxhash::FxBuildHasher;
-use indexmap::IndexMap;
-
 use std::mem;
 use std::ops::Neg;
+use std::rc::Rc;
 
 #[derive(Debug, Clone, Copy, PartialEq)]
 enum TokenType {
@@ -184,7 +182,7 @@ pub struct Parser<'a, R> {
     stack: Vec<TokenDesc>,
     terms: Vec<HeapCellValue>,
     var_locs: VarLocs,
-    var_names_to_locs: VarNamesToLocs,
+    inverse_var_locs: InverseVarLocs,
 }
 
 fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> {
@@ -326,7 +324,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             stack: vec![],
             terms: vec![],
             var_locs: VarLocs::default(),
-            var_names_to_locs: IndexMap::with_hasher(FxBuildHasher::default()),
+            inverse_var_locs: InverseVarLocs::default(),
         }
     }
 
@@ -337,7 +335,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             stack: vec![],
             terms: vec![],
             var_locs: VarLocs::default(),
-            var_names_to_locs: IndexMap::with_hasher(FxBuildHasher::default()),
+            inverse_var_locs: InverseVarLocs::default(),
         }
     }
 
@@ -501,32 +499,28 @@ impl<'a, R: CharRead> Parser<'a, R> {
                 self.terms.push(HeapCellValue::from(c));
                 TokenType::Term { heap_loc }
             }
-            Token::Var(var_string) => match self.var_names_to_locs.get(&var_string).cloned() {
-                Some(heap_loc) => {
-                    let heap_idx = heap_loc.get_value() as usize;
-
-                    self.var_locs.push_at_key(heap_idx, VarPtr::from(var_string));
-                    self.terms.push(heap_loc);
-
-                    TokenType::Term { heap_loc }
-                }
-                None => {
-                    self.terms.push(heap_loc);
+            Token::Var(var_string) => {
+                let var = Rc::new(var_string);
 
-                    if var_string.trim() != "_" {
-                        self.var_names_to_locs.insert(var_string.clone(), heap_loc);
+                match self.var_locs.get(&var).cloned() {
+                    Some(heap_loc) => {
+                        self.terms.push(heap_loc);
+                        TokenType::Term { heap_loc }
                     }
+                    None => {
+                        self.terms.push(heap_loc);
 
-                    self.var_locs.push_at_key(
-                        heap_loc.get_value() as usize,
-                        if var_string.trim() == "_" {
-                            VarPtr::from(Var::Anon)
-                        } else {
-                            VarPtr::from(var_string)
-                        },
-                    );
+                        // if var_string == "_", it not being present
+                        // as a key of self.var_locs means it is
+                        // anonymous.
 
-                    TokenType::Term { heap_loc }
+                        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::Comma => TokenType::Comma,
@@ -755,7 +749,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
 
     pub fn reset(&mut self) {
         self.stack.clear();
-        self.var_names_to_locs.clear();
+        self.var_locs.clear();
     }
 
     fn expand_comma_compacted_terms(&mut self, index: usize) -> usize {
@@ -1351,7 +1345,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
             }) => Ok(FocusedHeap {
                 heap: mem::replace(&mut self.terms, vec![]),
                 focus: heap_loc.get_value() as usize,
-                var_locs: mem::replace(&mut self.var_locs, VarLocs::default()),
+                inverse_var_locs: mem::replace(&mut self.inverse_var_locs, InverseVarLocs::default()),
             }),
             _ => Err(ParserError::IncompleteReduction(
                 self.lexer.loc_to_err_src(),
index 9759caf37b96b85663170241fdd2efe587e25bbd..e2fcfa0c4b41e978749198fb76ce264fd98a0809 100644 (file)
@@ -52,15 +52,15 @@ impl FocusedHeap {
         let heap_len = machine_st.heap.len();
         machine_st.heap.extend(copy_and_align_iter(self.heap.drain(..), 0, heap_len as i64));
 
-        let mut var_locs = VarLocs::default();
+        let mut inverse_var_locs = InverseVarLocs::default();
 
-        for (var_loc, var_ptrs) in self.var_locs.drain(..) {
-            var_locs.insert(var_loc + heap_len, var_ptrs);
+        for (var_loc, var_name) in self.inverse_var_locs.drain(..) {
+            inverse_var_locs.insert(var_loc + heap_len, var_name);
         }
 
         TermWriteResult {
             heap_loc: self.focus + heap_len,
-            var_locs,
+            inverse_var_locs,
         }
     }
 }
@@ -309,5 +309,5 @@ impl CharRead for ReadlineStream {
 #[derive(Debug)]
 pub struct TermWriteResult {
     pub heap_loc: usize,
-    pub var_locs: VarLocs,
+    pub inverse_var_locs: InverseVarLocs,
 }
index 18fda2ddc58ba6b6fe868b65aa95b0923789d571..84b78a752313901c352d1c2b0500658cfc00d3e0 100644 (file)
@@ -14,7 +14,7 @@ test_queries_on_call_with_inference_limit :-
          error,
          true),
     \+ call_with_inference_limit(g(X), 5, R),
-    maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]),
+    maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), % TODO this line fails!
     findall([R,X],
            call_with_inference_limit(g(X), 11, R),
            [[true, 1],
@@ -30,7 +30,7 @@ test_queries_on_call_with_inference_limit :-
             [true, 4],
             [!, 5]]),
     findall([R,X],
-           (call_with_inference_limit(g(X), 5, R), call(true)),
+           (call_with_inference_limit(g(X), 2, R), call(true)),
            [[true, 1],
             [true, 2],
             [inference_limit_exceeded, _]]),
index 528ded35882aa9e073bbca78090665ad5cfae989..a2b9891872f85807dc9c91c1c60ba00881aabde4 100644 (file)
@@ -1,4 +1,5 @@
 use crate::parser::ast::*;
+use crate::forms::GenContext;
 
 use bit_set::*;
 use fxhash::FxBuildHasher;