From: Mark Thom Date: Wed, 31 Jul 2024 20:04:55 +0000 (-0600) Subject: variable revision X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=310a369002386a6e6121a714dee9adcfafa6036e;p=scryer-prolog.git variable revision --- diff --git a/build/instructions_template.rs b/build/instructions_template.rs index eaf1881c..84d0abad 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -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)))]) } } } diff --git a/src/allocator.rs b/src/allocator.rs index cd32f41f..27def1d6 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -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, diff --git a/src/arithmetic.rs b/src/arithmetic.rs index c26d3cec..9253ee49 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -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, 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::(&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::( - 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::( + 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::(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 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) { diff --git a/src/codegen.rs b/src/codegen.rs index 24f90c8b..06d8c8e4 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -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, target: &mut CodeDeque, ) -> Option { 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); - } else { - let var_num = var_ptr.to_var_num().unwrap(); - - self.deep_var_instr::( - 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::( + var_num, + context, + target, + ); + } + VarPtr::Anon => { + Self::add_or_increment_void_instr::(target); + } } None @@ -482,7 +481,6 @@ impl<'b> CodeGenerator<'b> { &mut self, mut iter: Iter, index_ptrs: &IndexMap, - 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::(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::( + var_num, + lvl, + context, + &mut target, + ); + } + VarPtr::Anon => { + if let GenContext::Head = context { + self.marker.advance_arg(); + } else { + self.marker.mark_anon_var::(lvl, context, &mut target); + } } - } else { - self.marker.mark_var::( - 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::( - 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::( head, - var_locs, head_loc, context, index_ptrs, @@ -589,7 +590,6 @@ impl<'b> CodeGenerator<'b> { let tail_r_opt = self.subterm_to_instr::( 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::( - 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::( - 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::( + 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::( - 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::( + self.marker.mark_var::( 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::( 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::( 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::( iter, &clause.code_indices, - &mut term.var_locs, context, ); diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index b473d9d1..4577b1e6 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -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 => {} } } } diff --git a/src/forms.rs b/src/forms.rs index 4dee7439..be96e30c 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -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>), - Chunk(VecDeque), + Chunk { chunk_num: usize, terms: VecDeque }, } #[derive(Debug)] pub struct ChunkedTermVec { pub chunk_vec: VecDeque, + 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) { + 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); } } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 26f48cb3..8d434b15 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -479,7 +479,7 @@ pub struct HCPrinter<'a, Outputter> { toplevel_spec: Option, last_item_idx: usize, parent_of_first_op: Option<(DirectedOp, usize)>, - pub var_names: IndexMap, + pub var_names: IndexMap, 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(); diff --git a/src/iterators.rs b/src/iterators.rs index 030daf81..c139f006 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -232,7 +232,7 @@ pub(crate) enum ClauseItem<'a> { FirstBranch(usize), NextBranch, BranchEnd(usize), - Chunk(&'a VecDeque), + Chunk { chunk_num: usize, terms: &'a VecDeque }, } #[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 { 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); } diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index cdd7c515..496007bd 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1156,7 +1156,7 @@ impl MachineState { ) -> Result { 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); diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 4ddf1f33..983f5961 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -2283,40 +2283,36 @@ impl Machine { term_reg: RegType, vars: Vec, ) -> 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(()) diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index 801ce078..d7f35155 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -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 { + 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, @@ -111,7 +135,7 @@ impl BranchInfo { } } -type BranchMapInt = IndexMap>; +type BranchMapInt = IndexMap>; #[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, } +#[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, +} + +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, 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, + ); } } } diff --git a/src/machine/gc.rs b/src/machine/gc.rs index 4d3d45ec..456f075f 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -33,10 +33,12 @@ pub(crate) trait UnmarkPolicy { } } +#[cfg(test)] pub(crate) struct IteratorUMP { mark_phase: bool, } +#[cfg(test)] fn invert_marker(iter: &mut StacklessPreOrderHeapIter) { if iter.heap[iter.start].get_forwarding_bit() { while !iter.backward() {} @@ -50,6 +52,7 @@ fn invert_marker(iter: &mut StacklessPreOrderHeapIter) { while iter.forward().is_some() {} } +#[cfg(test)] impl UnmarkPolicy for IteratorUMP { #[inline(always)] fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option { @@ -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(); diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index 5e8d887f..bd4ea36e 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -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 = 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, diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 5b96fe37..40800f97 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -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::( &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) } diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 511695d9..ea8db552 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -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) } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index bd2b217f..1c18f16a 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -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, // (&'a VarPtr, &'a HeapCellValue)>, + iter: impl Iterator, atom_tbl: &AtomTable, ) -> Vec { 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, ) -> 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 = IndexMap::new(); + let mut var_names: IndexMap = 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!(); diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 5b0096fc..badd6255 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -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(); diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 39259656..477e9382 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -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>); - -impl Hash for VarPtr { - #[inline(always)] - fn hash(&self, hasher: &mut H) { - self.borrow().hash(hasher) - } -} - -impl Deref for VarPtr { - type Target = RefCell; - - #[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 { - 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 for VarPtr { - #[inline(always)] - fn from(value: Var) -> VarPtr { - VarPtr(Rc::new(RefCell::new(value))) - } -} - -impl From 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 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; 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>(iter: I) -> VarLocs { +pub fn inverse_var_locs_from_iter>(iter: I) -> InverseVarLocs { let mut occurrence_set: IndexMap = IndexMap::with_hasher(FxBuildHasher::default()); @@ -1056,21 +935,20 @@ pub fn var_locs_from_iter>(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; - -#[derive(Debug, Default)] -pub struct VarLocs(IndexMap, 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( - &mut self, - key: usize, - wrapper: impl FnOnce(&VarPtr) -> R, - ) -> Option { - 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 { - 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)> { - self.0.iter().map(|(&k, v)| (k, v)) - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - #[inline] - pub fn drain(&mut self, range: R) -> indexmap::map::Drain> - where R: RangeBounds - { - self.0.drain(range) - } - - #[inline] - pub fn insert(&mut self, key: usize, var_ptrs: VecDeque) { - self.0.insert(key, var_ptrs); - } -} +pub type VarLocs = IndexMap; +pub type InverseVarLocs = IndexMap; #[derive(Debug)] pub struct FocusedHeap { pub heap: Vec, 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, } } diff --git a/src/parser/parser.rs b/src/parser/parser.rs index bffc7167..5271b4a0 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -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, terms: Vec, var_locs: VarLocs, - var_names_to_locs: VarNamesToLocs, + inverse_var_locs: InverseVarLocs, } fn read_tokens(lexer: &mut Lexer) -> Result, 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(), diff --git a/src/read.rs b/src/read.rs index 9759caf3..e2fcfa0c 100644 --- a/src/read.rs +++ b/src/read.rs @@ -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, } diff --git a/src/tests/call_with_inference_limit.pl b/src/tests/call_with_inference_limit.pl index 18fda2dd..84b78a75 100644 --- a/src/tests/call_with_inference_limit.pl +++ b/src/tests/call_with_inference_limit.pl @@ -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, _]]), diff --git a/src/variable_records.rs b/src/variable_records.rs index 528ded35..a2b98918 100644 --- a/src/variable_records.rs +++ b/src/variable_records.rs @@ -1,4 +1,5 @@ use crate::parser::ast::*; +use crate::forms::GenContext; use bit_set::*; use fxhash::FxBuildHasher;