From: Mark Thom Date: Tue, 16 Jul 2024 21:38:22 +0000 (-0600) Subject: remove Term X-Git-Tag: v0.10.0~35^2~63 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=1ef681bd216317f01caeb2f75fb8549b51821b7f;p=scryer-prolog.git remove Term --- diff --git a/build/instructions_template.rs b/build/instructions_template.rs index f6f9351e..eaf1881c 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -192,9 +192,9 @@ enum ReplCodePtr { DynamicProperty, #[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))] AbolishClause, - #[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "$asserta")))] Asserta, - #[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "$assertz")))] Assertz, #[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))] Retract, diff --git a/src/allocator.rs b/src/allocator.rs index e961b975..cd32f41f 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -4,8 +4,6 @@ use crate::forms::*; use crate::instructions::*; use crate::targets::*; -use std::cell::Cell; - pub(crate) trait Allocator { fn new() -> Self; @@ -19,22 +17,21 @@ pub(crate) trait Allocator { fn mark_non_var<'a, Target: CompilationTarget<'a>>( &mut self, lvl: Level, + heap_loc: usize, context: GenContext, - cell: &'a Cell, code: &mut CodeDeque, - ); + ) -> RegType; #[allow(clippy::too_many_arguments)] fn mark_reserved_var<'a, Target: CompilationTarget<'a>>( &mut self, var_num: usize, lvl: Level, - cell: &Cell, - term_loc: GenContext, + context: GenContext, code: &mut CodeDeque, r: RegType, is_new_var: bool, - ); + ) -> RegType; fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType; @@ -42,14 +39,13 @@ pub(crate) trait Allocator { &mut self, var_num: usize, lvl: Level, - cell: &Cell, context: GenContext, code: &mut CodeDeque, - ); + ) -> RegType; fn reset(&mut self); fn reset_arg(&mut self, arg_num: usize); - fn reset_at_head(&mut self, args: &[Term]); + fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize); fn reset_contents(&mut self); fn advance_arg(&mut self); diff --git a/src/arithmetic.rs b/src/arithmetic.rs index e5d6b114..c26d3cec 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -7,6 +7,8 @@ use crate::debray_allocator::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::*; +use crate::machine::stack::Stack; +use crate::parser::ast::FocusedHeap; use crate::targets::QueryInstruction; use crate::types::*; @@ -20,7 +22,6 @@ use dashu::base::BitTest; use num_order::NumOrd; use ordered_float::{Float, OrderedFloat}; -use std::cell::Cell; use std::cmp::{max, min, Ordering}; use std::convert::TryFrom; use std::f64; @@ -51,13 +52,14 @@ impl Default for ArithmeticTerm { } } +pub(crate) type ArithCont = (CodeDeque, Option); + +/* #[derive(Debug)] pub(crate) struct ArithInstructionIterator<'a> { state_stack: Vec>, } -pub(crate) type ArithCont = (CodeDeque, Option); - impl<'a> ArithInstructionIterator<'a> { fn push_subterm(&mut self, lvl: Level, term: &'a Term) { self.state_stack @@ -134,13 +136,6 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { } } -#[derive(Debug)] -pub(crate) struct ArithmeticEvaluator<'a> { - marker: &'a mut DebrayAllocator, - interm: Vec, - interm_c: usize, -} - pub(crate) trait ArithmeticTermIter<'a> { type Iter: Iterator, ArithmeticError>>; @@ -154,23 +149,31 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term { ArithInstructionIterator::from(self) } } +*/ + +#[derive(Debug)] +pub(crate) struct ArithmeticEvaluator<'a> { + marker: &'a mut DebrayAllocator, + interm: Vec, + interm_c: usize, +} -fn push_literal(interm: &mut Vec, c: &Literal) -> Result<(), ArithmeticError> { +fn push_literal(interm: &mut Vec, c: Literal) -> Result<(), ArithmeticError> { match c { - Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))), - Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))), + Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(n))), + Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(n))), Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))), - Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))), - Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number( + Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(n))), + Literal::Atom(name) if name == atom!("e") => interm.push(ArithmeticTerm::Number( Number::Float(OrderedFloat(std::f64::consts::E)), )), - Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number( + Literal::Atom(name) if name == atom!("pi") => interm.push(ArithmeticTerm::Number( Number::Float(OrderedFloat(std::f64::consts::PI)), )), - Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number( + 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(c, 0)), } Ok(()) @@ -309,44 +312,57 @@ impl<'a> ArithmeticEvaluator<'a> { pub(crate) fn compile_is( &mut self, - src: &'a Term, - term_loc: GenContext, + src: &mut FocusedHeap, + term_loc: usize, + context: GenContext, arg: usize, ) -> Result { let mut code = CodeDeque::new(); - - for term_ref in src.iter()? { - match term_ref? { - ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?, - ArithTermRef::Var(lvl, cell, name) => { - let var_num = name.to_var_num().unwrap(); - - let r = if lvl == Level::Shallow { - self.marker - .mark_non_callable(var_num, arg, term_loc, cell, &mut code) - } else if term_loc.is_last() || cell.get().norm().reg_num() == 0 { - let r = self.marker.get_binding(var_num); + let mut stack = Stack::uninitialized(); + let mut iter = query_iterator::(&mut src.heap, &mut stack, term_loc); + + while let Some(term) = iter.next() { + read_heap_cell!(term, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + 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, cell, term_loc, &mut code, - ); - cell.get().norm() + var_num, lvl, context, &mut code, + ) } else { self.marker.increment_running_count(var_num); r } } else { self.marker.increment_running_count(var_num); - cell.get().norm() + old_r }; self.interm.push(ArithmeticTerm::Reg(r)); } - ArithTermRef::Op(name, arity) => { - code.push_back(self.instr_from_clause(name, arity)?); + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + push_literal(&mut self.interm, Literal::Atom(name))?; + } else { + code.push_back(self.instr_from_clause(name, arity)?); + } } - } + _ => { + match Literal::try_from(term) { + Ok(lit) => push_literal(&mut self.interm, lit)?, + _ => unreachable!() + } + } + ); } Ok((code, self.interm.pop())) diff --git a/src/codegen.rs b/src/codegen.rs index 5de85584..24f90c8b 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,4 +1,5 @@ use crate::allocator::*; +use crate::arena::ArenaHeaderTag; use crate::arithmetic::*; use crate::atom_table::*; use crate::debray_allocator::*; @@ -6,6 +7,7 @@ use crate::forms::*; use crate::indexing::*; use crate::instructions::*; use crate::iterators::*; +use crate::machine::heap::{heap_bound_deref, heap_bound_store}; use crate::parser::ast::*; use crate::targets::*; use crate::types::*; @@ -13,11 +15,14 @@ use crate::variable_records::*; use crate::machine::disjuncts::*; use crate::machine::machine_errors::*; +use crate::machine::machine_indices::CodeIndex; +use crate::machine::machine_state::pstr_loc_and_offset; +use crate::machine::stack::Stack; use fxhash::FxBuildHasher; +use indexmap::IndexMap; use indexmap::IndexSet; -use std::cell::Cell; use std::collections::VecDeque; #[derive(Debug)] @@ -276,37 +281,45 @@ pub(crate) struct CodeGenerator<'a> { pub(crate) skeleton: PredicateSkeleton, } -impl DebrayAllocator { - fn mark_var_in_non_callable( - &mut self, - var_num: usize, - term_loc: GenContext, - vr: &Cell, - code: &mut CodeDeque, - ) -> RegType { - self.mark_var::(var_num, Level::Shallow, vr, term_loc, code); - vr.get().norm() +fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) { + let subterm = heap[subterm_loc]; + + if subterm.is_ref() { + let subterm = heap_bound_deref(heap, subterm); + let subterm_loc = subterm.get_value() as usize; + let subterm = heap_bound_store(heap, subterm); + + let subterm_loc = if subterm.is_ref() { + subterm.get_value() as usize + } else { + subterm_loc + }; + + (subterm_loc, subterm) + } else { + (subterm_loc, subterm) } +} +impl DebrayAllocator { pub(crate) fn mark_non_callable( &mut self, var_num: usize, arg: usize, - term_loc: GenContext, - vr: &Cell, + context: GenContext, code: &mut CodeDeque, ) -> RegType { - match self.get_binding(var_num) { + match self.get_var_binding(var_num) { RegType::Temp(t) if t != 0 => RegType::Temp(t), RegType::Perm(p) if p != 0 => { - if let GenContext::Last(_) = term_loc { - self.mark_var_in_non_callable(var_num, term_loc, vr, code); + if let GenContext::Last(_) = context { + self.mark_var::(var_num, Level::Shallow, context, code); temp_v!(arg) } else { - if let VarAlloc::Perm(_, PermVarAllocation::Pending) = + if let VarAlloc::Perm { allocation: PermVarAllocation::Pending, .. } = &self.var_data.records[var_num].allocation { - self.mark_var_in_non_callable(var_num, term_loc, vr, code); + self.mark_var::(var_num, Level::Shallow, context, code); } else { self.increment_running_count(var_num); } @@ -314,35 +327,14 @@ impl DebrayAllocator { RegType::Perm(p) } } - _ => self.mark_var_in_non_callable(var_num, term_loc, vr, code), - } - } -} - -// if the final argument of the structure is a Literal::Index, -// decrement the arity of the PutStructure instruction by 1. -fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) { - match instr { - Instruction::PutStructure(_, ref mut arity, _) - | Instruction::GetStructure(.., ref mut arity, _) => { - if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { - // it is acceptable if arity == 0 is the result of - // this decrement. call/N will have to read the index - // constant for '$call_inline' to succeed. to find it, - // it must know the heap location of the index. - // self.store must stop before reading the atom into a - // register. - - *arity -= 1; - } + _ => self.mark_var::(var_num, Level::Shallow, context, code), } - _ => {} } } trait AddToFreeList<'a, Target: CompilationTarget<'a>> { fn add_term_to_free_list(&mut self, r: RegType); - fn add_subterm_to_free_list(&mut self, term: &Term); + fn add_subterm_to_free_list(&mut self, r: RegType); } impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> { @@ -350,7 +342,7 @@ impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> { self.marker.add_reg_to_free_list(r); } - fn add_subterm_to_free_list(&mut self, _term: &Term) {} + fn add_subterm_to_free_list(&mut self, _r: RegType) {} } impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> { @@ -358,21 +350,33 @@ impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> { fn add_term_to_free_list(&mut self, _r: RegType) {} #[inline(always)] - fn add_subterm_to_free_list(&mut self, term: &Term) { - if let Some(cell) = structure_cell(term) { - self.marker.add_reg_to_free_list(cell.get()); - } + fn add_subterm_to_free_list(&mut self, r: RegType) { + self.marker.add_reg_to_free_list(r); } } -fn structure_cell(term: &Term) -> Option<&Cell> { - match term { - &Term::Cons(ref cell, ..) - | &Term::Clause(ref cell, ..) - | Term::PartialString(ref cell, ..) - | Term::CompleteString(ref cell, ..) => Some(cell), - _ => None, +fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>( + index_ptrs: &IndexMap, + heap: &[HeapCellValue], + arity: usize, + heap_loc: usize, +) -> Option { + match fetch_index_ptr(heap, arity, heap_loc) { + Some(index_ptr) => { + let subterm = Literal::CodeIndex(index_ptr); + return Some(Target::constant_subterm(subterm)); + } + None => { + // if Level::Shallow == lvl { + if let Some(index_ptr) = index_ptrs.get(&heap_loc) { + let subterm = Literal::CodeIndex(*index_ptr); + return Some(Target::constant_subterm(subterm)); + } + // } + } } + + None } impl<'b> CodeGenerator<'b> { @@ -401,14 +405,13 @@ impl<'b> CodeGenerator<'b> { fn deep_var_instr<'a, Target: crate::targets::CompilationTarget<'a>>( &mut self, - cell: &'a Cell, var_num: usize, - term_loc: GenContext, + context: GenContext, target: &mut CodeDeque, ) { if self.marker.var_data.records[var_num].num_occurrences > 1 { self.marker - .mark_var::(var_num, Level::Deep, cell, term_loc, target); + .mark_var::(var_num, Level::Deep, context, target); } else { Self::add_or_increment_void_instr::(target); } @@ -416,134 +419,244 @@ impl<'b> CodeGenerator<'b> { fn subterm_to_instr<'a, Target: crate::targets::CompilationTarget<'a>>( &mut self, - subterm: &'a Term, - term_loc: GenContext, + subterm: HeapCellValue, + var_locs: &mut VarLocs, + heap_loc: usize, + context: GenContext, + index_ptrs: &IndexMap, target: &mut CodeDeque, - ) { - match subterm { - &Term::AnonVar => { - Self::add_or_increment_void_instr::(target); + ) -> Option { + let subterm = unmark_cell_bits!(subterm); + + 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, + ); + } + + None } - &Term::Cons(ref cell, ..) - | &Term::Clause(ref cell, ..) - | Term::PartialString(ref cell, ..) - | Term::CompleteString(ref cell, ..) => { - self.marker - .mark_non_var::(Level::Deep, term_loc, cell, target); - target.push_back(Target::clause_arg_to_instr(cell.get())); + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + if index_ptrs.contains_key(&heap_loc) { + let r = self.marker.mark_non_var::(Level::Deep, heap_loc, context, target); + target.push_back(Target::clause_arg_to_instr(r)); + return Some(r); + } else { + target.push_back(Target::constant_subterm(Literal::Atom(name))); + } + + None } - Term::Literal(_, ref constant) => { - target.push_back(Target::constant_subterm(*constant)); + (HeapCellValueTag::Str + | HeapCellValueTag::Lis + | HeapCellValueTag::PStrLoc + | HeapCellValueTag::CStr) => { + let r = self.marker.mark_non_var::(Level::Deep, heap_loc, context, target); + target.push_back(Target::clause_arg_to_instr(r)); + return Some(r); } - Term::Var(ref cell, ref var_ptr) => { - self.deep_var_instr::( - cell, - var_ptr.to_var_num().unwrap(), - term_loc, - target, - ); + _ => { + match Literal::try_from(subterm) { + Ok(lit) => target.push_back(Target::constant_subterm(lit)), + Err(_) => unreachable!(), + } + + None } - }; + ) } - fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, term_loc: GenContext) -> CodeDeque + fn compile_target<'a, Target, Iter>( + &mut self, + mut iter: Iter, + index_ptrs: &IndexMap, + var_locs: &mut VarLocs, + context: GenContext, + ) -> CodeDeque where Target: crate::targets::CompilationTarget<'a>, - Iter: Iterator>, + Iter: TermIterator, CodeGenerator<'b>: AddToFreeList<'a, Target>, { let mut target = CodeDeque::new(); - for term in iter { - match term { - TermRef::AnonVar(lvl @ Level::Shallow) => { - if let GenContext::Head = term_loc { - self.marker.advance_arg(); + 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) => { + 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); + } + } else { + self.marker.mark_var::( + var_ptr.to_var_num().unwrap(), + lvl, + context, + &mut target, + ); + } + } + } + (HeapCellValueTag::Atom, (name, arity)) => { + let heap_loc = iter.focus().value() as usize; + let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); + + if arity == 0 { + if let Some(instr) = add_index_ptr::(index_ptrs, &iter, arity, heap_loc) { + let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); + target.push_back(Target::to_structure(lvl, name, 0, r)); + target.push_back(instr); + } else if lvl == Level::Shallow { + let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); + target.push_back(Target::to_constant(lvl, Literal::Atom(name), r)); + } } else { - self.marker - .mark_anon_var::(lvl, term_loc, &mut target); + let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); + target.push_back(Target::to_structure(lvl, name, arity, r)); + + as AddToFreeList<'a, Target>>::add_term_to_free_list( + self, + r, + ); + + let free_list_regs: Vec<_> = (heap_loc + 1 ..= heap_loc + arity) + .map(|subterm_loc| { + let (subterm_loc, subterm) = subterm_index(iter.deref(), subterm_loc); + + self.subterm_to_instr::( + subterm, var_locs, subterm_loc, context, index_ptrs, &mut target, + ) + }) + .collect(); + + if let Some(instr) = add_index_ptr::(index_ptrs, &iter, arity, heap_loc) { + target.push_back(instr); + } + + for r_opt in free_list_regs { + if let Some(r) = r_opt { + as AddToFreeList<'a, Target>>::add_subterm_to_free_list( + self, r, + ); + } + } } } - TermRef::Clause(lvl, cell, name, terms) => { - self.marker - .mark_non_var::(lvl, term_loc, cell, &mut target); - target.push_back(Target::to_structure(lvl, name, terms.len(), cell.get())); + (HeapCellValueTag::Lis, l) => { + let heap_loc = iter.focus().value() as usize; + let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); + + let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); + + target.push_back(Target::to_list(lvl, r)); as AddToFreeList<'a, Target>>::add_term_to_free_list( self, - cell.get(), + r, ); - if let Some(instr) = target.back_mut() { - if let Some(term) = terms.last() { - trim_structure_by_last_arg(instr, term); - } - } + let (head_loc, head) = subterm_index(iter.deref(), l); + let (tail_loc, tail) = subterm_index(iter.deref(), l+1); + + let head_r_opt = self.subterm_to_instr::( + head, + var_locs, + head_loc, + context, + index_ptrs, + &mut target, + ); - for subterm in terms { - self.subterm_to_instr::(subterm, term_loc, &mut target); + let tail_r_opt = self.subterm_to_instr::( + tail, + var_locs, + tail_loc, + context, + index_ptrs, + &mut target, + ); + + if let Some(r) = head_r_opt { + as AddToFreeList<'a, Target>>::add_subterm_to_free_list( + self, r, + ); } - for subterm in terms { + if let Some(r) = tail_r_opt { as AddToFreeList<'a, Target>>::add_subterm_to_free_list( - self, subterm, + self, r, ); } } - TermRef::Cons(lvl, cell, head, tail) => { - self.marker - .mark_non_var::(lvl, term_loc, cell, &mut target); - target.push_back(Target::to_list(lvl, cell.get())); + (HeapCellValueTag::CStr, cstr_atom) => { + let heap_loc = iter.focus().value() as usize; + let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - as AddToFreeList<'a, Target>>::add_term_to_free_list( - self, - cell.get(), - ); + target.push_back(Target::to_pstr(lvl, cstr_atom, r, false)); + } + (HeapCellValueTag::PStr, pstr_atom) => { + let heap_loc = iter.focus().value() as usize; + let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); + let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - self.subterm_to_instr::(head, term_loc, &mut target); - self.subterm_to_instr::(tail, term_loc, &mut target); + target.push_back(Target::to_pstr(lvl, pstr_atom, r, true)); - as AddToFreeList<'a, Target>>::add_subterm_to_free_list( - self, head, - ); - as AddToFreeList<'a, Target>>::add_subterm_to_free_list( - self, tail, + 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, ); } - TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => { - self.marker - .mark_non_var::(lvl, term_loc, cell, &mut target); - target.push_back(Target::to_pstr(lvl, *string, cell.get(), false)); - } - TermRef::Literal(lvl @ Level::Shallow, cell, constant) => { - self.marker - .mark_non_var::(lvl, term_loc, cell, &mut target); - target.push_back(Target::to_constant(lvl, *constant, cell.get())); - } - TermRef::PartialString(lvl, cell, string, tail) => { - self.marker - .mark_non_var::(lvl, term_loc, cell, &mut target); - let atom = AtomTable::build_with(self.atom_tbl, string); + (HeapCellValueTag::PStrOffset, l) => { + let heap_loc = iter.focus().value() as usize; + let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(Target::to_pstr(lvl, atom, cell.get(), true)); - self.subterm_to_instr::(tail, term_loc, &mut target); - } - TermRef::CompleteString(lvl, cell, atom) => { - self.marker - .mark_non_var::(lvl, term_loc, cell, &mut target); - target.push_back(Target::to_pstr(lvl, atom, cell.get(), false)); - } - TermRef::Var(lvl @ Level::Shallow, cell, var) => { - self.marker.mark_var::( - var.to_var_num().unwrap(), - lvl, - cell, - term_loc, - &mut target, + let (index, n) = pstr_loc_and_offset(&iter, l); + let n = n.get_num() as usize; + + let pstr_atom = cell_as_atom!(iter[index]); + let pstr_offset_atom = if n == 0 { + pstr_atom + } else { + AtomTable::build_with(self.atom_tbl, &pstr_atom.as_str()[n ..]) + }; + + let (tail_loc, tail) = subterm_index(iter.deref(), l+1); + target.push_back(Target::to_pstr(lvl, pstr_offset_atom, r, true)); + + self.subterm_to_instr::( + tail, var_locs, tail_loc, context, index_ptrs, &mut target, ); } + _ if lvl == Level::Shallow => { + if let Ok(lit) = Literal::try_from(term) { + let heap_loc = iter.focus().value() as usize; + let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); + let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); + target.push_back(Target::to_constant(lvl, lit, r)); + } + } _ => {} - }; + ); } target @@ -575,21 +688,26 @@ impl<'b> CodeGenerator<'b> { fn compile_inlined( &mut self, ct: &InlinedClauseType, - terms: &'_ [Term], - term_loc: GenContext, + terms: &mut FocusedHeap, + term_loc: usize, + context: GenContext, code: &mut CodeDeque, ) -> Result<(), CompilationError> { + let term = terms.heap[terms.nth_arg(term_loc, 1).unwrap()]; + let call_instr = match ct { &InlinedClauseType::CompareNumber(mut cmp) => { self.marker.reset_arg(2); - let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc, 1)?; + let (mut lcode, at_1) = + self.compile_arith_expr(terms, term_loc + 1, 1, context, 1)?; - if !matches!(terms[0], Term::Var(..)) { + if !terms.deref_loc(term_loc + 1).is_var() { self.marker.advance_arg(); } - let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc, 2)?; + let (mut rcode, at_2) = + self.compile_arith_expr(terms, term_loc + 2, 2, context, 2)?; code.append(&mut lcode); code.append(&mut rcode); @@ -599,213 +717,294 @@ impl<'b> CodeGenerator<'b> { compare_number_instr!(cmp, at_1, at_2) } - InlinedClauseType::IsAtom(..) => match &terms[0] { - Term::Literal(_, Literal::Char(_)) - | Term::Literal(_, Literal::Atom(atom!("[]"))) - | Term::Literal(_, Literal::Atom(..)) => { + InlinedClauseType::IsAtom(..) => read_heap_cell!(term, + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + instr!("$succeed") + } else { + instr!("$fail") + } + } + (HeapCellValueTag::Char) => { instr!("$succeed") } - Term::Var(ref vr, ref name) => { + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); self.marker.reset_arg(1); - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); + 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!("atom", r) + } } _ => { instr!("$fail") } - }, - InlinedClauseType::IsAtomic(..) => match &terms[0] { - Term::AnonVar - | Term::Clause(..) - | Term::Cons(..) - | Term::PartialString(..) - | Term::CompleteString(..) => { - instr!("$fail") - } - Term::Literal(_, Literal::String(_)) => { - instr!("$fail") - } - Term::Literal(..) => { - instr!("$succeed") - } - Term::Var(ref vr, ref name) => { - self.marker.reset_arg(1); + ), + 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(); - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); + 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!("atomic", r) + instr!("atomic", r) + } } - }, - InlinedClauseType::IsCompound(..) => match &terms[0] { - Term::Clause(..) - | Term::Cons(..) - | Term::PartialString(..) - | Term::CompleteString(..) - | Term::Literal(_, Literal::String(..)) => { + (HeapCellValueTag::Fixnum | + HeapCellValueTag::Char | + HeapCellValueTag::F64) => { instr!("$succeed") } - Term::Var(ref vr, ref name) => { - self.marker.reset_arg(1); - - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); - - instr!("compound", r) - } - _ => { - instr!("$fail") + (HeapCellValueTag::Cons, cons_ptr) => { + match cons_ptr.get_tag() { + ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => { + instr!("$succeed") + } + _ => { + instr!("$fail") + } + } } - }, - InlinedClauseType::IsRational(..) => match terms[0] { - Term::Literal(_, Literal::Rational(_)) => { - instr!("$succeed") + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + instr!("$succeed") + } else { + instr!("$fail") + } } - Term::Var(ref vr, ref name) => { - self.marker.reset_arg(1); - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); - instr!("rational", r) + (HeapCellValueTag::Lis + | HeapCellValueTag::Str + | HeapCellValueTag::PStrLoc + | HeapCellValueTag::CStr) => { + instr!("$fail") } _ => { - instr!("$fail") + if Literal::try_from(term).is_ok() { + instr!("$succeed") + } else { + instr!("$fail") + } } - }, - InlinedClauseType::IsFloat(..) => match terms[0] { - Term::Literal(_, Literal::Float(_)) => { + ), + InlinedClauseType::IsCompound(..) => { + read_heap_cell!(term, + (HeapCellValueTag::Atom, (_, arity)) => { + if arity > 0 { + 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") + } + } + } + (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() { + 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") } - Term::Var(ref vr, ref name) => { + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); self.marker.reset_arg(1); - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); + 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!("float", r) + } } _ => { instr!("$fail") } - }, - InlinedClauseType::IsNumber(..) => match terms[0] { - Term::Literal(_, Literal::Float(_)) - | Term::Literal(_, Literal::Rational(_)) - | Term::Literal(_, Literal::Integer(_)) - | Term::Literal(_, Literal::Fixnum(_)) => { - instr!("$succeed") - } - Term::Var(ref vr, ref name) => { + ), + 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); - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); + 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!("number", r) + instr!("number", r) + } } _ => { - instr!("$fail") - } - }, - InlinedClauseType::IsNonVar(..) => match terms[0] { - Term::AnonVar => { - instr!("$fail") + if Number::try_from(term).is_ok() { + instr!("$succeed") + } else { + instr!("$fail") + } } - Term::Var(ref vr, ref name) => { + ), + 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); - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); + 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!("nonvar", r) + instr!("nonvar", r) + } } _ => { instr!("$succeed") } - }, - InlinedClauseType::IsInteger(..) => match &terms[0] { - Term::Literal(_, Literal::Integer(_)) | Term::Literal(_, Literal::Fixnum(_)) => { - instr!("$succeed") - } - Term::Var(ref vr, name) => { + ), + 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); + + 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) + } + } + _ => { + match Number::try_from(term) { + Ok(Number::Integer(_) | Number::Fixnum(_)) => { + instr!("$succeed") + } + _ => { + 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); - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); + if var_ptr.is_anon() { + instr!("$succeed") + } else { + let r = self.marker.mark_non_callable( + var_ptr.to_var_num().unwrap(), + 1, + context, + code, + ); - instr!("integer", r) + instr!("var", r) + } } _ => { instr!("$fail") } - }, - InlinedClauseType::IsVar(..) => match terms[0] { - Term::Literal(..) - | Term::Clause(..) - | Term::Cons(..) - | Term::PartialString(..) - | Term::CompleteString(..) => { - instr!("$fail") - } - Term::AnonVar => { - instr!("$succeed") - } - Term::Var(ref vr, ref name) => { - self.marker.reset_arg(1); - - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); - - instr!("var", r) - } - }, + ), }; // inlined predicates are never counted, so this overrides nothing. @@ -816,25 +1015,28 @@ impl<'b> CodeGenerator<'b> { fn compile_arith_expr( &mut self, - term: &Term, + terms: &mut FocusedHeap, + term_loc: usize, target_int: usize, - term_loc: GenContext, + context: GenContext, arg: usize, ) -> Result { let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int); - evaluator.compile_is(term, term_loc, arg) + evaluator.compile_is(terms, term_loc, context, arg) } fn compile_is_call( &mut self, - terms: &[Term], + terms: &mut FocusedHeap, + term_loc: usize, code: &mut CodeDeque, - term_loc: GenContext, + context: GenContext, call_policy: CallPolicy, ) -> Result<(), CompilationError> { macro_rules! compile_expr { - ($self:expr, $terms:expr, $term_loc:expr, $code:expr) => {{ - let (acode, at) = $self.compile_arith_expr($terms, 1, $term_loc, 2)?; + ($self:expr, $terms:expr, $context:expr, $code:expr) => {{ + let (acode, at) = + $self.compile_arith_expr($terms, term_loc + 2, 1, $context, 2)?; $code.extend(acode.into_iter()); at }}; @@ -842,70 +1044,74 @@ impl<'b> CodeGenerator<'b> { self.marker.reset_arg(2); - let at = match terms[0] { - Term::Var(ref vr, ref name) => { - let var_num = name.to_var_num().unwrap(); + let var = { + let var_cell = terms.heap[term_loc + 1]; + let terms = FocusedHeapRefMut::from_cell(&mut terms.heap, var_cell); + + terms.deref_loc(term_loc + 1) + }; + + let 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, - vr, - term_loc, + context, code, ); self.marker.mark_safe_var_unconditionally(var_num); - compile_expr!(self, &terms[1], term_loc, code) + compile_expr!(self, terms, context, code) } else { - self.marker - .mark_anon_var::(Level::Shallow, term_loc, code); + /* + if var.is_var() { + let h = var.get_value() as usize; - if let Term::Var(ref vr, ref var) = &terms[1] { - let var_num = var.to_var_num().unwrap(); + 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. + if self.marker.var_data.records[var_num].num_occurrences > 1 { - self.marker.mark_var::( + let r = self.marker.mark_var::( var_num, Level::Shallow, - vr, - term_loc, + context, code, ); self.marker.mark_safe_var_unconditionally(var_num); - let at = ArithmeticTerm::Reg(vr.get().norm()); + let at = ArithmeticTerm::Reg(r); self.add_call(code, instr!("$get_number", at), call_policy); return Ok(()); } } + */ - compile_expr!(self, &terms[1], term_loc, code) + compile_expr!(self, terms, context, code) } } - Term::Literal( - _, - c @ Literal::Integer(_) - | c @ Literal::Float(_) - | c @ Literal::Rational(_) - | c @ Literal::Fixnum(_), - ) => { - let v = HeapCellValue::from(c); - code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1))); - - self.marker.advance_arg(); - compile_expr!(self, &terms[1], term_loc, code) - } _ => { - code.push_back(instr!("$fail")); - return Ok(()); + if Number::try_from(var).is_ok() { + let v = HeapCellValue::from(var); + code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1))); + + self.marker.advance_arg(); + compile_expr!(self, terms, context, code) + } else { + code.push_back(instr!("$fail")); + return Ok(()); + } } - }; + ); let at = at.unwrap_or(interm!(1)); self.add_call(code, instr!("is", temp_v!(1), at), call_policy); @@ -915,6 +1121,7 @@ impl<'b> CodeGenerator<'b> { fn compile_seq( &mut self, + terms: &mut FocusedHeap, clauses: &ChunkedTermVec, code: &mut CodeDeque, ) -> Result<(), CompilationError> { @@ -926,7 +1133,7 @@ impl<'b> CodeGenerator<'b> { match clause_item { ClauseItem::Chunk(chunk) => { for (idx, term) in chunk.iter().enumerate() { - let term_loc = if idx + 1 < chunk.len() { + let context = if idx + 1 < chunk.len() { GenContext::Mid(chunk_num) } else { self.marker.in_tail_position = clause_iter.in_tail_position(); @@ -955,7 +1162,7 @@ impl<'b> CodeGenerator<'b> { if chunk_num == 0 { code.push_back(instr!("neck_cut")); } else { - let r = self.marker.get_binding(var_num); + let r = self.marker.get_var_binding(var_num); code.push_back(instr!("cut", r)); } @@ -969,7 +1176,7 @@ impl<'b> CodeGenerator<'b> { } &QueryTerm::LocalCut { var_num, cut_prev } => { let code = branch_code_stack.code(code); - let r = self.marker.get_binding(var_num); + let r = self.marker.get_var_binding(var_num); code.push_back(if cut_prev { instr!("cut_prev", r) @@ -988,31 +1195,55 @@ impl<'b> CodeGenerator<'b> { } } &QueryTerm::Clause( - _, - ClauseType::BuiltIn(BuiltInClauseType::Is(..)), - ref terms, - call_policy, + ref clause @ QueryClause { + ct: ClauseType::BuiltIn(BuiltInClauseType::Is(..)), + call_policy, + .. + }, ) => self.compile_is_call( terms, + clause.term_loc(), branch_code_stack.code(code), - term_loc, + context, call_policy, )?, - &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => { - self.compile_inlined( - ct, - terms, - term_loc, - branch_code_stack.code(code), - )? - } + &QueryTerm::Clause( + ref clause @ QueryClause { + ct: ClauseType::Inlined(ref ct), + .. + }, + ) => self.compile_inlined( + ct, + terms, + clause.term_loc(), + context, + branch_code_stack.code(code), + )?, &QueryTerm::Fail => { branch_code_stack.code(code).push_back(instr!("$fail")); } - term @ &QueryTerm::Clause(..) => { + &QueryTerm::Succeed => { + let code = branch_code_stack.code(code); + + if self.marker.in_tail_position { + if self.marker.var_data.allocates { + code.push_back(instr!("deallocate")); + } + } + + code.push_back( + if self.marker.in_tail_position { + instr!("$succeed").to_execute() + } else { + instr!("$succeed") + }, + ); + } + QueryTerm::Clause(clause) => { self.compile_query_line( - term, - term_loc, + terms, + clause, + context, branch_code_stack.code(code), ); @@ -1071,20 +1302,31 @@ impl<'b> CodeGenerator<'b> { pub(crate) fn compile_rule( &mut self, - rule: &Rule, + rule: &mut Rule, var_data: VarData, ) -> Result { let Rule { - head: (_, args), + ref mut term, clauses, } = rule; self.marker.var_data = var_data; + let mut code = VecDeque::new(); + let head_loc = term.nth_arg(term.focus, 1).unwrap(); - self.marker.reset_at_head(args); + self.marker.reset_at_head(term, head_loc); - let iter = FactIterator::from_rule_head_clause(args); - let fact = self.compile_target::(iter, GenContext::Head); + let mut stack = Stack::uninitialized(); + let iter = fact_iterator::( + &mut term.heap, &mut stack, head_loc, + ); + + let fact = self.compile_target::( + iter, + &IndexMap::with_hasher(FxBuildHasher::default()), + &mut term.var_locs, + GenContext::Head, + ); if self.marker.max_reg_allocated() > MAX_ARITY { return Err(CompilationError::ExceededMaxArity); @@ -1093,50 +1335,66 @@ impl<'b> CodeGenerator<'b> { self.marker.reset_free_list(); code.extend(fact); - self.compile_seq(clauses, &mut code)?; + self.compile_seq(term, &clauses, &mut code)?; Ok(Vec::from(code)) } pub(crate) fn compile_fact( &mut self, - fact: &Fact, + fact: &mut Fact, var_data: VarData, ) -> Result { let mut code = Vec::new(); - self.marker.var_data = var_data; - if let Term::Clause(_, _, args) = &fact.head { - self.marker.reset_at_head(args); + let fact_focus = fact.term.focus; + let mut stack = Stack::uninitialized(); - let iter = FactInstruction::iter(&fact.head); - let compiled_fact = self.compile_target::(iter, GenContext::Head); + self.marker.var_data = var_data; + self.marker.reset_at_head(&mut fact.term, fact_focus); - if self.marker.max_reg_allocated() > MAX_ARITY { - return Err(CompilationError::ExceededMaxArity); - } + let iter = fact_iterator::( + &mut fact.term.heap, &mut stack, fact_focus, + ); - code.extend(compiled_fact); + let compiled_fact = self.compile_target::( + iter, + &IndexMap::with_hasher(FxBuildHasher::default()), + &mut fact.term.var_locs, + GenContext::Head, + ); + + if self.marker.max_reg_allocated() > MAX_ARITY { + return Err(CompilationError::ExceededMaxArity); } + code.extend(compiled_fact); code.push(instr!("proceed")); + Ok(code) } - fn compile_query_line(&mut self, term: &QueryTerm, term_loc: GenContext, code: &mut CodeDeque) { - self.marker.reset_arg(term.arity()); + fn compile_query_line( + &mut self, + term: &mut FocusedHeap, + clause: &QueryClause, + context: GenContext, + code: &mut CodeDeque, + ) { + self.marker.reset_arg(term.arity(clause.term_loc())); - let iter = QueryIterator::new(term); - let query = self.compile_target::(iter, term_loc); + let mut stack = Stack::uninitialized(); + let iter = query_iterator::(&mut term.heap, &mut stack, clause.term_loc()); - code.extend(query); + let query = self.compile_target::( + iter, + &clause.code_indices, + &mut term.var_locs, + context, + ); - match term { - &QueryTerm::Clause(_, ref ct, _, call_policy) => { - self.add_call(code, ct.to_instr(), call_policy); - } - _ => unreachable!(), - }; + code.extend(query); + self.add_call(code, clause.ct.to_instr(), clause.call_policy); } fn split_predicate(clauses: &[PredicateClause]) -> Vec { @@ -1146,28 +1404,27 @@ impl<'b> CodeGenerator<'b> { 'outer: for (right, clause) in clauses.iter().enumerate() { if let Some(args) = clause.args() { - for (instantiated_arg_index, arg) in args.iter().enumerate() { - match arg { - Term::Var(..) | Term::AnonVar => {} - _ => { - if optimal_index != instantiated_arg_index { - if left >= right { - optimal_index = instantiated_arg_index; - continue 'outer; - } - - subseqs.push(ClauseSpan { - left, - right, - instantiated_arg_index: optimal_index, - }); + for (instantiated_arg_index, arg) in args.iter().cloned().enumerate() { + let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg)); + if !arg.is_var() { + if optimal_index != instantiated_arg_index { + if left >= right { optimal_index = instantiated_arg_index; - left = right; + continue 'outer; } - continue 'outer; + subseqs.push(ClauseSpan { + left, + right, + instantiated_arg_index: optimal_index, + }); + + optimal_index = instantiated_arg_index; + left = right; } + + continue 'outer; } } } @@ -1256,11 +1513,18 @@ impl<'b> CodeGenerator<'b> { let arg = clause.args().and_then(|args| args.get(optimal_index)); - if let Some(arg) = arg { + if let Some(arg) = arg.cloned() { let index = code.len(); if clauses_len > 1 || self.settings.is_extensible { - code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl); + let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg)); + code_offsets.index_term( + clause.heap(), + arg, + index, + &mut clause_index_info, + self.atom_tbl, + ); } } diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index d44c36cb..b473d9d1 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -1,10 +1,13 @@ use crate::allocator::*; +use crate::atom_table::*; use crate::codegen::SubsumedBranchHits; use crate::forms::Level; use crate::instructions::*; use crate::machine::disjuncts::VarData; +use crate::machine::heap::{heap_bound_deref, heap_bound_store}; use crate::parser::ast::*; use crate::targets::*; +use crate::types::*; use crate::variable_records::*; use bit_set::*; @@ -12,7 +15,6 @@ use bitvec::prelude::*; use fxhash::FxBuildHasher; use indexmap::IndexMap; -use std::cell::Cell; use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; @@ -152,6 +154,8 @@ pub(crate) struct DebrayAllocator { in_use: BitSet, // deep and non-var allocations temp_free_list: Vec, perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num + non_var_registers: IndexMap, + non_var_register_heap_locs: IndexMap, } impl DebrayAllocator { @@ -168,7 +172,7 @@ impl DebrayAllocator { for var_num in subsumed_hits { match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm(_, ref mut allocation) => { + VarAlloc::Perm { ref mut allocation, .. } => { if let PermVarAllocation::Done { shallow_safety, deep_safety, @@ -229,7 +233,7 @@ impl DebrayAllocator { let num_occurrences = self.var_data.records[var_num].num_occurrences; match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm(_, allocation) => { + VarAlloc::Perm { allocation, ..} => { let shallow_safety = VarSafetyStatus::needed_if( shallow_safety.contains(var_num), branch_designator, @@ -366,7 +370,7 @@ impl DebrayAllocator { &mut self, chunk_num: usize, code: &mut CodeDeque, - ) { + ) -> Option { if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) { let k = self.arg_c; @@ -382,8 +386,12 @@ impl DebrayAllocator { .allocation .set_register(r.reg_num()); self.in_use.insert(r.reg_num()); + + return Some(r); } }; + + None } fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>( @@ -433,6 +441,7 @@ impl DebrayAllocator { } self.temp_lb = final_index + 1; + final_index } @@ -456,7 +465,11 @@ impl DebrayAllocator { p }; - self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done()); + self.var_data.records[var_num].allocation = VarAlloc::Perm { + reg: p, + allocation: PermVarAllocation::done(), + }; + p } @@ -472,10 +485,15 @@ impl DebrayAllocator { } #[inline(always)] - pub fn get_binding(&self, var_num: usize) -> RegType { + pub fn get_var_binding(&self, var_num: usize) -> RegType { self.var_data.records[var_num].allocation.as_reg_type() } + #[inline(always)] + pub fn get_non_var_binding(&self, heap_loc: usize) -> RegType { + RegType::Temp(self.non_var_registers.get(&heap_loc).cloned().unwrap_or(0)) + } + pub fn num_perm_vars(&self) -> usize { self.perm_lb - 1 } @@ -485,7 +503,7 @@ impl DebrayAllocator { } fn add_perm_to_free_list(&mut self, chunk_num: usize, var_num: usize) { - if let VarAlloc::Perm(..) = &self.var_data.records[var_num].allocation { + if let VarAlloc::Perm { .. } = &self.var_data.records[var_num].allocation { self.perm_free_list.push_back((chunk_num, var_num)); } } @@ -496,9 +514,10 @@ impl DebrayAllocator { self.perm_free_list.pop_front(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => { - return Some(std::mem::replace(p, 0)); - } + VarAlloc::Perm { reg: p, allocation: PermVarAllocation::Pending } + if *p > 0 => { + return Some(std::mem::replace(p, 0)); + } _ => {} } } else { @@ -510,9 +529,12 @@ impl DebrayAllocator { } pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) { - if let VarAlloc::Perm(_, allocation) = &mut self.var_data.records[var_num].allocation { - *allocation = PermVarAllocation::Pending; - self.add_perm_to_free_list(chunk_num, var_num); + match &mut self.var_data.records[var_num].allocation { + VarAlloc::Perm { allocation, .. } => { + *allocation = PermVarAllocation::Pending; + self.add_perm_to_free_list(chunk_num, var_num); + } + _ => {} } } @@ -520,14 +542,14 @@ impl DebrayAllocator { let branch_designator = self.branch_stack.current_branch_designator(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm( - _, - PermVarAllocation::Done { + VarAlloc::Perm { + allocation: PermVarAllocation::Done { deep_safety, shallow_safety, .. }, - ) => { + .. + } => { *deep_safety = VarSafetyStatus::unneeded(branch_designator); *shallow_safety = VarSafetyStatus::unneeded(branch_designator); } @@ -542,14 +564,14 @@ impl DebrayAllocator { let branch_designator = self.branch_stack.current_branch_designator(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm( - _, - PermVarAllocation::Done { + VarAlloc::Perm { + allocation: PermVarAllocation::Done { deep_safety, shallow_safety, .. }, - ) => { + .. + } => { // GetVariable in head chunk is considered safe. if lvl == Level::Deep { *deep_safety = VarSafetyStatus::unneeded(branch_designator); @@ -586,13 +608,13 @@ impl DebrayAllocator { let branch_designator = self.branch_stack.current_branch_designator(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm( - _, - PermVarAllocation::Done { + VarAlloc::Perm { + allocation: PermVarAllocation::Done { ref mut shallow_safety, .. }, - ) => { + .. + } => { if !self.in_tail_position || self .branch_stack @@ -622,13 +644,13 @@ impl DebrayAllocator { let branch_designator = self.branch_stack.current_branch_designator(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm( - _, - PermVarAllocation::Done { + VarAlloc::Perm { + allocation: PermVarAllocation::Done { ref mut deep_safety, .. }, - ) => { + .. + } => { if self .branch_stack .safety_unneeded_in_branch(deep_safety, &branch_designator) @@ -671,13 +693,15 @@ impl Allocator for DebrayAllocator { temp_free_list: vec![], perm_free_list: VecDeque::new(), branch_stack: BranchStack { stack: vec![] }, + non_var_registers: IndexMap::with_hasher(FxBuildHasher::default()), + non_var_register_heap_locs: IndexMap::with_hasher(FxBuildHasher::default()), } } fn mark_anon_var<'a, Target: CompilationTarget<'a>>( &mut self, lvl: Level, - term_loc: GenContext, + context: GenContext, code: &mut CodeDeque, ) { let r = RegType::Temp(self.alloc_reg_to_non_var()); @@ -687,7 +711,7 @@ impl Allocator for DebrayAllocator { Level::Root | Level::Shallow => { let k = self.arg_c; - if let GenContext::Last(chunk_num) = term_loc { + if let GenContext::Last(chunk_num) = context { self.evacuate_arg::(chunk_num, code); } @@ -701,55 +725,69 @@ impl Allocator for DebrayAllocator { fn mark_non_var<'a, Target: CompilationTarget<'a>>( &mut self, lvl: Level, - term_loc: GenContext, - cell: &'a Cell, + heap_loc: usize, + context: GenContext, code: &mut CodeDeque, - ) { - let r = cell.get(); + ) -> RegType { + let r = self.get_non_var_binding(heap_loc); let r = match lvl { Level::Shallow => { let k = self.arg_c; - if let GenContext::Last(chunk_num) = term_loc { - self.evacuate_arg::(chunk_num, code); + if let GenContext::Last(chunk_num) = context { + if let Some(new_r) = self.evacuate_arg::(chunk_num, code) { + self.non_var_register_heap_locs + .swap_remove(&k) + .map(|old_heap_loc| { + self.non_var_registers.insert(old_heap_loc, new_r.reg_num()); + self.non_var_register_heap_locs + .insert(new_r.reg_num(), old_heap_loc); + }); + + self.non_var_registers.insert(heap_loc, k); + self.non_var_register_heap_locs.insert(k, heap_loc); + } } self.arg_c += 1; RegType::Temp(k) } - _ if r.reg_num() == 0 => RegType::Temp(self.alloc_reg_to_non_var()), + _ if r.reg_num() == 0 => { + let r = RegType::Temp(self.alloc_reg_to_non_var()); + self.non_var_registers.insert(heap_loc, r.reg_num()); + self.non_var_register_heap_locs + .insert(r.reg_num(), heap_loc); + r + } _ => { self.in_use.insert(r.reg_num()); r } }; - cell.set(r); + r } fn mark_var<'a, Target: CompilationTarget<'a>>( &mut self, var_num: usize, lvl: Level, - cell: &Cell, - term_loc: GenContext, + context: GenContext, code: &mut CodeDeque, - ) { - let (r, is_new_var) = match self.get_binding(var_num) { + ) -> RegType { + let (r, is_new_var) = match self.get_var_binding(var_num) { RegType::Temp(0) => { - let o = self.alloc_reg_to_var::(var_num, lvl, term_loc, code); - cell.set(VarReg::Norm(RegType::Temp(o))); + let o = self.alloc_reg_to_var::(var_num, lvl, context, code); (RegType::Temp(o), true) } RegType::Perm(0) => { - let p = self.alloc_perm_var(var_num, term_loc.chunk_num()); - cell.set(VarReg::Norm(RegType::Perm(p))); + let p = self.alloc_perm_var(var_num, context.chunk_num()); (RegType::Perm(p), true) } r @ RegType::Perm(_) => { let is_new_var = match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm(_, allocation) => { + VarAlloc::Perm { allocation, .. } => { if allocation.pending() { *allocation = PermVarAllocation::done(); true @@ -765,32 +803,29 @@ impl Allocator for DebrayAllocator { r => (r, false), }; - self.mark_reserved_var::(var_num, lvl, cell, term_loc, code, r, is_new_var); + self.mark_reserved_var::(var_num, lvl, context, code, r, is_new_var) } fn mark_reserved_var<'a, Target: CompilationTarget<'a>>( &mut self, var_num: usize, lvl: Level, - cell: &Cell, - term_loc: GenContext, + context: GenContext, code: &mut CodeDeque, r: RegType, is_new_var: bool, - ) { + ) -> RegType { match lvl { Level::Root | Level::Shallow => { let k = self.arg_c; if self.is_curr_arg_distinct_from(var_num) { - self.evacuate_arg::(term_loc.chunk_num(), code); + self.evacuate_arg::(context.chunk_num(), code); } - cell.set(VarReg::ArgAndNorm(r, k)); - - if !self.in_place(var_num, term_loc, r, k) { + if !self.in_place(var_num, context, r, k) { if is_new_var { - self.mark_safe_var(var_num, lvl, term_loc); + self.mark_safe_var(var_num, lvl, context); code.push_back(Target::argument_to_variable(r, k)); } else { code.push_back(self.argument_to_value::(var_num, r, k)); @@ -800,15 +835,15 @@ impl Allocator for DebrayAllocator { self.arg_c += 1; } Level::Deep if is_new_var => { - if let GenContext::Head = term_loc { + if let GenContext::Head = context { if self.occurs_shallowly_in_head(var_num, r.reg_num()) { code.push_back(self.subterm_to_value::(var_num, r)); } else { - self.mark_safe_var(var_num, lvl, term_loc); + self.mark_safe_var(var_num, lvl, context); code.push_back(Target::subterm_to_variable(r)); } } else { - self.mark_safe_var(var_num, lvl, term_loc); + self.mark_safe_var(var_num, lvl, context); code.push_back(Target::subterm_to_variable(r)); } } @@ -830,14 +865,15 @@ impl Allocator for DebrayAllocator { if record.running_count < record.num_occurrences { record.running_count += 1; } else { - self.free_var(term_loc.chunk_num(), var_num); + self.free_var(context.chunk_num(), var_num); } self.in_use.insert(o); + r } fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType { - match self.get_binding(var_num) { + match self.get_var_binding(var_num) { RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)), RegType::Temp(0) => { let t = self.alloc_reg_to_non_var(); @@ -861,6 +897,8 @@ impl Allocator for DebrayAllocator { fn reset(&mut self) { self.perm_lb = 1; self.shallow_temp_mappings.clear(); + self.non_var_registers.clear(); + self.non_var_register_heap_locs.clear(); self.in_use.clear(); self.temp_free_list.clear(); } @@ -868,6 +906,8 @@ impl Allocator for DebrayAllocator { fn reset_contents(&mut self) { self.in_use.clear(); self.shallow_temp_mappings.clear(); + self.non_var_registers.clear(); + self.non_var_register_heap_locs.clear(); self.temp_free_list.clear(); } @@ -875,24 +915,44 @@ impl Allocator for DebrayAllocator { self.arg_c += 1; } - fn reset_at_head(&mut self, args: &[Term]) { - self.reset_arg(args.len()); - self.arity = args.len(); + fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize) { + read_heap_cell!(term.deref_loc(head_loc), + (HeapCellValueTag::Str, s) => { + let arity = cell_as_atom_cell!(term.heap[s]).get_arity(); - for (idx, arg) in args.iter().enumerate() { - if let Term::Var(_, ref var) = arg { - let var_num = var.to_var_num().unwrap(); - let r = self.get_binding(var_num); + self.reset_arg(arity); + self.arity = arity; - 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); + for (idx, arg) in term.heap[s+1 .. s+arity+1].iter().cloned().enumerate() { + if arg.is_var() { + let var = heap_bound_store( + &term.heap, + heap_bound_deref(&term.heap, arg), + ); + + if !var.is_var() { + 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); + } + } } } - } + _ => { + self.reset_arg(0); + } + ); } fn reset_arg(&mut self, arity: usize) { diff --git a/src/forms.rs b/src/forms.rs index 148d567f..4dee7439 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -17,7 +17,6 @@ use fxhash::FxBuildHasher; use indexmap::{IndexMap, IndexSet}; use ordered_float::OrderedFloat; -use std::cell::Cell; use std::collections::VecDeque; use std::convert::TryFrom; use std::fmt; @@ -67,15 +66,6 @@ pub enum Level { Shallow, } -impl Level { - pub(crate) fn child_level(self) -> Level { - match self { - Level::Root => Level::Shallow, - _ => Level::Deep, - } - } -} - #[derive(Debug, Clone, Copy)] pub enum CallPolicy { Default, @@ -89,19 +79,6 @@ pub enum ChunkType { Last, } -#[derive(Debug)] -pub enum RootIterationPolicy { - Iterated, - NotIterated, -} - -impl RootIterationPolicy { - #[inline(always)] - pub fn iterable(&self) -> bool { - matches!(self, RootIterationPolicy::Iterated) - } -} - impl ChunkType { #[inline(always)] pub fn to_gen_context(self, chunk_num: usize) -> GenContext { @@ -182,35 +159,40 @@ impl ChunkedTermVec { } } +#[derive(Debug)] +pub struct QueryClause { + pub ct: ClauseType, + pub arity: usize, + pub term: HeapCellValue, + pub code_indices: IndexMap, + pub call_policy: CallPolicy, +} + +impl QueryClause { + pub fn term_loc(&self) -> usize { + self.term.get_value() as usize + } +} + #[derive(Debug)] pub enum QueryTerm { - // register, clause type, subterms, clause call policy. - Clause(Cell, ClauseType, Vec, CallPolicy), + Clause(QueryClause), Fail, - LocalCut { var_num: usize, cut_prev: bool }, // var_num - GlobalCut(usize), // var_num + Succeed, + LocalCut { var_num: usize, cut_prev: bool }, + GlobalCut(usize), // var_num GetCutPoint { var_num: usize, prev_b: bool }, GetLevel(usize), // var_num } -impl QueryTerm { - pub(crate) fn arity(&self) -> usize { - match self { - QueryTerm::Clause(_, _, subterms, ..) => subterms.len(), - &QueryTerm::GetLevel(_) | &QueryTerm::GetCutPoint { .. } => 1, - _ => 0, - } - } -} - #[derive(Debug)] pub struct Fact { - pub(crate) head: Term, + pub(crate) term: FocusedHeap, } #[derive(Debug)] pub struct Rule { - pub(crate) head: (Atom, Vec), + pub(crate) term: FocusedHeap, pub(crate) clauses: ChunkedTermVec, } @@ -253,6 +235,53 @@ impl ClauseInfo for PredicateKey { } } +fn clause_name(heap: &[HeapCellValue], term_loc: usize) -> Option { + let name = term_name(heap, term_loc); + + if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) { + term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| term_name(heap, arg_loc)) + } else { + name + } +} + +fn clause_arity(heap: &[HeapCellValue], term_loc: usize) -> usize { + let name = term_name(heap, term_loc); + + if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) { + term_nth_arg(heap, term_loc, 1) + .map(|arg_loc| term_arity(heap, arg_loc)) + .unwrap_or(0) + } else { + term_arity(heap, term_loc) + } +} + +impl ClauseInfo for FocusedHeap { + #[inline] + fn name(&self) -> Option { + clause_name(&self.heap, self.focus) + } + + #[inline] + fn arity(&self) -> usize { + clause_arity(&self.heap, self.focus) + } +} + +impl<'a> ClauseInfo for FocusedHeapRefMut<'a> { + #[inline] + fn name(&self) -> Option { + clause_name(self.heap, self.focus) + } + + #[inline] + fn arity(&self) -> usize { + clause_arity(self.heap, self.focus) + } +} + +/* impl ClauseInfo for Term { fn name(&self) -> Option { match self { @@ -287,29 +316,30 @@ impl ClauseInfo for Term { } } } +*/ impl ClauseInfo for Rule { fn name(&self) -> Option { - Some(self.head.0) + self.term.name(self.term.focus) } fn arity(&self) -> usize { - self.head.1.len() + self.term.arity(self.term.focus) } } impl ClauseInfo for PredicateClause { fn name(&self) -> Option { match self { - PredicateClause::Fact(ref term, ..) => term.head.name(), - PredicateClause::Rule(ref rule, ..) => rule.name(), + PredicateClause::Fact(ref fact, ..) => fact.term.name(fact.term.focus), + PredicateClause::Rule(ref rule, ..) => rule.term.name(rule.term.focus), } } fn arity(&self) -> usize { match self { - PredicateClause::Fact(ref term, ..) => term.head.arity(), - PredicateClause::Rule(ref rule, ..) => rule.arity(), + PredicateClause::Fact(ref fact, ..) => fact.term.arity(fact.term.focus), + PredicateClause::Rule(ref rule, ..) => rule.term.arity(rule.term.focus), } } } @@ -321,19 +351,31 @@ pub enum PredicateClause { } impl PredicateClause { - pub(crate) fn args(&self) -> Option<&[Term]> { - match self { - PredicateClause::Fact(term, ..) => match &term.head { - Term::Clause(_, _, args) => Some(args), - _ => None, - }, - PredicateClause::Rule(rule, ..) => { - if rule.head.1.is_empty() { - None - } else { - Some(&rule.head.1) - } + pub(crate) fn args(&self) -> Option<&[HeapCellValue]> { + let (term, focus) = match self { + PredicateClause::Fact(Fact { term }, _) => (term, term.focus), + PredicateClause::Rule(Rule { term, .. }, _) => { + let focus = term.nth_arg(term.focus, 1).unwrap(); + (term, focus) + } + }; + + let arity = term.arity(focus); + + read_heap_cell!(term.deref_loc(focus), + (HeapCellValueTag::Str, s) => { + Some(&term.heap[s+1 .. s+arity+1]) + } + _ => { + None } + ) + } + + pub(crate) fn heap(&self) -> &[HeapCellValue] { + match self { + PredicateClause::Fact(ref fact, ..) => &fact.term.heap, + PredicateClause::Rule(ref rule, ..) => &rule.term.heap, } } } diff --git a/src/heap_iter.rs b/src/heap_iter.rs index 61fde0eb..5b621836 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -34,7 +34,7 @@ pub struct EagerStackfulPreOrderHeapIter<'a> { start_value: HeapCellValue, iter_stack: Vec, mark_phase: bool, - heap: &'a mut Heap, + pub heap: &'a mut Heap, } impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> { @@ -249,7 +249,7 @@ impl ListElisionPolicy for NonListElider { #[derive(Debug)] pub struct StackfulPreOrderHeapIter<'a, ElideLists> { - pub heap: &'a mut Vec, + pub heap: &'a mut [HeapCellValue], pub machine_stack: &'a mut Stack, stack: Vec, h: IterStackLoc, @@ -265,11 +265,13 @@ impl<'a, ElideLists> Drop for StackfulPreOrderHeapIter<'a, ElideLists> { cell.set_mark_bit(false); } - self.heap.pop(); + // self.heap.pop(); } } -pub trait FocusedHeapIter: Iterator { +pub trait FocusedHeapIter: + Deref + Iterator +{ fn focus(&self) -> IterStackLoc; } @@ -282,6 +284,14 @@ impl<'a, ElideLists: ListElisionPolicy> FocusedHeapIter } } +impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> { + type Target = [HeapCellValue]; + + fn deref(&self) -> &Self::Target { + &self.heap + } +} + impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> { #[inline] pub fn read_cell_mut(&mut self, loc: IterStackLoc) -> &mut HeapCellValue { @@ -358,9 +368,9 @@ impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> { impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> { #[inline] - fn new(heap: &'a mut Vec, stack: &'a mut Stack, cell: HeapCellValue) -> Self { - let h = IterStackLoc::iterable_loc(heap.len(), HeapOrStackTag::Heap); - heap.push(cell); + fn new(heap: &'a mut [HeapCellValue], stack: &'a mut Stack, root_loc: usize) -> Self { + let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap); + // heap.push(cell); Self { heap, @@ -501,6 +511,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> } } + impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a, ElideLists> { type Item = HeapCellValue; @@ -524,9 +535,9 @@ pub(crate) fn cycle_detecting_stackless_preorder_iter( pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>( heap: &'a mut Vec, stack: &'a mut Stack, - cell: HeapCellValue, + root_loc: usize, ) -> StackfulPreOrderHeapIter<'a, ElideLists> { - StackfulPreOrderHeapIter::new(heap, stack, cell) + StackfulPreOrderHeapIter::new(heap, stack, root_loc) } #[derive(Debug)] @@ -538,7 +549,7 @@ pub(crate) struct PostOrderIterator { } impl Deref for PostOrderIterator { - type Target = Iter; + type Target = [HeapCellValue]; fn deref(&self) -> &Self::Target { &self.base_iter @@ -610,6 +621,7 @@ impl FocusedHeapIter for PostOrderIterator { } } +/* impl PostOrderIterator { /* return true if the term at heap offset idx_loc is a * direct/inlined subterm of a structure at the focus of @@ -631,6 +643,7 @@ impl PostOrderIterator { false } } +*/ pub(crate) type LeftistPostOrderHeapIter<'a, ElideLists> = PostOrderIterator>; @@ -657,9 +670,9 @@ impl<'a, ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'a, ElideLists> pub(crate) fn stackful_post_order_iter<'a, ElideLists: ListElisionPolicy>( heap: &'a mut Heap, stack: &'a mut Stack, - cell: HeapCellValue, + root_loc: usize, ) -> LeftistPostOrderHeapIter<'a, ElideLists> { - PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, stack, cell)) + PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, stack, root_loc)) } #[cfg(test)] @@ -1771,11 +1784,13 @@ mod tests { .heap .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + wam.machine_st.heap.push(str_loc_as_cell!(0)); + { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - str_loc_as_cell!(0), + 3, ); assert_eq!( @@ -1810,7 +1825,7 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - str_loc_as_cell!(0), + 4, ); assert_eq!( @@ -1842,7 +1857,7 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); let mut var = heap_loc_as_cell!(0); @@ -1869,7 +1884,7 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 1, ); assert_eq!( @@ -1893,7 +1908,7 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); assert_eq!( @@ -1929,7 +1944,7 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); // the cycle will be iterated twice before being detected. @@ -1951,7 +1966,15 @@ mod tests { ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(0) + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) ); assert_eq!(iter.next(), None); @@ -1961,7 +1984,7 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); // cut the iteration short to check that all cells are @@ -2000,7 +2023,7 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); @@ -2025,7 +2048,7 @@ mod tests { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); @@ -2048,11 +2071,14 @@ mod tests { .heap .push(fixnum_as_cell!(Fixnum::build_with(0i64))); + let h = wam.machine_st.heap.len(); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - pstr_loc_as_cell!(0), + h, ); let pstr_offset_cell = pstr_offset_as_cell!(0); @@ -2078,16 +2104,20 @@ mod tests { } */ + wam.machine_st.heap.pop(); wam.machine_st.heap.pop(); wam.machine_st .heap .push(fixnum_as_cell!(Fixnum::build_with(1i64))); + let h = wam.machine_st.heap.len(); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - pstr_loc_as_cell!(0), + h, ); let pstr_offset_cell = pstr_offset_as_cell!(0); @@ -2127,11 +2157,14 @@ mod tests { wam.machine_st.heap.extend(functor); + let h = wam.machine_st.heap.len(); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + h, ); assert_eq!( @@ -2194,7 +2227,7 @@ mod tests { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + h, ); assert_eq!( @@ -2263,7 +2296,7 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); let mut cyclic_link = list_loc_as_cell!(1); @@ -2292,12 +2325,13 @@ mod tests { wam.machine_st.heap.push(pstr_as_cell!(atom!("a string"))); wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 2, ); assert_eq!( @@ -2325,11 +2359,14 @@ mod tests { wam.machine_st.heap.push(str_loc_as_cell!(4)); wam.machine_st.heap.push(empty_list_as_cell!()); + let h = wam.machine_st.heap.len(); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + h, ); assert_eq!( @@ -2359,6 +2396,8 @@ mod tests { let a_atom = atom!("a"); let b_atom = atom!("b"); + wam.machine_st.heap.push(str_loc_as_cell!(1)); + wam.machine_st .heap .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); @@ -2367,7 +2406,7 @@ mod tests { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - str_loc_as_cell!(0), + 0, ); assert_eq!( @@ -2388,13 +2427,14 @@ mod tests { wam.machine_st.heap.clear(); + wam.machine_st.heap.push(str_loc_as_cell!(1)); wam.machine_st.heap.extend(functor!( f_atom, [ atom(a_atom), atom(b_atom), atom(a_atom), - cell(str_loc_as_cell!(0)) + cell(str_loc_as_cell!(1)) ] )); @@ -2403,7 +2443,7 @@ mod tests { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - str_loc_as_cell!(0), + 0, ); assert_eq!( @@ -2419,7 +2459,7 @@ mod tests { atom_as_cell!(a_atom) ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), @@ -2437,7 +2477,7 @@ mod tests { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); let mut var = heap_loc_as_cell!(0); @@ -2464,7 +2504,7 @@ mod tests { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 1, ); assert_eq!( @@ -2484,11 +2524,14 @@ mod tests { wam.machine_st.heap.push(atom_as_cell!(b_atom)); wam.machine_st.heap.push(empty_list_as_cell!()); + let h = wam.machine_st.heap.len(); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + h, ); assert_eq!( @@ -2515,16 +2558,18 @@ mod tests { assert_eq!(iter.next(), None); } + wam.machine_st.heap.pop(); wam.machine_st.heap.pop(); // now make the list cyclic. + let h = wam.machine_st.heap.len(); wam.machine_st.heap.push(heap_loc_as_cell!(0)); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + h, ); // the cycle will be iterated twice before being detected. @@ -2556,7 +2601,7 @@ mod tests { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); // cut the iteration short to check that all cells are @@ -2591,11 +2636,15 @@ mod tests { put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + + let h = wam.machine_st.heap.len() - 1; + { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - pstr_loc_as_cell!(0), + h, ); assert_eq!( @@ -2608,6 +2657,7 @@ mod tests { assert_eq!(iter.next(), None); } + wam.machine_st.heap.pop(); wam.machine_st.heap.pop(); wam.machine_st.heap.push(pstr_loc_as_cell!(2)); @@ -2615,11 +2665,15 @@ mod tests { put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + + let h = wam.machine_st.heap.len() - 1; + { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - pstr_loc_as_cell!(0), + h, ); assert_eq!( @@ -2632,6 +2686,7 @@ mod tests { assert_eq!(iter.next(), None); } + wam.machine_st.heap.pop(); wam.machine_st.heap.pop(); wam.machine_st .heap @@ -2642,11 +2697,15 @@ mod tests { .heap .push(fixnum_as_cell!(Fixnum::build_with(0i64))); + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + + let h = wam.machine_st.heap.len() - 1; + { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - pstr_loc_as_cell!(0), + h, ); assert_eq!( @@ -2664,16 +2723,21 @@ mod tests { assert_eq!(iter.next(), None); } + wam.machine_st.heap.pop(); wam.machine_st.heap.pop(); wam.machine_st .heap .push(fixnum_as_cell!(Fixnum::build_with(1i64))); + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + + let h = wam.machine_st.heap.len() - 1; + { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - pstr_loc_as_cell!(0), + h, ); assert_eq!( @@ -2707,7 +2771,7 @@ mod tests { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); assert_eq!( @@ -2771,7 +2835,7 @@ mod tests { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - heap_loc_as_cell!(0), + 0, ); assert_eq!( diff --git a/src/heap_print.rs b/src/heap_print.rs index f6f0c8f3..26f48cb3 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -532,11 +532,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { stack: &'a mut Stack, op_dir: &'a OpDir, output: Outputter, - cell: HeapCellValue, + root_loc: usize, ) -> Self { HCPrinter { outputter: output, - iter: stackful_preorder_iter(heap, stack, cell), + iter: stackful_preorder_iter(heap, stack, root_loc), atom_tbl, op_dir, state_stack: vec![], @@ -1841,6 +1841,8 @@ mod tests { .heap .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + wam.machine_st.heap.push(str_loc_as_cell!(0)); + { let printer = HCPrinter::new( &mut wam.machine_st.heap, @@ -1848,7 +1850,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(0), + 0, ); let output = printer.print(); @@ -1870,6 +1872,9 @@ mod tests { ] )); + let h = wam.machine_st.heap.len(); + wam.machine_st.heap.push(str_loc_as_cell!(0)); + { let printer = HCPrinter::new( &mut wam.machine_st.heap, @@ -1877,7 +1882,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(0), + h, ); let output = printer.print(); @@ -1901,7 +1906,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(0), + 0, ); let output = printer.print(); @@ -1914,7 +1919,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(0), + 0, ); printer @@ -1947,7 +1952,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(0), + 0, ); let output = printer.print(); @@ -1966,7 +1971,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(0), + 0, ); let output = printer.print(); @@ -1983,7 +1988,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(0), + 0, ); printer @@ -2015,7 +2020,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(0), + 0, ); printer.max_depth = 5; @@ -2031,6 +2036,10 @@ mod tests { put_partial_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl); + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + + let h = wam.machine_st.heap.len() - 1; + { let printer = HCPrinter::new( &mut wam.machine_st.heap, @@ -2038,7 +2047,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - pstr_loc_as_cell!(0), + h, ); let output = printer.print(); @@ -2048,6 +2057,7 @@ mod tests { all_cells_unmarked(&wam.machine_st.heap); + wam.machine_st.heap.pop(); wam.machine_st.heap.pop(); wam.machine_st.heap.push(list_loc_as_cell!(2)); @@ -2066,7 +2076,7 @@ mod tests { &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(0), + 0, ); printer.double_quotes = true; diff --git a/src/indexing.rs b/src/indexing.rs index f4cb22ae..a199e625 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1,8 +1,8 @@ use crate::atom_table::*; -use crate::parser::ast::*; - use crate::forms::*; use crate::instructions::*; +use crate::parser::ast::*; +use crate::types::*; use fxhash::FxBuildHasher; use indexmap::IndexMap; @@ -1491,34 +1491,60 @@ impl CodeOffsets { pub(crate) fn index_term( &mut self, - optimal_arg: &Term, + heap: &[HeapCellValue], + optimal_arg: HeapCellValue, index: usize, clause_index_info: &mut ClauseIndexInfo, atom_tbl: &AtomTable, ) { - match optimal_arg { - &Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => { - clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); - self.index_list(index); + read_heap_cell!(optimal_arg, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); + + if (name, arity) == (atom!("."), 2) { + clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); + self.index_list(index); + } else { + clause_index_info.opt_arg_index_key = + OptArgIndexKey::Structure(self.optimal_index, 0, name, arity); + + self.index_structure(name, arity, index); + } + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + let overlapping_constants = self.index_constant(atom_tbl, Literal::Atom(name), index); + + clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( + self.optimal_index, + 0, + Literal::Atom(name), + overlapping_constants, + ); } - &Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => { + (HeapCellValueTag::Lis + | HeapCellValueTag::CStr + | HeapCellValueTag::PStrLoc) => { clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); self.index_list(index); } - &Term::Clause(_, name, ref terms) => { - clause_index_info.opt_arg_index_key = - OptArgIndexKey::Structure(self.optimal_index, 0, name, terms.len()); - - self.index_structure(name, terms.len(), index); - } - &Term::Literal(_, constant) => { - let overlapping_constants = self.index_constant(atom_tbl, constant, index); - - clause_index_info.opt_arg_index_key = - OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants); + _ => { + match Literal::try_from(optimal_arg) { + Ok(lit) => { + let overlapping_constants = self.index_constant(atom_tbl, lit, index); + + clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( + self.optimal_index, + 0, + lit, + overlapping_constants, + ); + } + _ => {} + } } - _ => {} - } + ); } pub(crate) fn no_indices(&mut self) -> bool { diff --git a/src/iterators.rs b/src/iterators.rs index b3140ee9..030daf81 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -1,328 +1,224 @@ -use crate::atom_table::*; +use crate::atom_table::AtomCell; use crate::forms::*; -use crate::instructions::*; -use crate::parser::ast::*; +use crate::heap_iter::*; +use crate::machine::heap::*; +use crate::machine::stack::*; +use crate::types::*; + +use bit_set::*; +use fxhash::FxBuildHasher; +use indexmap::IndexMap; -use std::cell::Cell; use std::collections::VecDeque; use std::iter::*; +use std::ops::Deref; use std::vec::Vec; -#[allow(clippy::borrowed_box)] -#[derive(Debug, Clone)] -pub(crate) enum TermRef<'a> { - AnonVar(Level), - Cons(Level, &'a Cell, &'a Term, &'a Term), - Literal(Level, &'a Cell, &'a Literal), - Clause(Level, &'a Cell, Atom, &'a Vec), - PartialString(Level, &'a Cell, &'a String, &'a Box), - CompleteString(Level, &'a Cell, Atom), - Var(Level, &'a Cell, VarPtr), -} - -/* -impl<'a> TermRef<'a> { - pub(crate) fn level(&self) -> Level { - match self { - TermRef::AnonVar(lvl) | - TermRef::Cons(lvl, ..) | - TermRef::Literal(lvl, ..) | - TermRef::Var(lvl, ..) | - TermRef::Clause(lvl, ..) | - TermRef::CompleteString(lvl, ..) | - TermRef::PartialString(lvl, ..) => *lvl, - } - } +pub(crate) trait TermIterator: + Deref + Iterator +{ + fn focus(&self) -> IterStackLoc; + fn level(&mut self) -> Level; } -*/ -#[allow(clippy::borrowed_box)] #[derive(Debug)] -pub(crate) enum TermIterState<'a> { - AnonVar(Level), - Clause(Level, usize, &'a Cell, Atom, &'a Vec), - Literal(Level, &'a Cell, &'a Literal), - InitialCons(Level, &'a Cell, &'a Term, &'a Term), - FinalCons(Level, &'a Cell, &'a Term, &'a Term), - InitialPartialString(Level, &'a Cell, &'a String, &'a Box), - FinalPartialString(Level, &'a Cell, &'a String, &'a Box), - CompleteString(Level, &'a Cell, Atom), - Var(Level, &'a Cell, VarPtr), +pub(crate) struct TargetIterator { + shallow_terms: IndexMap, FxBuildHasher>, + root_terms: BitSet, + iter: I, + arg_c: usize, } -impl<'a> TermIterState<'a> { - pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> { - match term { - Term::AnonVar => TermIterState::AnonVar(lvl), - Term::Clause(cell, name, subterms) => { - TermIterState::Clause(lvl, 0, cell, *name, subterms) - } - Term::Cons(cell, head, tail) => { - TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()) +fn record_path( + heap: &[HeapCellValue], + root_terms: &mut BitSet, + mut root_loc: usize, +) -> usize { + loop { + let cell = heap[root_loc]; + root_terms.insert(root_loc); + + read_heap_cell!(cell, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h == root_loc { + break; + } else { + root_loc = h; + } } - Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant), - Term::PartialString(cell, string_buf, tail) => { - TermIterState::InitialPartialString(lvl, cell, string_buf, tail) + (HeapCellValueTag::Lis) => { + root_terms.insert(root_loc); + break; + } + _ => { + if cell.is_ref() { + root_terms.insert(cell.get_value() as usize); + } + + break; } - Term::CompleteString(cell, atom) => TermIterState::CompleteString(lvl, cell, *atom), - Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()), - } + ); } + + root_loc } -#[derive(Debug)] -pub(crate) struct QueryIterator<'a> { - state_stack: Vec>, +fn find_root_terms(heap: &[HeapCellValue], root_loc: usize) -> (usize, BitSet) { + let mut root_terms = BitSet::::default(); + let root_loc = record_path(heap, &mut root_terms, root_loc); + (root_loc, root_terms) } -impl<'a> QueryIterator<'a> { - fn push_subterm(&mut self, lvl: Level, term: &'a Term) { - self.state_stack - .push(TermIterState::subterm_to_state(lvl, term)); - } +fn find_shallow_terms( + heap: &[HeapCellValue], + root_loc: usize, +) -> IndexMap, FxBuildHasher> { + let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default()); - /* - fn from_rule_head_clause(terms: &'a Vec) -> Self { - let state_stack = terms - .iter() - .rev() - .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt)) - .collect(); + let (h, arity) = read_heap_cell!(heap[root_loc], + (HeapCellValueTag::Str, s) => { + (s+1, cell_as_atom_cell!(heap[s]).get_arity()) + } + (HeapCellValueTag::Lis, l) => { + (l, 2) + } + (HeapCellValueTag::Atom, (_name, arity)) => { + (root_loc + 1, arity) + } + _ => { + (root_loc, 0) + } + ); - QueryIterator { state_stack } + for idx in 0..arity { + let mut shallow_terms = BitSet::default(); + record_path(heap, &mut shallow_terms, h + idx); + shallow_terms_map.insert(idx + 1, shallow_terms); } - */ - - fn from_term(term: &'a Term) -> Self { - let state = match term { - Term::AnonVar - | Term::Cons(..) - | Term::Literal(..) - | Term::PartialString(..) - | Term::CompleteString(..) => { - return QueryIterator { - state_stack: vec![], - } - } - Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms), - Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()), - }; - QueryIterator { - state_stack: vec![state], + shallow_terms_map +} + +impl TargetIterator { + fn new(iter: I, root_loc: usize, arg_c: usize) -> Self { + let (derefed_root_loc, root_terms) = find_root_terms(&iter, root_loc); + let shallow_terms = find_shallow_terms(&iter, derefed_root_loc); + + Self { + shallow_terms, + root_terms, + iter, + arg_c, } } - fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) { - match term { - QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => { - self.state_stack - .push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms)); - } - QueryTerm::Clause(ref cell, ref ct, ref terms, _) => { - self.state_stack - .push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms)); + fn current_level(&self, arg_c_inc: usize) -> Level { + let current_focus = self.iter.focus().value() as usize; + + if self.root_terms.contains(current_focus) { + return Level::Root; + } + + if let Some(shallow_terms) = self.shallow_terms.get(&(self.arg_c + arg_c_inc)) { + if shallow_terms.contains(current_focus) { + return Level::Shallow; } - _ => {} } - } - pub fn new(term: &'a QueryTerm) -> Self { - let mut iter = QueryIterator { - state_stack: vec![], - }; - iter.extend_state(Level::Root, term); - iter + Level::Deep } } -impl<'a> Iterator for QueryIterator<'a> { - type Item = TermRef<'a>; +impl<'a, const SKIP_ROOT: bool> TermIterator for FactIterator<'a, SKIP_ROOT> { + fn focus(&self) -> IterStackLoc { + self.iter.focus() + } - fn next(&mut self) -> Option { - while let Some(iter_state) = self.state_stack.pop() { - match iter_state { - TermIterState::AnonVar(lvl) => { - return Some(TermRef::AnonVar(lvl)); - } - TermIterState::Clause(lvl, child_num, cell, name, child_terms) => { - if child_num == child_terms.len() { - match name { - atom!("$call") if lvl == Level::Root => { - self.push_subterm(Level::Shallow, &child_terms[0]); - } - _ => { - return match lvl { - Level::Root => None, - lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)), - } - } - }; - } else { - self.state_stack.push(TermIterState::Clause( - lvl, - child_num + 1, - cell, - name, - child_terms, - )); - - self.push_subterm(lvl.child_level(), &child_terms[child_num]); - } - } - TermIterState::InitialCons(lvl, cell, head, tail) => { - self.state_stack - .push(TermIterState::FinalCons(lvl, cell, head, tail)); + fn level(&mut self) -> Level { + let lvl = self.current_level(1); - self.push_subterm(lvl.child_level(), tail); - self.push_subterm(lvl.child_level(), head); - } - TermIterState::InitialPartialString(lvl, cell, string, tail) => { - self.state_stack - .push(TermIterState::FinalPartialString(lvl, cell, string, tail)); - self.push_subterm(lvl.child_level(), tail); - } - TermIterState::FinalPartialString(lvl, cell, atom, tail) => { - return Some(TermRef::PartialString(lvl, cell, atom, tail)); - } - TermIterState::CompleteString(lvl, cell, atom) => { - return Some(TermRef::CompleteString(lvl, cell, atom)); - } - TermIterState::FinalCons(lvl, cell, head, tail) => { - return Some(TermRef::Cons(lvl, cell, head, tail)); - } - TermIterState::Literal(lvl, cell, constant) => { - return Some(TermRef::Literal(lvl, cell, constant)); - } - TermIterState::Var(lvl, cell, var_ptr) => { - return Some(TermRef::Var(lvl, cell, var_ptr)); - } - }; + if let Level::Shallow = lvl { + self.arg_c += 1; } - None + lvl } } -#[derive(Debug)] -pub(crate) struct FactIterator<'a> { - state_queue: VecDeque>, - iterable_root: RootIterationPolicy, -} - -impl<'a> FactIterator<'a> { - fn push_subterm(&mut self, lvl: Level, term: &'a Term) { - self.state_queue - .push_back(TermIterState::subterm_to_state(lvl, term)); +impl<'a, const SKIP_ROOT: bool> TermIterator for QueryIterator<'a, SKIP_ROOT> { + fn focus(&self) -> IterStackLoc { + self.iter.focus() } - pub(crate) fn from_rule_head_clause(terms: &'a [Term]) -> Self { - let state_queue = terms - .iter() - .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt)) - .collect(); + fn level(&mut self) -> Level { + let lvl = self.current_level(0); - FactIterator { - state_queue, - iterable_root: RootIterationPolicy::NotIterated, + if let Level::Shallow = lvl { + self.arg_c += 1; } - } - fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self { - let states = match term { - Term::AnonVar => { - vec![TermIterState::AnonVar(Level::Root)] - } - Term::Clause(cell, name, terms) => { - vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)] - } - Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons( - Level::Root, - cell, - head.as_ref(), - tail.as_ref(), - )], - Term::PartialString(cell, string_buf, tail) => { - vec![TermIterState::InitialPartialString( - Level::Root, - cell, - string_buf, - tail, - )] - } - Term::CompleteString(cell, atom) => { - vec![TermIterState::CompleteString(Level::Root, cell, *atom)] - } - Term::Literal(cell, constant) => { - vec![TermIterState::Literal(Level::Root, cell, constant)] - } - Term::Var(cell, var_ptr) => { - vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())] - } - }; - - FactIterator { - state_queue: VecDeque::from(states), - iterable_root, - } + lvl } } -impl<'a> Iterator for FactIterator<'a> { - type Item = TermRef<'a>; +impl Iterator for TargetIterator { + type Item = HeapCellValue; fn next(&mut self) -> Option { - while let Some(state) = self.state_queue.pop_front() { - match state { - TermIterState::AnonVar(lvl) => { - return Some(TermRef::AnonVar(lvl)); - } - TermIterState::Clause(lvl, _, cell, name, child_terms) => { - for child_term in child_terms { - self.push_subterm(lvl.child_level(), child_term); - } + loop { + let next_term = self.iter.next(); - match lvl { - Level::Root if !self.iterable_root.iterable() => continue, - _ => return Some(TermRef::Clause(lvl, cell, name, child_terms)), - }; - } - TermIterState::InitialCons(lvl, cell, head, tail) => { - self.push_subterm(Level::Deep, head); - self.push_subterm(Level::Deep, tail); + if next_term.is_none() { + return None; + } - return Some(TermRef::Cons(lvl, cell, head, tail)); - } - TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => { - self.push_subterm(Level::Deep, tail); - return Some(TermRef::PartialString(lvl, cell, string_buf, tail)); - } - TermIterState::CompleteString(lvl, cell, atom) => { - return Some(TermRef::CompleteString(lvl, cell, atom)); - } - TermIterState::Literal(lvl, cell, constant) => { - return Some(TermRef::Literal(lvl, cell, constant)) - } - TermIterState::Var(lvl, cell, var_ptr) => { - return Some(TermRef::Var(lvl, cell, var_ptr)); - } - _ => {} + let focus = self.iter.focus().value() as usize; + + if SKIP_ROOT && self.root_terms.contains(focus) { + continue; + } else { + return next_term; } } + } +} - None +impl Deref for TargetIterator { + type Target = [HeapCellValue]; + + fn deref(&self) -> &Self::Target { + self.iter.deref() } } -pub(crate) fn post_order_iter(term: &'_ Term) -> QueryIterator { - QueryIterator::from_term(term) +impl FocusedHeapIter for TargetIterator { + fn focus(&self) -> IterStackLoc { + self.iter.focus() + } } -pub(crate) fn breadth_first_iter( - term: &'_ Term, - iterable_root: RootIterationPolicy, -) -> FactIterator { - FactIterator::new(term, iterable_root) +pub(crate) type FactIterator<'a, const SKIP_ROOT: bool> = + TargetIterator, SKIP_ROOT>; + +pub(crate) fn fact_iterator<'a, const SKIP_ROOT: bool>( + heap: &'a mut Heap, + stack: &'a mut Stack, + root_loc: usize, +) -> FactIterator<'a, SKIP_ROOT> { + // let cell = heap[root_loc]; + TargetIterator::new(stackful_preorder_iter(heap, stack, root_loc), root_loc, 0) +} + +pub(crate) type QueryIterator<'a, const SKIP_ROOT: bool> = + TargetIterator>, SKIP_ROOT>; + +pub(crate) fn query_iterator<'a, const SKIP_ROOT: bool>( + heap: &'a mut Heap, + stack: &'a mut Stack, + root_loc: usize, +) -> QueryIterator<'a, SKIP_ROOT> { + // let cell = heap[root_loc]; + TargetIterator::new(stackful_post_order_iter(heap, stack, root_loc), root_loc, 1) } #[derive(Debug, Copy, Clone)] diff --git a/src/lib/atts.pl b/src/lib/atts.pl index f251b57d..6d18b447 100644 --- a/src/lib/atts.pl +++ b/src/lib/atts.pl @@ -59,7 +59,7 @@ get_attrs_var_check(Module) --> !, '$get_attr_list'(Var, Ls), nonvar(Ls), - atts:'$copy_attr_list'(Ls, Module, Attr))]. + atts:'$copy_attr_list'(Ls, Module, Attr))]. put_attrs(Name/Arity, Module) --> put_attr(Name, Arity, Module), diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index bea783f7..e7aebf3f 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1175,14 +1175,8 @@ clause(H, B) :- % Asserts (inserts) a new clause (rule or fact) into the current module. % The clause will be inserted at the beginning of the module. asserta(Clause0) :- - loader:strip_module(Clause0, Module, Clause), - asserta_(Module, Clause). - -asserta_(Module, (Head :- Body)) :- - !, - '$asserta'(Module, Head, Body). -asserta_(Module, Fact) :- - '$asserta'(Module, Fact, true). + loader:strip_subst_module(Clause0, user, Module, Clause), + '$asserta'(Module, Clause). :- meta_predicate assertz(:). @@ -1191,14 +1185,8 @@ asserta_(Module, Fact) :- % Asserts (inserts) a new clause (rule or fact) into the current module. % The clase will be inserted at the end of the module. assertz(Clause0) :- - loader:strip_module(Clause0, Module, Clause), - assertz_(Module, Clause). - -assertz_(Module, (Head :- Body)) :- - !, - '$assertz'(Module, Head, Body). -assertz_(Module, Fact) :- - '$assertz'(Module, Fact, true). + loader:strip_subst_module(Clause0, user, Module, Clause), + '$assertz'(Module, Clause). :- meta_predicate retract(:). diff --git a/src/lib/si.pl b/src/lib/si.pl index 0e29c190..90cc4d3f 100644 --- a/src/lib/si.pl +++ b/src/lib/si.pl @@ -126,4 +126,3 @@ when_condition_si((A, B)) :- when_condition_si((A ; B)) :- when_condition_si(A), when_condition_si(B). - diff --git a/src/loader.pl b/src/loader.pl index 12341b42..26b6afc8 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -205,6 +205,7 @@ load_loop(Stream, Evacuable) :- read_term(Stream, Term, [singletons(Singletons)]) ; Term = end_of_file ), + % write('Term: '), writeq(Term), nl, ( Term == end_of_file -> close(Stream), '$conclude_load'(Evacuable) @@ -219,6 +220,7 @@ load_loop(Stream, Evacuable) :- compile_term(Term, Evacuable) :- expand_terms_and_goals(Term, Terms), + % write('Terms: '), writeq(Terms),nl, !, ( var(Terms) -> instantiation_error(load/1) diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 43ea34c2..cdd7c515 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1155,8 +1155,17 @@ impl MachineState { value: HeapCellValue, ) -> Result { let stub_gen = || functor_stub(atom!("is"), 2); - let mut iter = - stackful_post_order_iter::(&mut self.heap, &mut self.stack, value); + + let root_loc = if value.is_ref() { + value.get_value() as usize + } else { + let type_error = self.type_error(ValidType::Evaluable, value); + return Err(self.error_form(type_error, stub_gen())); + }; + + let mut iter = stackful_post_order_iter::( + &mut self.heap, &mut self.stack, root_loc, + ); while let Some(value) = iter.next() { if value.get_forwarding_bit() { diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index d84822fe..794c0e76 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -11,8 +11,8 @@ use std::vec::IntoIter; pub(super) type Bindings = Vec<(usize, HeapCellValue)>; #[derive(Debug)] -pub(super) struct AttrVarInitializer { - pub(super) attr_var_queue: Vec, +pub(crate) struct AttrVarInitializer { + pub(crate) attr_var_queue: Vec, pub(super) bindings: Bindings, pub(super) p: usize, pub(super) cp: usize, @@ -131,9 +131,15 @@ impl MachineState { pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec { let mut seen_set = IndexSet::new(); let mut seen_vars = vec![]; + let root_loc = if cell.is_ref() { + cell.get_value() as usize + } else { + return vec![]; + }; - let mut iter = - stackful_preorder_iter::(&mut self.heap, &mut self.stack, cell); + let mut iter = stackful_preorder_iter::( + &mut self.heap, &mut self.stack, root_loc, // cell, + ); while let Some(value) = iter.next() { read_heap_cell!(value, diff --git a/src/machine/compile.rs b/src/machine/compile.rs index e58f3553..4ddf1f33 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -11,7 +11,6 @@ use crate::machine::term_stream::*; use crate::machine::*; use crate::parser::ast::*; -use std::cell::Cell; use std::collections::VecDeque; use std::mem; use std::ops::Range; @@ -1233,14 +1232,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { fn compile_standalone_clause( &mut self, - term: Term, + term: FocusedHeap, settings: CodeGenSettings, ) -> Result { let mut preprocessor = Preprocessor::new(settings); let clause = self.try_term_to_tl(term, &mut preprocessor)?; - // let queue = preprocessor.parse_queue(self)?; - let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings); let clause_code = cg.compile_predicate(vec![clause])?; @@ -1272,7 +1269,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings); - let mut code = cg.compile_predicate(clauses)?; if settings.is_extensible { @@ -1470,7 +1466,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { pub(super) fn incremental_compile_clause( &mut self, key: PredicateKey, - clause: Term, + clause: FocusedHeap, compilation_target: CompilationTarget, non_counted_bt: bool, append_or_prepend: AppendOrPrepend, @@ -2005,16 +2001,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } impl<'a, LS: LoadState<'a>> Loader<'a, LS> { - pub(super) fn compile_clause_clauses>( + pub(super) fn compile_clause_clauses( &mut self, key: PredicateKey, compilation_target: CompilationTarget, - clause_clauses: ClauseIter, + clause_clauses: Vec, append_or_prepend: AppendOrPrepend, ) -> Result<(), SessionError> { - let clause_predicates = clause_clauses - .map(|(head, body)| Term::Clause(Cell::default(), atom!("$clause"), vec![head, body])); - let clause_clause_compilation_target = match compilation_target { CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), _ => compilation_target, @@ -2022,7 +2015,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let mut num_clause_predicates = 0; - for clause_term in clause_predicates { + for clause_term in clause_clauses { self.incremental_compile_clause( (atom!("$clause"), 2), clause_term, @@ -2253,13 +2246,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .clause_clauses .drain(0..std::cmp::min(predicates_len, clause_clauses_len)) .collect(); - let compilation_target = self.payload.predicates.compilation_target; self.compile_clause_clauses( key, compilation_target, - clauses_vec.into_iter(), + clauses_vec, AppendOrPrepend::Append, )?; } @@ -2288,15 +2280,43 @@ impl Machine { pub(crate) fn compile_standalone_clause( &mut self, - term_loc: RegType, - vars: &[Term], + term_reg: RegType, + vars: Vec, ) -> Result<(), SessionError> { - let mut compile = || { + 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 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)); + + for idx in header_loc + 1 .. header_loc + 1 + old_arity { + self.machine_st.heap.push(self.machine_st.heap[idx]); + } + + for var in vars { + self.machine_st.heap.push(var); + } + + let value = if new_arity > 0 { + str_loc_as_cell!(new_header_loc) + } else { + heap_loc_as_cell!(new_header_loc) + }; + + let mut compile = |cell| { + use crate::heap_iter::eager_stackful_preorder_iter; + let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(self, InlineTermStream {}); - let term = loader.read_term_from_heap(term_loc); - let clause = build_rule_body(vars, term); + let mut term = loader.copy_term_from_heap(cell); let settings = CodeGenSettings { global_clock_tick: None, @@ -2304,10 +2324,16 @@ impl Machine { non_counted_bt: true, }; - loader.compile_standalone_clause(clause, settings) + let value = term.heap[term.focus]; + + term.var_locs = var_locs_from_iter( + eager_stackful_preorder_iter(&mut term.heap, value), + ); + + loader.compile_standalone_clause(term, settings) }; - let StandaloneCompileResult { clause_code, .. } = compile()?; + let StandaloneCompileResult { clause_code, .. } = compile(value)?; self.code.extend(clause_code); Ok(()) diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index 651b3db7..801ce078 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -1,18 +1,19 @@ use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; -use crate::iterators::*; +use crate::iterators::fact_iterator; +use crate::machine::Stack; use crate::machine::loader::*; use crate::machine::machine_errors::CompilationError; use crate::machine::preprocessor::*; use crate::parser::ast::*; use crate::parser::dashu::Rational; +use crate::types::*; use crate::variable_records::*; use dashu::Integer; use indexmap::{IndexMap, IndexSet}; -use std::cell::Cell; use std::cmp::Ordering; use std::collections::VecDeque; use std::hash::{Hash, Hasher}; @@ -147,11 +148,21 @@ enum TraversalState { // where it leaves off. BuildFinalDisjunct(usize), Fail, - GetCutPoint { var_num: usize, prev_b: bool }, - Cut { var_num: usize, is_global: bool }, + Succeed, + GetCutPoint { + var_num: usize, + prev_b: bool, + }, + Cut { + var_num: usize, + is_global: bool, + }, CutPrev(usize), ResetCallPolicy(CallPolicy), - Term(Term), + Term { + subterm: HeapCellValue, + term_loc: usize, + }, OverrideGlobalCutVar(usize), ResetGlobalCutVarOverride(Option), RemoveBranchNum, // pop the current_branch_num and from the root set. @@ -183,7 +194,7 @@ impl VarData { fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) { let global_cut_var_num = if let &Some(global_cut_var_num) = &self.global_cut_var_num { match &self.records[global_cut_var_num].allocation { - VarAlloc::Perm(..) => Some(global_cut_var_num), + VarAlloc::Perm { .. } => Some(global_cut_var_num), VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => { Some(global_cut_var_num) } @@ -196,7 +207,7 @@ impl VarData { if let Some(global_cut_var_num) = global_cut_var_num { let term = QueryTerm::GetLevel(global_cut_var_num); self.records[global_cut_var_num].allocation = - VarAlloc::Perm(0, PermVarAllocation::Pending); + VarAlloc::Perm { reg: 0, allocation: PermVarAllocation::Pending }; match build_stack.front_mut() { Some(ChunkedTerms::Branch(_)) => { @@ -213,8 +224,8 @@ impl VarData { } } -pub type ClassifyFactResult = (Term, VarData); -pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData); +pub type ClassifyFactResult = VarData; +pub type ClassifyRuleResult = (ChunkedTermVec, VarData); fn merge_branch_seq(branches: impl Iterator) -> BranchInfo { let mut branch_info = BranchInfo::new(BranchNumber::default()); @@ -255,28 +266,32 @@ impl VariableClassifier { } } - pub fn classify_fact(mut self, term: Term) -> Result { - self.classify_head_variables(&term)?; - Ok(( - term, - self.branch_map.separate_and_classify_variables( - self.var_num, - self.global_cut_var_num, - self.current_chunk_num, - ), + pub fn classify_fact( + mut self, + term: &mut FocusedHeap, + ) -> Result { + let focus = term.focus; + self.classify_head_variables(term, focus)?; + + Ok(self.branch_map.separate_and_classify_variables( + self.var_num, + self.global_cut_var_num, + self.current_chunk_num, )) } pub fn classify_rule<'a, LS: LoadState<'a>>( mut self, loader: &mut Loader<'a, LS>, - head: Term, - body: Term, + term: &mut FocusedHeap, ) -> Result { - self.classify_head_variables(&head)?; + let head_loc = term.nth_arg(term.focus, 1).unwrap(); + let body_loc = term.nth_arg(term.focus, 2).unwrap(); + + self.classify_head_variables(term, head_loc)?; self.root_set.insert(self.current_branch_num.clone()); - let mut query_terms = self.classify_body_variables(loader, body)?; + let mut query_terms = self.classify_body_variables(loader, term, body_loc)?; self.merge_branches(); @@ -288,7 +303,7 @@ impl VariableClassifier { var_data.emit_initial_get_level(&mut query_terms); - Ok((head, query_terms, var_data)) + Ok((query_terms, var_data)) } fn merge_branches(&mut self) { @@ -332,22 +347,39 @@ impl VariableClassifier { } } - fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) { + fn probe_body_term( + &mut self, + arg_c: usize, + arity: usize, + term: &mut FocusedHeap, + term_loc: usize, + ) { let classify_info = ClassifyInfo { arg_c, arity }; + let mut lvl = Level::Shallow; + let mut stack = Stack::uninitialized(); + let mut iter = fact_iterator::( + &mut term.heap, + &mut stack, + term_loc, + ); + // second arg is true to iterate the root, which may be a variable - for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) { - if let TermRef::Var(lvl, _, var_ptr) = term_ref { - // root terms are shallow here (since we're iterating a - // body term) so take the child level. - let lvl = lvl.child_level(); - self.probe_body_var(VarInfo { - var_ptr, - lvl, - classify_info, - chunk_type: self.current_chunk_type, - }); + while let Some(subterm) = iter.next() { + if !subterm.is_var() { + lvl = Level::Deep; + continue; } + + 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, + }); } } @@ -401,56 +433,79 @@ impl VariableClassifier { self.probe_body_var(var_info); } - fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> { - match term { - Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {} - _ => return Err(CompilationError::InvalidRuleHead), - } + fn classify_head_variables( + &mut self, + term: &mut FocusedHeap, + head_loc: usize, + ) -> Result<(), CompilationError> { + let arity = read_heap_cell!(term.deref_loc(head_loc), + (HeapCellValueTag::Str, s) => { + cell_as_atom_cell!(term.heap[s]).get_arity() + } + (HeapCellValueTag::Atom) => { + return Ok(()); + } + _ => { + return Err(CompilationError::InvalidRuleHead); + } + ); - let mut classify_info = ClassifyInfo { - arg_c: 1, - arity: term.arity(), - }; + let mut classify_info = ClassifyInfo { arg_c: 1, arity }; - if let Term::Clause(_, _, terms) = term { - for term in terms.iter() { - for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) { - if let TermRef::Var(lvl, _, var_ptr) = term_ref { - // a body term, so we need the child level here. - let lvl = lvl.child_level(); + if arity > 0 { + let (_term_loc, value) = subterm_index(&term.heap, head_loc); + let str_offset = value.get_value() as usize; - // 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(); + debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str); - let needs_new_branch = branch_info_v.is_empty(); + for idx in str_offset + 1 ..= str_offset + arity { + let mut lvl = Level::Shallow; + let mut stack = Stack::uninitialized(); + let mut iter = fact_iterator::( + &mut term.heap, + &mut stack, + idx, + ); - if needs_new_branch { - branch_info_v.push(BranchInfo::new(self.current_branch_num.clone())); - } + while let Some(subterm) = iter.next() { + if !subterm.is_var() { + lvl = Level::Deep; + continue; + } - let branch_info = branch_info_v.last_mut().unwrap(); - let needs_new_chunk = branch_info.chunks.is_empty(); + let h = subterm.get_value() as usize; + let var_ptr = term.var_locs.read_next_var_ptr_at_key(h).unwrap().clone(); - if needs_new_chunk { - branch_info.chunks.push(ChunkInfo { - chunk_num: self.current_chunk_num, - term_loc: GenContext::Head, - vars: vec![], - }); - } + // the body of the if let here is an inlined + // "probe_head_var". note the difference between it + // and "probe_body_var". + let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default(); + let needs_new_branch = branch_info_v.is_empty(); - let chunk_info = branch_info.chunks.last_mut().unwrap(); - let var_info = VarInfo { - var_ptr, - classify_info, - chunk_type: self.current_chunk_type, - lvl, - }; + if needs_new_branch { + branch_info_v.push(BranchInfo::new(self.current_branch_num.clone())); + } + + let branch_info = branch_info_v.last_mut().unwrap(); + let needs_new_chunk = branch_info.chunks.is_empty(); - chunk_info.vars.push(var_info); + if needs_new_chunk { + branch_info.chunks.push(ChunkInfo { + chunk_num: self.current_chunk_num, + term_loc: GenContext::Head, + vars: vec![], + }); } + + let chunk_info = branch_info.chunks.last_mut().unwrap(); + let var_info = VarInfo { + var_ptr, + classify_info, + chunk_type: self.current_chunk_type, + lvl, + }; + + chunk_info.vars.push(var_info); } classify_info.arg_c += 1; @@ -460,17 +515,40 @@ impl VariableClassifier { Ok(()) } + fn new_cut_state(&mut self) -> TraversalState { + let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override { + (var_num, false) + } else if let Some(var_num) = self.global_cut_var_num { + (var_num, true) + } else { + let var_num = self.var_num; + + self.global_cut_var_num = Some(var_num); + self.var_num += 1; + + (var_num, true) + }; + + self.probe_in_situ_var(var_num); + + TraversalState::Cut { var_num, is_global } + } + fn classify_body_variables<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - term: Term, + terms: &mut FocusedHeap, + term_loc: usize, ) -> Result { - let mut state_stack = vec![TraversalState::Term(term)]; + let mut state_stack = vec![TraversalState::Term { + subterm: terms.heap[term_loc], + term_loc, + }]; let mut build_stack = ChunkedTermVec::new(); self.current_chunk_type = ChunkType::Mid; - while let Some(traversal_st) = state_stack.pop() { + 'outer: while let Some(traversal_st) = state_stack.pop() { match traversal_st { TraversalState::AddBranchNum(branch_num) => { self.root_set.insert(branch_num.clone()); @@ -544,297 +622,339 @@ impl VariableClassifier { TraversalState::Fail => { build_stack.push_chunk_term(QueryTerm::Fail); } - TraversalState::Term(term) => { + TraversalState::Succeed => { + build_stack.push_chunk_term(QueryTerm::Succeed); + } + TraversalState::Term { + mut subterm, + mut term_loc, + } => { // return true iff new chunk should be added. - let update_chunk_data = |classifier: &mut Self, predicate_name, arity| { - if ClauseType::is_inlined(predicate_name, arity) { + let update_chunk_data = |classifier: &mut Self, key: PredicateKey| { + if ClauseType::is_inlined(key.0, key.1) { classifier.try_set_chunk_at_inlined_boundary() } else { classifier.try_set_chunk_at_call_boundary() } }; - let mut add_chunk = |classifier: &mut Self, name: Atom, terms: Vec| { - if update_chunk_data(classifier, name, terms.len()) { - build_stack.add_chunk(); - } - - for (arg_c, term) in terms.iter().enumerate() { - classifier.probe_body_term(arg_c + 1, terms.len(), term); - } - - build_stack.push_chunk_term(clause_to_query_term( - loader, - name, - terms, - classifier.call_policy, - )); - }; - - match term { - Term::Clause( - _, - name @ (atom!("->") | atom!(";") | atom!(",")), - mut terms, - ) if terms.len() == 3 => { - if let Some(last_arg) = terms.last() { - if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { - terms.pop(); - state_stack.push(TraversalState::Term(Term::Clause( - Cell::default(), - name, - terms, - ))); - } else { - add_chunk(self, name, terms); - } + macro_rules! add_chunk { + ($classifier:ident, $key:expr, $tag:expr, $term_loc:expr) => {{ + if update_chunk_data($classifier, $key) { + build_stack.add_chunk(); } - } - Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => { - let tail = terms.pop().unwrap(); - let head = terms.pop().unwrap(); - - let iter = unfold_by_str(tail, atom!(",")) - .into_iter() - .rev() - .chain(std::iter::once(head)) - .map(TraversalState::Term); - - state_stack.extend(iter); - } - Term::Clause(_, atom!(";"), mut terms) if terms.len() == 2 => { - let tail = terms.pop().unwrap(); - let head = terms.pop().unwrap(); - - let first_branch_num = self.current_branch_num.split(); - let branches: Vec<_> = std::iter::once(head) - .chain(unfold_by_str(tail, atom!(";")).into_iter()) - .collect(); - - let mut branch_numbers = vec![first_branch_num]; - - for idx in 1..branches.len() { - let succ_branch_number = branch_numbers[idx - 1].incr_by_delta(); - branch_numbers.push(if idx + 1 < branches.len() { - succ_branch_number.split() - } else { - succ_branch_number - }); + 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); } - let build_stack_len = build_stack.len(); - build_stack.reserve_branch(branches.len()); - - state_stack.push(TraversalState::RepBranchNum( - self.current_branch_num.halve_delta(), - )); - - let iter = branches.into_iter().zip(branch_numbers.into_iter()); - let final_disjunct_loc = state_stack.len(); + build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( + loader, + $key, + terms.as_ref_mut($term_loc), + HeapCellValue::build_with($tag, $term_loc as u64), + $classifier.call_policy, + ))); + }}; + } - for (term, branch_num) in iter.rev() { - state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); - state_stack.push(TraversalState::RemoveBranchNum); - state_stack.push(TraversalState::Term(term)); - state_stack.push(TraversalState::AddBranchNum(branch_num)); + macro_rules! add_qualified_chunk { + ($classifier:ident, $module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{ + if update_chunk_data($classifier, $key) { + build_stack.add_chunk(); } - if let TraversalState::BuildDisjunct(build_stack_len) = - state_stack[final_disjunct_loc] + for (arg_c, term_loc) in + ($term_loc + 1..$term_loc + $key.1 + 1).enumerate() { - state_stack[final_disjunct_loc] = - TraversalState::BuildFinalDisjunct(build_stack_len); + $classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc); } - self.current_chunk_type = ChunkType::Mid; - self.current_chunk_num += 1; - } - Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => { - let then_term = terms.pop().unwrap(); - let if_term = terms.pop().unwrap(); - - let prev_b = if matches!( - state_stack.last(), - Some(TraversalState::RemoveBranchNum) - ) { - // check if the second-to-last element - // is a regular BuildDisjunct, as we - // don't want to add GetPrevLevel in - // case of a TrustMe. - match state_stack.iter().rev().nth(1) { - Some(&TraversalState::BuildDisjunct(preceding_len)) => { - preceding_len + 1 == build_stack.len() - } - _ => false, - } - } else { - false - }; - - state_stack.push(TraversalState::Term(then_term)); - state_stack.push(TraversalState::Cut { - var_num: self.var_num, - is_global: false, - }); - state_stack.push(TraversalState::Term(if_term)); - state_stack.push(TraversalState::GetCutPoint { - var_num: self.var_num, - prev_b, - }); - - self.var_num += 1; - } - Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => { - let not_term = terms.pop().unwrap(); - let build_stack_len = build_stack.len(); - - build_stack.reserve_branch(2); - - state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len)); - state_stack.push(TraversalState::Term(Term::Clause( - Cell::default(), - atom!("$succeed"), - vec![], - ))); - state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); - state_stack.push(TraversalState::Fail); - state_stack.push(TraversalState::CutPrev(self.var_num)); - state_stack.push(TraversalState::ResetGlobalCutVarOverride( - self.global_cut_var_num_override, + build_stack.push_chunk_term(QueryTerm::Clause( + qualified_clause_to_query_term( + loader, + $key, + $module_name, + terms.as_ref_mut($term_loc), + HeapCellValue::build_with($tag, $term_loc as u64), + $classifier.call_policy, + ), )); - state_stack.push(TraversalState::Term(not_term)); - state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num)); - state_stack.push(TraversalState::GetCutPoint { - var_num: self.var_num, - prev_b: false, - }); + }}; + } - self.current_chunk_type = ChunkType::Mid; - self.current_chunk_num += 1; + loop { + read_heap_cell!(subterm, + (HeapCellValueTag::Str, subterm_loc) => { + let (name, arity) = cell_as_atom_cell!(terms.heap[subterm_loc]) + .get_name_and_arity(); - self.var_num += 1; - } - Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => { - let predicate_name = terms.pop().unwrap(); - let module_name = terms.pop().unwrap(); - - match (module_name, predicate_name) { - ( - Term::Literal(_, Literal::Atom(module_name)), - Term::Literal(_, Literal::Atom(predicate_name)), - ) => { - if update_chunk_data(self, predicate_name, 0) { - build_stack.add_chunk(); - } + match (name, arity) { + (atom!("->") | atom!(";") | atom!(","), 3) => { + if blunt_index_ptr(&mut terms.heap, (name, 2), subterm_loc) { + subterm = terms.heap[subterm_loc]; + continue; + } - build_stack.push_chunk_term(qualified_clause_to_query_term( - loader, - module_name, - predicate_name, - vec![], - self.call_policy, - )); - } - ( - Term::Literal(_, Literal::Atom(module_name)), - Term::Clause(_, name, terms), - ) => { - if update_chunk_data(self, name, terms.len()) { - build_stack.add_chunk(); + add_chunk!(self, (name, 2), HeapCellValueTag::Str, subterm_loc); } - - for (arg_c, term) in terms.iter().enumerate() { - self.probe_body_term(arg_c + 1, terms.len(), term); + (atom!(","), 2) => { + let head_loc = terms.nth_arg(subterm_loc, 1).unwrap(); + let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + let head = terms.heap[head_loc]; + + let iter = unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(",")) + .into_iter() + .rev() + .chain(std::iter::once((head, head_loc))) + .map(|(subterm, term_loc)| { + TraversalState::Term { subterm, term_loc } + }); + state_stack.extend(iter); } - - build_stack.push_chunk_term(qualified_clause_to_query_term( - loader, - module_name, - name, - terms, - self.call_policy, - )); - } - (module_name, predicate_name) => { - if update_chunk_data(self, atom!("call"), 2) { - build_stack.add_chunk(); + (atom!(";"), 2) => { + let head_loc = terms.nth_arg(subterm_loc, 1).unwrap(); + let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + + let head = terms.heap[head_loc]; + + let first_branch_num = self.current_branch_num.split(); + let branches: Vec<_> = std::iter::once((head, head_loc)) + .chain( + unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(";")) + .into_iter(), + ) + .collect(); + + let mut branch_numbers = vec![first_branch_num]; + + for idx in 1..branches.len() { + let succ_branch_number = branch_numbers[idx - 1].incr_by_delta(); + + branch_numbers.push(if idx + 1 < branches.len() { + succ_branch_number.split() + } else { + succ_branch_number + }); + } + + let build_stack_len = build_stack.len(); + build_stack.reserve_branch(branches.len()); + + state_stack.push(TraversalState::RepBranchNum( + self.current_branch_num.halve_delta(), + )); + + let iter = branches.into_iter().zip(branch_numbers.into_iter()); + let final_disjunct_loc = state_stack.len(); + + for ((subterm, term_loc), branch_num) in iter.rev() { + state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); + state_stack.push(TraversalState::RemoveBranchNum); + state_stack.push(TraversalState::Term { subterm, term_loc }); + state_stack.push(TraversalState::AddBranchNum(branch_num)); + } + + if let TraversalState::BuildDisjunct(build_stack_len) = + state_stack[final_disjunct_loc] + { + state_stack[final_disjunct_loc] = + TraversalState::BuildFinalDisjunct(build_stack_len); + } + + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; } + (atom!("->"), 2) => { + let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); + let then_term_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + + let if_term = terms.heap[if_term_loc]; + let then_term = terms.heap[then_term_loc]; + + let prev_b = if matches!( + state_stack.last(), + Some(TraversalState::RemoveBranchNum) + ) { + // check if the second-to-last element + // is a regular BuildDisjunct, as we + // don't want to add GetPrevLevel in + // case of a TrustMe. + match state_stack.iter().rev().nth(1) { + Some(&TraversalState::BuildDisjunct(preceding_len)) => { + preceding_len + 1 == build_stack.len() + } + _ => false, + } + } else { + false + }; + + state_stack.push(TraversalState::Term { + subterm: then_term, + term_loc: then_term_loc, + }); + state_stack.push(TraversalState::Cut { + var_num: self.var_num, + is_global: false, + }); + state_stack.push(TraversalState::Term { + subterm: if_term, + term_loc: if_term_loc, + }); + state_stack.push(TraversalState::GetCutPoint { + var_num: self.var_num, + prev_b, + }); + + self.var_num += 1; + } + (atom!("\\+"), 1) => { + let not_term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); + let not_term = terms.heap[not_term_loc]; + let build_stack_len = build_stack.len(); + + build_stack.reserve_branch(2); + + let branch_num = self.current_branch_num.split(); + let succ_branch_num = branch_num.incr_by_delta(); + + state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len)); + state_stack.push(TraversalState::Succeed); + state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); + state_stack.push(TraversalState::RepBranchNum(succ_branch_num)); + state_stack.push(TraversalState::Fail); + state_stack.push(TraversalState::CutPrev(self.var_num)); + state_stack.push(TraversalState::ResetGlobalCutVarOverride( + self.global_cut_var_num_override, + )); + state_stack.push(TraversalState::Term { + subterm: not_term, + term_loc: not_term_loc, + }); + state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num)); + state_stack.push(TraversalState::GetCutPoint { + var_num: self.var_num, + prev_b: false, + }); + state_stack.push(TraversalState::AddBranchNum(branch_num)); + + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; + + self.var_num += 1; + } + (atom!(":"), 2) => { + let module_name_loc = terms.nth_arg(subterm_loc, 1).unwrap(); + let predicate_term_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + + let module_name = terms.deref_loc(module_name_loc); + let predicate_term = terms.deref_loc(predicate_term_loc); + + read_heap_cell!(module_name, + (HeapCellValueTag::Atom, (module_name, arity)) => { + if arity == 0 { + read_heap_cell!(predicate_term, + (HeapCellValueTag::Str, s) => { + let key = cell_as_atom_cell!(terms.heap[s]) + .get_name_and_arity(); + + add_qualified_chunk!( + self, + module_name, + key, + HeapCellValueTag::Str, + s + ); + } + (HeapCellValueTag::Atom, (predicate_name, predicate_arity)) => { + debug_assert_eq!(predicate_arity, 0); + let key = (predicate_name, predicate_arity); + + add_qualified_chunk!( + self, + module_name, + key, + HeapCellValueTag::Str, + predicate_term_loc + ); + } + _ => {} + ); + + continue 'outer; + } + } + _ => {} + ); + + if update_chunk_data(self, (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 h = terms.heap.len(); + + terms.heap.push(atom_as_cell!(atom!("call"), 1)); + terms.heap.push(str_loc_as_cell!(subterm_loc)); + + build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( + loader, + (atom!("call"), 1), + terms.as_ref_mut(h), + str_loc_as_cell!(h), + self.call_policy, + ))); + } + (atom!("$call_with_inference_counting"), 1) => { + let term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); + let subterm = terms.deref_loc(term_loc); - self.probe_body_term(1, 0, &module_name); - self.probe_body_term(2, 0, &predicate_name); - - terms.push(module_name); - terms.push(predicate_name); + state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); + state_stack.push(TraversalState::Term { subterm, term_loc }); - build_stack.push_chunk_term(clause_to_query_term( - loader, - atom!("call"), - vec![Term::Clause(Cell::default(), atom!(":"), terms)], - self.call_policy, - )); + self.call_policy = CallPolicy::Counted; + } + (name, arity) => { + add_chunk!(self, (name, arity), HeapCellValueTag::Str, subterm_loc); + } } } - } - Term::Clause(_, atom!("$call_with_inference_counting"), mut terms) - if terms.len() == 1 => - { - state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); - state_stack.push(TraversalState::Term(terms.pop().unwrap())); + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); - self.call_policy = CallPolicy::Counted; - } - Term::Clause(_, name, terms) => { - add_chunk(self, name, terms); - } - var @ Term::Var(..) => { - if update_chunk_data(self, atom!("call"), 1) { - build_stack.add_chunk(); + if name == atom!("!") { + state_stack.push(self.new_cut_state()); + } else { + add_chunk!(self, (name, 0), HeapCellValueTag::Var, term_loc); + } } - - self.probe_body_term(1, 1, &var); - - build_stack.push_chunk_term(clause_to_query_term( - loader, - atom!("call"), - vec![var], - self.call_policy, - )); - } - Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => { - let (var_num, is_global) = - if let Some(var_num) = self.global_cut_var_num_override { - (var_num, false) - } else if let Some(var_num) = self.global_cut_var_num { - (var_num, true) + (HeapCellValueTag::Char, c) => { + if c == '!' { + state_stack.push(self.new_cut_state()); } else { - let var_num = self.var_num; - - self.global_cut_var_num = Some(var_num); - self.var_num += 1; - - (var_num, true) - }; - - self.probe_in_situ_var(var_num); + return Err(CompilationError::InadmissibleQueryTerm); + } + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h != term_loc { + subterm = terms.heap[h]; + term_loc = h; + continue; + } - state_stack.push(TraversalState::Cut { var_num, is_global }); - } - Term::Literal(_, Literal::Atom(name)) => { - if update_chunk_data(self, name, 0) { - build_stack.add_chunk(); + add_chunk!(self, (atom!("call"), 1), HeapCellValueTag::Var, h); + } + _ => { + return Err(CompilationError::InadmissibleQueryTerm); } + ); - build_stack.push_chunk_term(clause_to_query_term( - loader, - name, - vec![], - self.call_policy, - )); - } - _ => { - return Err(CompilationError::InadmissibleQueryTerm); - } + break; } } } @@ -899,7 +1019,8 @@ impl BranchMap { var_data.records[var_num].num_occurrences += chunk.vars.len(); for var_info in chunk.vars.iter_mut() { - var_info.var_ptr.set(Var::Generated(var_num)); + let is_anon = var_info.var_ptr.is_anon(); + var_info.var_ptr.set(Var::Generated { is_anon, var_num }); } } } diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 57d3e5ae..729c6974 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -2664,6 +2664,8 @@ impl Machine { &Instruction::CallNamed(arity, name, ref idx) => { let idx = idx.get(); + // println!("calling {}/{}", name.as_str(), arity); + try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); if self.machine_st.fail { @@ -2675,6 +2677,8 @@ impl Machine { &Instruction::ExecuteNamed(arity, name, ref idx) => { let idx = idx.get(); + // println!("executing {}/{}", name.as_str(), arity); + try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); if self.machine_st.fail { @@ -2686,6 +2690,8 @@ impl Machine { &Instruction::DefaultCallNamed(arity, name, ref idx) => { let idx = idx.get(); + // println!("calling {}/{}", name.as_str(), arity); + try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); if self.machine_st.fail { @@ -2695,6 +2701,8 @@ impl Machine { &Instruction::DefaultExecuteNamed(arity, name, ref idx) => { let idx = idx.get(); + // println!("executing {}/{}", name.as_str(), arity); + try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); if self.machine_st.fail { @@ -3511,6 +3519,15 @@ impl Machine { self.dynamic_module_resolution(arity - 2) ); + /* + println!( + "(slow) calling {}:{}/{}", + module_name.as_str(), + key.0.as_str(), + key.1, + ); + */ + try_or_throw!(self.machine_st, self.call_clause(module_name, key)); if self.machine_st.fail { @@ -3523,6 +3540,15 @@ impl Machine { self.dynamic_module_resolution(arity - 2) ); + /* + println!( + "(slow) executing {}:{}/{}", + module_name.as_str(), + key.0.as_str(), + key.1, + ); + */ + try_or_throw!(self.machine_st, self.execute_clause(module_name, key)); if self.machine_st.fail { diff --git a/src/machine/gc.rs b/src/machine/gc.rs index e37178bf..4d3d45ec 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -7,6 +7,9 @@ use crate::types::*; #[cfg(test)] use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc}; +#[cfg(test)] +use std::ops::Deref; + pub(crate) trait UnmarkPolicy { fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option where @@ -103,6 +106,15 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> { iter_state: UMP, } +#[cfg(test)] +impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> { + type Target = [HeapCellValue]; + + fn deref(&self) -> &Self::Target { + self.heap + } +} + #[cfg(test)] impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> { #[inline] diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 86c1b681..f62e01f6 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -436,7 +436,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { pub(super) fn try_term_to_tl( &mut self, - term: Term, + term: FocusedHeap, preprocessor: &mut Preprocessor, ) -> Result { let tl = preprocessor.try_term_to_tl(self, term)?; @@ -1164,7 +1164,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let mut path_buf = PathBuf::from(&*filename.as_str()); path_buf.set_extension("pl"); - let file = File::open(&path_buf)?; + let file = File::open(&path_buf) + .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?; ( Stream::from_file_as_input( @@ -1245,7 +1246,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ModuleSource::File(filename) => { let mut path_buf = PathBuf::from(&*filename.as_str()); path_buf.set_extension("pl"); - let file = File::open(&path_buf)?; + let file = File::open(&path_buf) + .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?; ( Stream::from_file_as_input( diff --git a/src/machine/loader.rs b/src/machine/loader.rs index b7e7c4b5..5b96fe37 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -15,7 +15,6 @@ use crate::types::*; use indexmap::IndexSet; -use std::cell::Cell; use std::collections::VecDeque; use std::convert::TryFrom; use std::fmt; @@ -177,18 +176,18 @@ impl CompilationTarget { } pub struct PredicateQueue { - pub(super) predicates: Vec, + pub(super) predicates: Vec, pub(super) compilation_target: CompilationTarget, } impl PredicateQueue { #[inline] - pub(super) fn push(&mut self, clause: Term) { + pub(super) fn push(&mut self, clause: FocusedHeap) { self.predicates.push(clause); } #[inline] - pub(crate) fn first(&self) -> Option<&Term> { + pub(crate) fn first(&self) -> Option<&FocusedHeap> { self.predicates.first() } @@ -492,11 +491,23 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } - pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Term { + pub(crate) fn copy_term_from_heap(&mut self, cell: HeapCellValue) -> FocusedHeap { + use crate::iterators::fact_iterator; + + let mut term = FocusedHeap::empty(); + let mut stack = Stack::uninitialized(); let machine_st = LS::machine_st(&mut self.payload); - let cell = machine_st[r]; - machine_st.read_term_from_heap(cell) + term.copy_term_from_machine_heap(machine_st, cell); + term.var_locs = var_locs_from_iter( + fact_iterator::( + &mut term.heap, + &mut stack, + 0, + ), + ); + + term } pub(crate) fn load(mut self) -> Result { @@ -513,18 +524,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let compilation_target = &load_state.compilation_target; let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target); - let term = load_state.term_stream.next(&composite_op_dir)?; + let mut term = load_state.term_stream.next(&composite_op_dir)?; if !term.is_consistent(&load_state.predicates) { self.compile_and_submit()?; } - let term = match term { - Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => { - return Ok(Some(setup_declaration(self, terms)?)); - } - term => term, - }; + if Some(atom!(":-")) == term.name(term.focus) && term.arity(term.focus) == 1 { + let new_focus = term.nth_arg(term.focus, 1).unwrap(); + let term = term.as_ref_mut(new_focus); + return Ok(Some(setup_declaration(self, term)?)); + } self.payload.predicates.push(term); } @@ -1045,31 +1055,60 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let machine_st = LS::machine_st(&mut self.payload); let cell = machine_st[r]; - let export_list = machine_st.read_term_from_heap(cell); - let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl; - let export_list = setup_module_export_list(export_list, atom_tbl)?; + let export_list = FocusedHeapRefMut::from_cell(&mut machine_st.heap, cell); + let export_list = setup_module_export_list(export_list)?; Ok(export_list.into_iter().collect()) } - fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> { - match term { - Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => { - let body = terms.pop().unwrap(); - let head = terms.pop().unwrap(); + fn clause_clause(&mut self, cell: HeapCellValue) -> Result { + let machine_st = LS::machine_st(&mut self.payload); + let mut term = FocusedHeap::empty(); + + read_heap_cell!(cell, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) + .get_name_and_arity(); + + term.copy_term_from_machine_heap(machine_st, cell); + let focus = term.heap.len(); + + term.heap.push(str_loc_as_cell!(focus+1)); + term.heap.push(atom_as_cell!(atom!("clause"), 2)); - self.payload.clause_clauses.push((head, body)); + match (name, arity) { + (atom!(":-"), 2) => { + term.heap.push(heap_loc_as_cell!(2)); + term.heap.push(heap_loc_as_cell!(3)); + } + _ => { + term.heap.push(heap_loc_as_cell!(0)); + term.heap.push(atom_as_cell!(atom!("true"))); + } + } + + term.focus = focus; } - head @ Term::Literal(_, Literal::Atom(..)) | head @ Term::Clause(..) => { - let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true"))); - self.payload.clause_clauses.push((head, body)); + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + term.heap.push(str_loc_as_cell!(1)); + term.heap.push(atom_as_cell!(atom!("clause"), 2)); + term.heap.push(atom_as_cell!(name)); + term.heap.push(atom_as_cell!(atom!("true"))); + + term.focus = 0; + } else { + return Err(CompilationError::InadmissibleFact); + } } _ => { return Err(CompilationError::InadmissibleFact); } - } + ); - Ok(()) + let value = term.heap[term.focus]; + term.var_locs = var_locs_from_iter(eager_stackful_preorder_iter(&mut term.heap, value)); + Ok(term) } fn add_extensible_predicate_declaration( @@ -1287,9 +1326,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ) } - fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> { - if let Some(predicate_name) = ClauseInfo::name(term) { - let arity = ClauseInfo::arity(term); + fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> { + let machine_st = LS::machine_st(&mut self.payload); + let term = FocusedHeapRefMut::from_cell(&mut machine_st.heap, value); + + let name_opt = ClauseInfo::name(&term); + + if let Some(predicate_name) = name_opt { + let arity = ClauseInfo::arity(&term); let predicates_compilation_target = self.payload.predicates.compilation_target; let is_dynamic = self @@ -1300,7 +1344,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .unwrap_or(false); if is_dynamic { - self.add_clause_clause(term.clone())?; + let clause_clause_term = self.clause_clause(value)?; + self.payload.clause_clauses.push(clause_clause_term); } } @@ -1366,108 +1411,6 @@ impl<'a> MachinePreludeView<'a> { } } -impl MachineState { - pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term { - let mut term_stack = vec![]; - let mut iter = - stackful_post_order_iter::(&mut self.heap, &mut self.stack, term_addr); - - while let Some(addr) = iter.next() { - let addr = unmark_cell_bits!(addr); - - read_heap_cell!(addr, - (HeapCellValueTag::Lis) => { - use crate::parser::parser::as_partial_string; - - let tail = term_stack.pop().unwrap(); - let head = term_stack.pop().unwrap(); - - match as_partial_string(head, tail) { - Ok((string, Some(tail))) => { - term_stack.push(Term::PartialString(Cell::default(), string, tail)); - } - Ok((string, None)) => { - let atom = AtomTable::build_with(&self.atom_tbl, &string); - term_stack.push(Term::CompleteString(Cell::default(), atom)); - } - Err(cons_term) => term_stack.push(cons_term), - } - } - (HeapCellValueTag::StackVar, h) => { - term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h)))); - } - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { - term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h)))); - } - (HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum | - HeapCellValueTag::Char | HeapCellValueTag::F64) => { - term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap())); - } - (HeapCellValueTag::Atom, (name, arity)) => { - let h = iter.focus().value() as usize; - let mut arity = arity; - - if iter.heap.len() > h + arity + 1 { - let value = iter.heap[h + arity + 1]; - - if let Some(idx) = get_structure_index(value) { - // in the second condition, arity == 0, - // meaning idx cannot pertain to this atom - // if it is the direct subterm of a larger - // structure. - if arity > 0 || !iter.direct_subterm_of_str(h) { - term_stack.push( - Term::Literal(Cell::default(), Literal::CodeIndex(idx)) - ); - - arity += 1; - } - } - } - - if arity == 0 { - term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); - } else { - let subterms = term_stack - .drain(term_stack.len() - arity ..) - .collect(); - - term_stack.push(Term::Clause(Cell::default(), name, subterms)); - } - } - (HeapCellValueTag::PStr, atom) => { - let tail = term_stack.pop().unwrap(); - - if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail { - term_stack.push(Term::CompleteString(Cell::default(), atom)); - } else { - term_stack.push(Term::PartialString( - Cell::default(), - atom.as_str().to_owned(), - Box::new(tail), - )); - } - } - (HeapCellValueTag::PStrLoc, h) => { - let atom = cell_as_atom_cell!(iter.heap[h]).get_name(); - let tail = term_stack.pop().unwrap(); - - term_stack.push(Term::PartialString( - Cell::default(), - atom.as_str().to_owned(), - Box::new(tail), - )); - } - _ => { - } - ); - } - - debug_assert!(term_stack.len() == 1); - term_stack.pop().unwrap() - } -} - impl Machine { pub(crate) fn use_module(&mut self) -> CallResult { let subevacuable_addr = self @@ -1628,10 +1571,11 @@ impl Machine { } pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult { + let value = self.machine_st.registers[1]; let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let add_clause = || { - let term = loader.read_term_from_heap(temp_v!(1)); + let term = loader.copy_term_from_heap(value); loader.incremental_compile_clause( (atom!("term_expansion"), 2), @@ -1653,6 +1597,7 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st.registers[1]))); + let value = self.machine_st.registers[2]; let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); let compilation_target = match target_module_name { @@ -1661,21 +1606,21 @@ impl Machine { }; let add_clause = || { - let term = loader.read_term_from_heap(temp_v!(2)); + let term = loader.copy_term_from_heap(value); - let indexing_arg = match term.name() { - Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg), - Some(_) => term.first_arg(), + let indexing_arg = match term.name(term.focus) { + Some(atom!(":-")) => term.nth_arg(term.focus, 1).and_then(|h| term.nth_arg(h, 1)), + Some(_) => term.nth_arg(term.focus, 1), None => None, }; - if let Some(indexing_term) = indexing_arg { - if let Some(indexing_name) = indexing_term.name() { + if let Some(indexing_term_loc) = indexing_arg { + if let Some(indexing_name) = term.name(indexing_term_loc) { loader .wam_prelude .indices .goal_expansion_indices - .insert((indexing_name, indexing_term.arity())); + .insert((indexing_name, term.arity(indexing_term_loc))); } } @@ -1981,30 +1926,24 @@ impl Machine { }; let stub_gen = || functor_stub(key.0, key.1); + let assert_clause = self.machine_st.registers[2]; + let (name, arity) = { + let term = FocusedHeapRefMut::from_cell(&mut self.machine_st.heap, assert_clause); + (ClauseInfo::name(&term), ClauseInfo::arity(&term)) + }; - let head = self.deref_register(2); - - if head.is_var() { - let err = self.machine_st.instantiation_error(); - return Err(self.machine_st.error_form(err, stub_gen())); - } - - let mut compile_assert = || { + let mut compile_assert = |assert_clause, name, arity| { let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = Loader::new(self, LiveTermStream::new(ListingSource::User)); loader.payload.compilation_target = compilation_target; - let head = - LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head); - - let name = if let Some(name) = head.name() { + let name = if let Some(name) = name { name } else { return Err(SessionError::from(CompilationError::InvalidRuleHead)); }; - let arity = head.arity(); let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity)); let is_dynamic_predicate = loader @@ -2036,16 +1975,9 @@ impl Machine { return LiveLoadAndMachineState::evacuate(loader); } - let body = loader.read_term_from_heap(temp_v!(3)); - - let asserted_clause = Term::Clause( - Cell::default(), - atom!(":-"), - vec![head.clone(), body.clone()], - ); - // if a new predicate was just created, make it dynamic. loader.add_dynamic_predicate(compilation_target, name, arity)?; + let asserted_clause = loader.copy_term_from_heap(assert_clause); loader.incremental_compile_clause( (name, arity), @@ -2055,20 +1987,22 @@ impl Machine { append_or_prepend, )?; + let clause_clause_term = loader.clause_clause(assert_clause)?; + // the global clock is incremented after each assertion. LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; loader.compile_clause_clauses( (name, arity), compilation_target, - std::iter::once((head, body)), + vec![clause_clause_term], append_or_prepend, )?; LiveLoadAndMachineState::evacuate(loader) }; - match compile_assert() { + match compile_assert(assert_clause, name, arity) { Ok(_) => Ok(()), Err(SessionError::CompilationError( CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact, @@ -2474,9 +2408,12 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> { self.payload.predicates.compilation_target = compilation_target; } - let term = self.read_term_from_heap(term_reg); + let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); + let value = machine_st[term_reg]; + + self.add_clause_clause_if_dynamic(value)?; - self.add_clause_clause_if_dynamic(&term)?; + let term = self.copy_term_from_heap(value); self.payload.term_stream.term_queue.push_back(term); self.load() diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 82056f3a..511695d9 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -24,7 +24,7 @@ enum ErrorProvenance { #[derive(Debug)] pub(crate) struct MachineError { stub: MachineStub, - location: Option<(usize, usize)>, // line_num, col_num + location: Option, from: ErrorProvenance, } @@ -649,7 +649,7 @@ impl MachineState { stub[1] = err.stub[0]; } - if let Some((line_num, _)) = location { + if let Some(ParserErrorSrc { line_num, .. }) = location { stub.push(atom_as_cell!(atom!(":"), 2)); stub.push(str_loc_as_cell!(h + 6 + stub_addition_len)); stub.push(integer_as_cell!(Number::arena_from( @@ -741,9 +741,9 @@ impl From for CompilationError { } impl CompilationError { - pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> { + pub(crate) fn line_and_col_num(&self) -> Option { match self { - CompilationError::ParserError(err) => err.line_and_col_num(), + CompilationError::ParserError(err) => Some(err.err_src()), _ => None, } } @@ -1044,13 +1044,6 @@ pub enum SessionError { PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey), } -impl From for SessionError { - #[inline] - fn from(err: std::io::Error) -> SessionError { - SessionError::from(ParserError::from(err)) - } -} - impl From for SessionError { #[inline] fn from(err: ParserError) -> Self { diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index e2d7b248..56c03e7e 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -21,6 +21,8 @@ use std::collections::BTreeSet; use std::ops::{Deref, DerefMut}; use crate::types::*; +// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +// pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity); // 7.2 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -212,30 +214,6 @@ impl CodeIndex { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum VarKey { - AnonVar(usize), - VarPtr(VarPtr), -} - -impl VarKey { - #[allow(clippy::inherent_to_string)] - #[inline] - pub(crate) fn to_string(&self) -> String { - match self { - VarKey::AnonVar(h) => format!("_{}", h), - VarKey::VarPtr(var) => var.borrow().to_string(), - } - } - - #[inline(always)] - pub(crate) fn is_anon(&self) -> bool { - matches!(self, VarKey::AnonVar(_)) - } -} - -pub(crate) type HeapVarDict = IndexMap; - pub(crate) type GlobalVarDir = IndexMap), FxBuildHasher>; pub(crate) type StreamAliasDir = IndexMap; @@ -292,11 +270,9 @@ impl IndexStore { _ => self .get_meta_predicate_spec(key.0, key.1, &compilation_target) .map(|meta_specs| { - meta_specs.iter().find(|meta_spec| { - matches!( - meta_spec, - MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) - ) + meta_specs.iter().find(|meta_spec| match meta_spec { + MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) => true, + _ => false, }) }) .map(|meta_spec_opt| meta_spec_opt.is_some()) diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 5376042c..bd2b217f 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -71,7 +71,7 @@ pub struct MachineState { pub(super) e: usize, pub(super) num_of_args: usize, pub(super) cp: usize, - pub(super) attr_var_init: AttrVarInitializer, + pub(crate) attr_var_init: AttrVarInitializer, pub(super) fail: bool, pub heap: Heap, pub(super) mode: MachineMode, @@ -200,20 +200,21 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn ) } -fn push_var_eq_functors<'a>( +fn push_var_eq_functors( heap: &mut Heap, - iter: impl Iterator, + iter: impl Iterator, // (&'a VarPtr, &'a HeapCellValue)>, atom_tbl: &AtomTable, ) -> Vec { let mut list_of_var_eqs = vec![]; - for (var, binding) in iter { - let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); + for (var_loc, var_ptr) in iter { // (var, binding) in iter { + let var_atom = AtomTable::build_with(atom_tbl, &*var_ptr.borrow().to_string()); let h = heap.len(); + let binding = heap[var_loc]; heap.push(atom_as_cell!(atom!("="), 2)); heap.push(atom_as_cell!(var_atom)); - heap.push(*binding); + heap.push(binding); list_of_var_eqs.push(str_loc_as_cell!(h)); } @@ -221,6 +222,16 @@ fn push_var_eq_functors<'a>( list_of_var_eqs } + +pub(crate) fn copy_and_align_iter>( + iter: Iter, + boundary: i64, + h: i64, +) -> impl Iterator { + let diff = boundary - h; + iter.map(move |heap_value| heap_value - diff) +} + #[derive(Debug)] pub struct Ball { pub(super) boundary: usize, @@ -241,13 +252,7 @@ impl Ball { } pub(super) fn copy_and_align(&self, h: usize) -> Heap { - let diff = self.boundary as i64 - h as i64; - - self.stub - .iter() - .cloned() - .map(|heap_value| heap_value - diff) - .collect() + copy_and_align_iter(self.stub.iter().cloned(), self.boundary as i64, h as i64).collect() } } @@ -311,7 +316,7 @@ impl<'a> CopierTarget for CopyTerm<'a> { } #[derive(Debug)] -pub(super) struct CopyBallTerm<'a> { +pub(crate) struct CopyBallTerm<'a> { attr_var_queue: &'a mut Vec, stack: &'a mut Stack, heap: &'a mut Heap, @@ -320,7 +325,7 @@ pub(super) struct CopyBallTerm<'a> { } impl<'a> CopyBallTerm<'a> { - pub(super) fn new( + pub(crate) fn new( attr_var_queue: &'a mut Vec, stack: &'a mut Stack, heap: &'a mut Heap, @@ -536,18 +541,19 @@ impl MachineState { pub fn write_read_term_options( &mut self, - mut var_list: Vec<(VarKey, HeapCellValue, usize)>, + mut var_list: Vec<(VarPtr, 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_name, var, _)| { - if var_name.is_anon() { + var_list.iter().filter_map(|(var_ptr, var, _)| { + if var_ptr.is_anon() { None } else { - Some((var_name, var)) + let var_loc = var.get_value() as usize; + Some((var_loc, var_ptr.clone())) } }), &self.atom_tbl, @@ -586,13 +592,13 @@ impl MachineState { Ok(unify_fn!(*self, var_names_offset, var_names_addr)) } - pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult { - let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc], + pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult { + let heap_loc = read_heap_cell!(self.heap[term.heap_loc], (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { - pstr_loc_as_cell!(term_write_result.heap_loc) + pstr_loc_as_cell!(term.heap_loc) } _ => { - heap_loc_as_cell!(term_write_result.heap_loc) + heap_loc_as_cell!(term.heap_loc) } ); @@ -602,15 +608,15 @@ impl MachineState { return Ok(()); } + /* for var in term_write_result.var_dict.values_mut() { *var = heap_bound_deref(&self.heap, *var); } + */ let mut singleton_var_set: IndexMap = IndexMap::new(); - for cell in - stackful_preorder_iter::(&mut self.heap, &mut self.stack, heap_loc) - { + for cell in eager_stackful_preorder_iter(&mut self.heap, heap_loc) { let cell = unmark_cell_bits!(cell); if let Some(var) = cell.as_var() { @@ -624,34 +630,42 @@ impl MachineState { let singleton_var_list = push_var_eq_functors( &mut self.heap, - term_write_result - .var_dict + term.var_locs .iter() - .filter(|(var_name, binding)| { - if var_name.is_anon() { - return false; + .filter_map(|(var_loc, var_ptrs)| { + let var_ptr = var_ptrs.front().unwrap(); + + if var_ptr.is_anon() { + return None; } - if let Some(r) = binding.as_var() { - *singleton_var_set.get(&r).unwrap_or(&false) + // add h to offset the term variable into its heap location. + let r = Ref::heap_cell(var_loc); + + if singleton_var_set.get(&r).cloned().unwrap_or(false) { + Some((var_loc, var_ptr.clone())) } else { - false + None } }), &self.atom_tbl, ); + /* for var in term_write_result.var_dict.values_mut() { *var = heap_bound_deref(&self.heap, *var); } + */ let mut var_list = Vec::with_capacity(singleton_var_set.len()); - for (var_name, addr) in term_write_result.var_dict { - if let Some(var) = addr.as_var() { - if let Some(idx) = singleton_var_set.get_index_of(&var) { - var_list.push((var_name, addr, idx)); - } + for (var_loc, var_ptrs) in term.var_locs.iter() { + let var_ptr = var_ptrs.front().unwrap().clone(); + 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)); } } @@ -734,8 +748,8 @@ impl MachineState { } loop { - match self.read(stream, &indices.op_dir) { - Ok(term_write_result) => return self.read_term_body(term_write_result), + match self.read_to_heap(stream, &indices.op_dir) { + Ok(term) => return self.read_term_body(term), Err(err) => { match &err { CompilationError::ParserError(e) if e.is_unexpected_eof() => { @@ -881,13 +895,16 @@ impl MachineState { } ); + let h = self.heap.len(); + self.heap.push(term_to_be_printed); + let mut printer = HCPrinter::new( &mut self.heap, Arc::clone(&self.atom_tbl), &mut self.stack, op_dir, PrinterOutputter::new(), - term_to_be_printed, + h, ); printer.ignore_ops = ignore_ops; diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 457afacf..5b0096fc 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -39,7 +39,7 @@ impl MockWAM { &mut self, input_stream: Stream, ) -> Result { - self.machine_st.read(input_stream, &self.op_dir) + self.machine_st.read_to_heap(input_stream, &self.op_dir) } pub fn parse_and_write_parsed_term_to_heap( @@ -58,23 +58,24 @@ impl MockWAM { print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc); + let var_names = term_write_result + .var_locs + .iter() + .map(|(var_loc, var_ptrs)| { + (self.machine_st.heap[var_loc], var_ptrs.front().unwrap().clone()) + }) + .collect(); + let mut printer = HCPrinter::new( &mut self.machine_st.heap, Arc::clone(&self.machine_st.atom_tbl), &mut self.machine_st.stack, &self.op_dir, PrinterOutputter::new(), - heap_loc_as_cell!(term_write_result.heap_loc), + term_write_result.heap_loc, ); - printer.var_names = term_write_result - .var_dict - .into_iter() - .map(|(var, cell)| match var { - VarKey::VarPtr(var) => (cell, var.clone()), - VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string())), - }) - .collect(); + printer.var_names = var_names; Ok(printer.print().result()) } @@ -217,7 +218,7 @@ pub(crate) fn write_parsed_term_to_heap( input_stream: Stream, op_dir: &OpDir, ) -> Result { - machine_st.read(input_stream, op_dir) + machine_st.read_to_heap(input_stream, op_dir) } #[cfg(test)] @@ -287,14 +288,15 @@ mod tests { wam.heap.clear(); { - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + let term_write_result_1 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap(); unify!( wam, - str_loc_as_cell!(1), + heap_loc_as_cell!(term_write_result_1.heap_loc), heap_loc_as_cell!(term_write_result_2.heap_loc) ); @@ -307,14 +309,15 @@ mod tests { wam.heap.clear(); { - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + let term_write_result_1 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap(); unify!( wam, - heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_1.heap_loc), heap_loc_as_cell!(term_write_result_2.heap_loc) ); @@ -327,14 +330,15 @@ mod tests { wam.heap.clear(); { - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + let term_write_result_1 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap(); unify!( wam, - heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_1.heap_loc), heap_loc_as_cell!(term_write_result_2.heap_loc) ); @@ -347,14 +351,15 @@ mod tests { wam.heap.clear(); { - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + let term_write_result_1 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap(); unify!( wam, - heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_1.heap_loc), heap_loc_as_cell!(term_write_result_2.heap_loc) ); @@ -367,7 +372,8 @@ mod tests { wam.heap.clear(); { - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + let term_write_result_1 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); @@ -376,7 +382,7 @@ mod tests { unify!( wam, - heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_1.heap_loc), heap_loc_as_cell!(term_write_result_2.heap_loc) ); @@ -459,21 +465,8 @@ mod tests { wam.heap.push(heap_loc_as_cell!(0)); unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); - assert!(!wam.fail); all_cells_unmarked(&wam.heap); - wam.heap.clear(); - - { - let term_write_result_1 = - parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap(); - - print_heap_terms(wam.heap.iter(), term_write_result_1.heap_loc); - - unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4)); - - assert_eq!(wam.heap[2], str_loc_as_cell!(4)); - } } #[test] @@ -496,8 +489,8 @@ mod tests { unify_with_occurs_check!( wam, - str_loc_as_cell!(0), - str_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) ); assert!(wam.fail); diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index 9fcd1825..0173285e 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -5,11 +5,14 @@ use crate::instructions::*; use crate::machine::disjuncts::*; use crate::machine::loader::*; use crate::machine::machine_errors::*; +use crate::machine::CodeIndex; use crate::parser::ast::*; +use crate::types::*; +use fxhash::FxBuildHasher; +use indexmap::IndexMap; use indexmap::IndexSet; -use std::cell::Cell; use std::convert::TryFrom; pub(crate) fn to_op_decl(prec: u16, spec: OpDeclSpec, name: Atom) -> OpDecl { OpDecl::new(OpDesc::build_with(prec, spec), name) @@ -21,44 +24,30 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result, atom_tbl: &AtomTable) -> Result { - // should allow non-partial lists? - let name = match terms.pop().unwrap() { - Term::Literal(_, Literal::Atom(name)) => name, - Term::Literal(_, Literal::Char(c)) => AtomTable::build_with(atom_tbl, &c.to_string()), - other => { - return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclNameType(other), - )); - } - }; +fn setup_op_decl(term: &FocusedHeapRefMut) -> Result { + let (focus, _cell) = subterm_index(term.heap, term.focus); - let spec = match terms.pop().unwrap() { - Term::Literal(_, Literal::Atom(name)) => name, - other => { - return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclSpecDomain(other), - )) - } + let name = match term.name(focus+3) { + Some(name) => name, + None => return Err(CompilationError::InconsistentEntry), }; - let spec = to_op_decl_spec(spec)?; + let spec = match term.name(focus+2) { + Some(name) => name, + None => return Err(CompilationError::InconsistentEntry), + }; - let prec = match terms.pop().unwrap() { - Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) { - Ok(n) if n <= 1200 => n, - _ => { - return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclPrecDomain(bi), - )); + let prec = read_heap_cell!(term.deref_loc(focus+1), + (HeapCellValueTag::Fixnum, n) => { + match u16::try_from(n.get_num()) { + Ok(n) if n <= 1200 => n, + _ => return Err(CompilationError::InconsistentEntry), } - }, - other => { - return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclPrecType(other), - )); } - }; + _ => { + return Err(CompilationError::InconsistentEntry); + } + ); if name == "[]" || name == "{}" { return Err(CompilationError::InvalidDirective( @@ -81,140 +70,166 @@ fn setup_op_decl(mut terms: Vec, atom_tbl: &AtomTable) -> Result Result { - match term { - Term::Clause(_, slash, ref mut terms) - if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 => - { - let arity = terms.pop().unwrap(); - let name = terms.pop().unwrap(); - - let arity = match arity { - Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(), - Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(), - _ => None, - } - .ok_or(CompilationError::InvalidModuleExport)?; +fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result { + let name_opt = term.name(term.focus); + let arity = term.arity(term.focus); - let name = match name { - Term::Literal(_, Literal::Atom(name)) => Some(name), - _ => None, - } + if let (Some(atom!("/") | atom!("//")), 2) = (name_opt, arity) { + let arity_loc = term.nth_arg(term.focus, 2).unwrap(); + + let arity = match Number::try_from(term.deref_loc(arity_loc)) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + Ok(Number::Integer(n)) => (&*n).try_into().ok(), + _ => None, + } + .ok_or(CompilationError::InvalidModuleExport)?; + + let name_loc = term.nth_arg(term.focus, 1).unwrap(); + let name = term + .name(name_loc) .ok_or(CompilationError::InvalidModuleExport)?; - if *slash == atom!("/") { - Ok((name, arity)) - } else { - Ok((name, arity + 2)) - } + if name_opt == Some(atom!("/")) { + Ok((name, arity)) + } else { + Ok((name, arity + 2)) } - _ => Err(CompilationError::InvalidModuleExport), + } else { + Err(CompilationError::InvalidModuleExport) } } -fn setup_module_export( - mut term: Term, - atom_tbl: &AtomTable, -) -> Result { - setup_predicate_indicator(&mut term) +fn setup_module_export(term: &FocusedHeapRefMut) -> Result { + setup_predicate_indicator(term) .map(ModuleExport::PredicateKey) .or_else(|_| { - if let Term::Clause(_, name, terms) = term { - if terms.len() == 3 && name == atom!("op") { - Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?)) - } else { - Err(CompilationError::InvalidModuleDecl) - } + let name_opt = term.name(term.focus); + let arity = term.arity(term.focus); + + if let (Some(atom!("op")), 3) = (name_opt, arity) { + Ok(ModuleExport::OpDecl(setup_op_decl(term)?)) } else { Err(CompilationError::InvalidModuleDecl) } }) } +/* TODO: should be unnecessary now. + pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term { let head_term = Term::Clause(Cell::default(), atom!(""), vars.to_vec()); let rule = vec![head_term, body_term]; Term::Clause(Cell::default(), atom!(":-"), rule) } +*/ pub(super) fn setup_module_export_list( - mut export_list: Term, - atom_tbl: &AtomTable, + term: FocusedHeapRefMut, ) -> Result, CompilationError> { let mut exports = vec![]; - - while let Term::Cons(_, t1, t2) = export_list { - let module_export = setup_module_export(*t1, atom_tbl)?; - - exports.push(module_export); - export_list = *t2; + let mut focus = term.focus; + + loop { + read_heap_cell!(term.heap[focus], + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h == focus { + break; + } else { + focus = h; + } + } + (HeapCellValueTag::Lis, l) => { + let term = FocusedHeapRefMut { + heap: term.heap, + focus: l, + }; + exports.push(setup_module_export(&term)?); + + focus = l + 1; + } + (HeapCellValueTag::Atom, (name, _arity)) => { + if name == atom!("[]") { + return Ok(exports); + } else { + break; + } + } + _ => { + break; + } + ); } - if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { - Ok(exports) - } else { - Err(CompilationError::InvalidModuleDecl) - } + Err(CompilationError::InvalidModuleDecl) } -fn setup_module_decl( - mut terms: Vec, - atom_tbl: &AtomTable, -) -> Result { - let export_list = terms.pop().unwrap(); - let name = terms.pop().unwrap(); - - let name = match name { - Term::Literal(_, Literal::Atom(name)) => Some(name), - _ => None, - } - .ok_or(CompilationError::InvalidModuleDecl)?; - - let exports = setup_module_export_list(export_list, atom_tbl)?; +fn setup_module_decl(term: FocusedHeapRefMut) -> Result { + let name = term + .name(term.focus + 1) + .ok_or(CompilationError::InvalidModuleDecl)?; + let export_list = FocusedHeapRefMut { + heap: term.heap, + focus: term.focus + 2, + }; + let exports = setup_module_export_list(export_list)?; Ok(ModuleDecl { name, exports }) } -fn setup_use_module_decl(mut terms: Vec) -> Result { - match terms.pop().unwrap() { - Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => { - match terms.pop().unwrap() { - Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)), - _ => Err(CompilationError::InvalidModuleDecl), +fn setup_use_module_decl(term: &FocusedHeapRefMut) -> Result { + read_heap_cell!(term.deref_loc(term.focus+1), + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity(); + + if (name, arity) == (atom!("library"), 1) { + read_heap_cell!(term.deref_loc(s+1), + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + return Ok(ModuleSource::Library(name)); + } + } + _ => { + } + ) } + + return Err(CompilationError::InvalidModuleDecl); } - Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)), - _ => Err(CompilationError::InvalidUseModuleDecl), - } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + Ok(ModuleSource::File(name)) + } else { + Err(CompilationError::InvalidUseModuleDecl) + } + } + _ => { + Err(CompilationError::InvalidUseModuleDecl) + } + ) } type UseModuleExport = (ModuleSource, IndexSet); -fn setup_qualified_import( - mut terms: Vec, - atom_tbl: &AtomTable, -) -> Result { - let mut export_list = terms.pop().unwrap(); - let module_src = match terms.pop().unwrap() { - Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => { - match terms.pop().unwrap() { - Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)), - _ => Err(CompilationError::InvalidModuleDecl), - } - } - Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)), - _ => Err(CompilationError::InvalidUseModuleDecl), - }?; - +fn setup_qualified_import(term: FocusedHeapRefMut) -> Result { + let module_src = setup_use_module_decl(&term)?; let mut exports = IndexSet::new(); - while let Term::Cons(_, t1, t2) = export_list { - exports.insert(setup_module_export(*t1, atom_tbl)?); - export_list = *t2; + let mut focus = term.focus + 2; + + while let HeapCellValueTag::Lis = term.heap[focus].get_tag() { + focus = term.heap[focus].get_value() as usize; + + let term = FocusedHeapRefMut { + heap: term.heap, + focus, + }; + exports.insert(setup_module_export(&term)?); + + focus = focus + 1; } - if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { + if term.heap[focus] == empty_list_as_cell!() { Ok((module_src, exports)) } else { Err(CompilationError::InvalidModuleDecl) @@ -261,18 +276,20 @@ fn setup_qualified_import( */ fn setup_meta_predicate<'a, LS: LoadState<'a>>( - mut terms: Vec, + term: FocusedHeapRefMut, loader: &mut Loader<'a, LS>, ) -> Result<(Atom, Atom, Vec), CompilationError> { - fn get_name_and_meta_specs( - name: Atom, - terms: &mut [Term], - ) -> Result<(Atom, Vec), CompilationError> { + fn get_meta_specs( + term: FocusedHeapRefMut, + arity: usize, + ) -> Result, CompilationError> { let mut meta_specs = vec![]; - for meta_spec in terms.iter_mut() { - match meta_spec { - Term::Literal(_, Literal::Atom(meta_spec)) => { + for meta_spec_loc in term.focus + 1..term.focus + arity + 1 { + read_heap_cell!(term.deref_loc(meta_spec_loc), + (HeapCellValueTag::Atom, (meta_spec, arity)) => { + debug_assert_eq!(arity, 0); + let meta_spec = match meta_spec { atom!("+") => MetaSpec::Plus, atom!("-") => MetaSpec::Minus, @@ -283,271 +300,307 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>( meta_specs.push(meta_spec); } - Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) { - Ok(n) if n <= MAX_ARITY => { - meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n)); - } - _ => { - return Err(CompilationError::InvalidMetaPredicateDecl); + (HeapCellValueTag::Fixnum, n) => { + match usize::try_from(n.get_num()) { + Ok(n) if n <= MAX_ARITY => { + meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n)); + } + _ => { + return Err(CompilationError::InvalidMetaPredicateDecl); + } } - }, + } _ => { return Err(CompilationError::InvalidMetaPredicateDecl); } - } + ); } - Ok((name, meta_specs)) + Ok(meta_specs) } - match terms.pop().unwrap() { - Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => { - let spec = terms.pop().unwrap(); - let module_name = terms.pop().unwrap(); - - match module_name { - Term::Literal(_, Literal::Atom(module_name)) => match spec { - Term::Clause(_, name, mut terms) => { - let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; - Ok((module_name, name, meta_specs)) - } - _ => Err(CompilationError::InvalidMetaPredicateDecl), - }, - _ => Err(CompilationError::InvalidMetaPredicateDecl), + read_heap_cell!(term.deref_loc(term.focus+1), + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity(); + + match (name, arity) { + (atom!(":"), 2) => { + let module_name = term.heap[s+1]; + let spec = term.heap[s+2]; + + read_heap_cell!(module_name, + (HeapCellValueTag::Atom, (module_name, arity)) => { + if arity == 0 { + read_heap_cell!(spec, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(term.heap[s]) + .get_name_and_arity(); + + let term = FocusedHeapRefMut { heap: term.heap, focus: s }; + return Ok((module_name, name, get_meta_specs(term, arity)?)); + } + _ => { + } + ); + } else { + return Err(CompilationError::InvalidMetaPredicateDecl); + } + } + _ => { + } + ); + } + _ => { + let term = FocusedHeapRefMut { heap: term.heap, focus: s }; + let module_name = loader.payload.compilation_target.module_name(); + return Ok((module_name, name, get_meta_specs(term, arity)?)); + } } + + Err(CompilationError::InvalidMetaPredicateDecl) } - Term::Clause(_, name, mut terms) => { - let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; - Ok(( - loader.payload.compilation_target.module_name(), - name, - meta_specs, - )) + _ => { + Err(CompilationError::InvalidMetaPredicateDecl) } - _ => Err(CompilationError::InvalidMetaPredicateDecl), - } + ) } pub(super) fn setup_declaration<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, - mut terms: Vec, + term: FocusedHeapRefMut, ) -> Result { - let term = terms.pop().unwrap(); + let mut focus = term.focus; - match term { - Term::Clause(_, name, mut terms) => match (name, terms.len()) { - (atom!("dynamic"), 1) => { - let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; - Ok(Declaration::Dynamic(name, arity)) - } - (atom!("module"), 2) => { - let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; - Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)) - } - (atom!("op"), 3) => { - let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; - Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)) + loop { + read_heap_cell!(term.heap[focus], + (HeapCellValueTag::Atom, (name, arity)) => { + let term = FocusedHeapRefMut { heap: term.heap, focus }; + + return match (name, arity) { + (atom!("dynamic"), 1) => { + let (name, arity) = setup_predicate_indicator(&term)?; + Ok(Declaration::Dynamic(name, arity)) + } + (atom!("module"), 2) => { + Ok(Declaration::Module(setup_module_decl(term)?)) + } + (atom!("op"), 3) => { + Ok(Declaration::Op(setup_op_decl(&term)?)) + } + (atom!("non_counted_backtracking"), 1) => { + let focus = term.nth_arg(term.focus, 1).unwrap(); + let (name, arity) = setup_predicate_indicator(&FocusedHeapRefMut { heap: term.heap, focus })?; + Ok(Declaration::NonCountedBacktracking(name, arity)) + } + (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&term)?)), + (atom!("use_module"), 2) => { + let (name, exports) = setup_qualified_import(term)?; + + Ok(Declaration::UseQualifiedModule(name, exports)) + } + (atom!("meta_predicate"), 1) => { + let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?; + Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) + } + _ => Err(CompilationError::InvalidDirective( + DirectiveError::InvalidDirective(name, arity) + )) + }; } - (atom!("non_counted_backtracking"), 1) => { - let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; - Ok(Declaration::NonCountedBacktracking(name, arity)) + (HeapCellValueTag::Str, s) => { + focus = s; } - (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)), - (atom!("use_module"), 2) => { - let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; - let (name, exports) = setup_qualified_import(terms, atom_tbl)?; - - Ok(Declaration::UseQualifiedModule(name, exports)) + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if focus != h { + focus = h; + } else { + return Err(CompilationError::InvalidDirective( + DirectiveError::ExpectedDirective(heap_loc_as_cell!(h)), + )); + } } - (atom!("meta_predicate"), 1) => { - let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?; - Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) + _ => { + return Err(CompilationError::InvalidDirective( + DirectiveError::ExpectedDirective(term.heap[focus]) + )); } - _ => Err(CompilationError::InvalidDirective( - DirectiveError::InvalidDirective(name, terms.len()), - )), - }, - other => Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(other), - )), + ); } } fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, module_name: Atom, - terms: Vec, + arity: usize, + term: &FocusedHeapRefMut, meta_specs: Vec, -) -> Vec { - let mut arg_terms = Vec::with_capacity(terms.len()); +) -> IndexMap { + let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default()); - for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) { + for (subterm_loc, meta_spec) in (term.focus + 1..term.focus + arity + 1).zip(meta_specs) { if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec { - if let Some(name) = term.name() { + if let Some(name) = term.name(subterm_loc) { if name == atom!("$call") { - arg_terms.push(term); continue; } - let arity = term.arity(); + let arity = term.arity(subterm_loc); + + struct QualifiedNameInfo { + module_name: Atom, + name: Atom, + qualified_term_loc: usize, + } fn get_qualified_name( - module_term: &Term, - qualified_term: &Term, - ) -> Option<(Atom, Atom)> { - if let Term::Literal(_, Literal::Atom(module_name)) = module_term { - if let Some(name) = qualified_term.name() { - return Some((*module_name, name)); + term: &FocusedHeapRefMut, + module_term_loc: usize, + qualified_term_loc: usize, + ) -> Option { + let (module_term_loc, _) = subterm_index(term.heap, module_term_loc); + let (qualified_term_loc, _) = subterm_index(term.heap, qualified_term_loc); + + read_heap_cell!(term.heap[module_term_loc], + (HeapCellValueTag::Atom, (module_name, arity)) => { + if arity == 0 { + if let Some(name) = term.name(qualified_term_loc) { + return Some(QualifiedNameInfo { + module_name, + name, + qualified_term_loc, + }); + } + } } - } + _ => {} + ); None } - fn identity_fn(_module_name: Atom, term: Term) -> Term { - term - } + let (subterm_loc, _) = subterm_index(term.heap, subterm_loc); - fn tag_with_module_name(module_name: Atom, term: Term) -> Term { - Term::Clause( - Cell::default(), - atom!(":"), - vec![ - Term::Literal(Cell::default(), Literal::Atom(module_name)), - term, - ], - ) - } + let subterm_arity = term.arity(subterm_loc); + let subterm_name_opt = term.name(subterm_loc); - let process_term: fn(Atom, Term) -> Term; + let (module_name, key, term_loc) = + if subterm_name_opt == Some(atom!(":")) && subterm_arity == 2 { + debug_assert_eq!(term.heap[subterm_loc].get_tag(), HeapCellValueTag::Atom); - let (module_name, key, term) = match term { - Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => { - if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1]) - { - process_term = tag_with_module_name; - ( + match get_qualified_name(term, subterm_loc + 1, subterm_loc + 2) { + Some(QualifiedNameInfo { module_name, - (name, terms[1].arity() + supp_args), - terms.pop().unwrap(), - ) - } else { - arg_terms.push(Term::Clause(cell, atom!(":"), terms)); - continue; - } - } - term => { - process_term = identity_fn; - (module_name, (name, arity + supp_args), term) - } - }; - - let term = match term { - Term::Clause(cell, name, mut terms) => { - if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { - arg_terms - .push(process_term(module_name, Term::Clause(cell, name, terms))); - - continue; - } - - let idx = loader.get_or_insert_qualified_code_index(module_name, key); - - terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx))); - process_term(module_name, Term::Clause(cell, name, terms)) - } - Term::Literal(cell, Literal::Atom(name)) => { - let idx = loader.get_or_insert_qualified_code_index(module_name, key); - - process_term( - module_name, - Term::Clause( - cell, name, - vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))], + qualified_term_loc, + }) => ( + module_name, + (name, term.arity(qualified_term_loc) + supp_args), + qualified_term_loc, ), - ) - } - term => term, - }; + None => { + continue; + } + } + } else { + (module_name, (name, arity + supp_args), subterm_loc) + }; - arg_terms.push(term); - continue; + if let Some(index_ptr) = fetch_index_ptr(term.heap, key.1, term_loc) { + index_ptrs.insert(term_loc, index_ptr); + continue; + } + + index_ptrs.insert( + term_loc, + loader.get_or_insert_qualified_code_index(module_name, key), + ); } } - - arg_terms.push(term); } - arg_terms + index_ptrs } #[inline] pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, - name: Atom, - mut terms: Vec, + key: PredicateKey, + terms: FocusedHeapRefMut, + term: HeapCellValue, call_policy: CallPolicy, -) -> QueryTerm { - if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { - // supplementary code vector indices are unnecessary for - // root-level clauses. - terms.pop(); - } +) -> QueryClause { + // supplementary code vector indices are unnecessary for + // root-level clauses. + blunt_index_ptr(terms.heap, key, terms.focus); - let mut ct = loader.get_clause_type(name, terms.len()); + let mut ct = loader.get_clause_type(key.0, key.1); if let ClauseType::Named(arity, name, idx) = ct { if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { let module_name = loader.payload.compilation_target.module_name(); - let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs); - - return QueryTerm::Clause( - Cell::default(), - ClauseType::Named(arity, name, idx), - terms, + let code_indices = + build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs); + + return QueryClause { + ct: ClauseType::Named(key.1, key.0, idx), + arity, + term, + code_indices, call_policy, - ); + }; } - ct = ClauseType::Named(arity, name, idx); + ct = ClauseType::Named(key.1, key.0, idx); } - QueryTerm::Clause(Cell::default(), ct, terms, call_policy) + QueryClause { + ct, + arity: key.1, + term, + code_indices: IndexMap::with_hasher(FxBuildHasher::default()), + call_policy, + } } #[inline] pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, + key: PredicateKey, module_name: Atom, - name: Atom, - mut terms: Vec, + terms: FocusedHeapRefMut, + term: HeapCellValue, call_policy: CallPolicy, -) -> QueryTerm { - if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { - // supplementary code vector indices are unnecessary for - // root-level clauses. - terms.pop(); - } +) -> QueryClause { + // supplementary code vector indices are unnecessary for + // root-level clauses. + blunt_index_ptr(terms.heap, key, terms.focus); - let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len()); + let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1); if let ClauseType::Named(arity, name, idx) = ct { if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { - let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs); - - return QueryTerm::Clause( - Cell::default(), - ClauseType::Named(arity, name, idx), - terms, + let code_indices = + build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs); + + return QueryClause { + ct: ClauseType::Named(key.1, key.0, idx), + arity, + term, + code_indices, call_policy, - ); + }; } - ct = ClauseType::Named(arity, name, idx); + ct = ClauseType::Named(key.1, key.0, idx); } - QueryTerm::Clause(Cell::default(), ct, terms, call_policy) + QueryClause { + ct, + arity: key.1, + term, + code_indices: IndexMap::with_hasher(FxBuildHasher::default()), + call_policy, + } } #[derive(Debug)] @@ -560,69 +613,50 @@ impl Preprocessor { Preprocessor { settings } } - fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> { - match term { - Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => { - let classifier = VariableClassifier::new(self.settings.default_call_policy()); - - let (head, var_data) = classifier.classify_fact(term)?; - Ok((Fact { head }, var_data)) - } - _ => Err(CompilationError::InadmissibleFact), + pub fn setup_fact( + &mut self, + mut term: FocusedHeap, + ) -> Result<(Fact, VarData), CompilationError> { + if term.name(term.focus).is_some() { + let classifier = VariableClassifier::new(self.settings.default_call_policy()); + let var_data = classifier.classify_fact(&mut term)?; + + Ok((Fact { term }, var_data)) + } else { + Err(CompilationError::InadmissibleFact) } } fn setup_rule<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - head: Term, - body: Term, + mut term: FocusedHeap, ) -> Result<(Rule, VarData), CompilationError> { let classifier = VariableClassifier::new(self.settings.default_call_policy()); + let (clauses, var_data) = classifier.classify_rule(loader, &mut term)?; + let head_loc = term.nth_arg(term.focus, 1).unwrap(); - let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?; - - match head { - Term::Clause(_, name, terms) => Ok(( - Rule { - head: (name, terms), - clauses, - }, - var_data, - )), - Term::Literal(_, Literal::Atom(name)) => Ok(( - Rule { - head: (name, vec![]), - clauses, - }, - var_data, - )), - _ => Err(CompilationError::InvalidRuleHead), + if term.name(head_loc).is_some() { + Ok((Rule { term, clauses }, var_data)) + } else { + Err(CompilationError::InvalidRuleHead) } } pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - term: Term, + term: FocusedHeap, ) -> Result { - match term { - Term::Clause(r, name, mut terms) => { - let is_rule = name == atom!(":-") && terms.len() == 2; - - if is_rule { - let tail = terms.pop().unwrap(); - let head = terms.pop().unwrap(); + let name = term.name(term.focus); + let arity = term.arity(term.focus); - let (rule, var_data) = self.setup_rule(loader, head, tail)?; - Ok(TopLevel::Rule(rule, var_data)) - } else { - let term = Term::Clause(r, name, terms); - let (fact, var_data) = self.setup_fact(term)?; - Ok(TopLevel::Fact(fact, var_data)) - } + match (name, arity) { + (Some(atom!(":-")), 2) => { + let (rule, var_data) = self.setup_rule(loader, term)?; + Ok(TopLevel::Rule(rule, var_data)) } - term => { + _ => { let (fact, var_data) = self.setup_fact(term)?; Ok(TopLevel::Fact(fact, var_data)) } diff --git a/src/machine/raw_block.rs b/src/machine/raw_block.rs index 1b5d79fb..7e85eff4 100644 --- a/src/machine/raw_block.rs +++ b/src/machine/raw_block.rs @@ -24,12 +24,7 @@ pub(crate) struct RawBlock { impl RawBlock { pub(crate) fn new() -> Self { - let mut block = RawBlock { - size: 0, - base: ptr::null(), - top: ptr::null(), - _marker: PhantomData, - }; + let mut block = Self::uninitialized(); unsafe { block.grow(); @@ -38,6 +33,15 @@ impl RawBlock { block } + pub(crate) fn uninitialized() -> Self { + Self { + size: 0, + base: ptr::null(), + top: ptr::null(), + _marker: PhantomData, + } + } + unsafe fn init_at_size(&mut self, cap: usize) { let layout = alloc::Layout::from_size_align_unchecked(cap, T::align()); diff --git a/src/machine/stack.rs b/src/machine/stack.rs index 210a7cac..bf330813 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -168,6 +168,13 @@ impl Stack { } } + pub(crate) fn uninitialized() -> Self { + Stack { + buf: RawBlock::empty_block(), + _marker: PhantomData, + } + } + #[inline(always)] unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 { loop { diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 678b2297..25b2d725 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1880,7 +1880,7 @@ impl MachineState { ) -> Result { match stream.peek_char() { None => Ok(stream), // empty stream is handled gracefully by Lexer::eof - Some(Err(e)) => Err(ParserError::IO(e)), + Some(Err(e)) => Err(ParserError::IO(e, ParserErrorSrc::default())), Some(Ok(c)) => { if c == '\u{feff}' { // skip UTF-8 BOM diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index cc39cba5..5505f68e 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -28,7 +28,7 @@ use crate::machine::stack::*; use crate::machine::streams::*; use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC}; use crate::parser::char_reader::*; -use crate::parser::dashu::Integer; +use crate::parser::dashu::{Integer, Rational}; use crate::read::*; use crate::types::*; use rand::rngs::StdRng; @@ -824,25 +824,30 @@ impl MachineState { ) { let mut seen_set = IndexSet::new(); - { - let mut iter = - stackful_post_order_iter::(&mut self.heap, &mut self.stack, term); + let outcome = if term.is_ref() { + { + let mut iter = stackful_post_order_iter::( + &mut self.heap, &mut self.stack, term.get_value() as usize, + ); - while let Some(value) = iter.next() { - if iter.parent_stack_len() >= max_depth { - iter.pop_stack(); - continue; - } + while let Some(value) = iter.next() { + if iter.parent_stack_len() >= max_depth { + iter.pop_stack(); + continue; + } - let value = unmark_cell_bits!(value); + let value = unmark_cell_bits!(value); - if value.is_var() { - seen_set.insert(value); + if value.is_var() { + seen_set.insert(value); + } } } - } - let outcome = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter(),)); + heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter())) + } else { + empty_list_as_cell!() + }; unify_fn!(*self, list_of_vars, outcome); } @@ -942,36 +947,51 @@ impl MachineState { tokens.reverse(); match parser.read_term(&op_dir, Tokens::Provided(tokens)) { - Err(err) => { - let err = self.syntax_error(err); - return Err(self.error_form(err, stub_gen())); - } - Ok(Term::Literal(_, Literal::Rational(n))) => { - self.unify_rational(n, nx); - } - Ok(Term::Literal(_, Literal::Float(n))) => { - self.unify_f64(n.as_ptr(), nx); - } - Ok(Term::Literal(_, Literal::Integer(n))) => { - self.unify_big_int(n, nx); - } - Ok(Term::Literal(_, Literal::Fixnum(n))) => { - self.unify_fixnum(n, nx); - } - _ => { - let err = ParserError::ParseBigInt(0, 0); - let err = self.syntax_error(err); + Ok(term) => { + let mut error_gen = || { + let e = ParserError::ParseBigInt(ParserErrorSrc::default()); + let e = self.syntax_error(e); + + return Err(self.error_form(e, stub_gen())); + }; - return Err(self.error_form(err, stub_gen())); + read_heap_cell!(term.heap[term.focus], + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::Rational, n) => { + self.unify_rational(n, nx); + } + (ArenaHeaderTag::Integer, n) => { + self.unify_big_int(n, nx); + } + _ => { + return error_gen(); + } + ) + } + (HeapCellValueTag::F64, n) => { + self.unify_f64(n, nx); + } + (HeapCellValueTag::Fixnum, n) => { + self.unify_fixnum(n, nx); + } + _ => { + return error_gen(); + } + ); + } + Err(e) => { + let e = self.syntax_error(e); + return Err(self.error_form(e, stub_gen())); } } break; } Ok(c) => { - let (line_num, col_num) = (lexer.line_num, lexer.col_num); + let err_src = lexer.loc_to_err_src(); - let err = ParserError::UnexpectedChar(c, line_num, col_num); + let err = ParserError::UnexpectedChar(c, err_src); let err = self.syntax_error(err); return Err(self.error_form(err, stub_gen())); @@ -1440,6 +1460,8 @@ impl Machine { } }; + // println!("(fast) calling {}/{}", name.as_str(), arity); + if let Some(code_index) = index_cell { if !code_index.is_undefined() { load_registers(&mut self.machine_st, goal, goal_arity); @@ -1599,12 +1621,12 @@ impl Machine { let vars: Vec<_> = vars .union(&result.supp_vars) // difference + union does not cancel. - .map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value())))) + .cloned() .collect(); let helper_clause_loc = self.code.len(); - match self.compile_standalone_clause(temp_v!(1), &vars) { + match self.compile_standalone_clause(temp_v!(1), vars) { Err(e) => { let err = self.machine_st.session_error(e); let stub = functor_stub(atom!("call"), result.key.1); @@ -3572,7 +3594,9 @@ impl Machine { } Some(Err(e)) => { let stub = functor_stub(atom!("$get_n_chars"), 3); - let err = self.machine_st.session_error(SessionError::from(e)); + let err = self.machine_st.session_error(SessionError::from( + ParserError::IO(e, ParserErrorSrc::default()), + )); return Err(self.machine_st.error_form(err, stub)); } @@ -6266,10 +6290,10 @@ impl Machine { } #[inline(always)] - fn read_term_and_write_to_heap( + fn read_term_from_atom( &mut self, atom_or_string: AtomOrString, - ) -> Result, MachineStub> { + ) -> Result, MachineStub> { let string = match atom_or_string { AtomOrString::Atom(atom!("[]")) => "".to_owned(), _ => atom_or_string.into(), @@ -6279,15 +6303,12 @@ impl Machine { let mut parser = Parser::new(chars, &mut self.machine_st); let op_dir = CompositeOpDir::new(&self.indices.op_dir, None); - let term_write_result = parser + let term = parser .read_term(&op_dir, Tokens::Default) - .map_err(|err| error_after_read_term(err, 0, &parser)) - .and_then(|term| { - write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl) - }); + .map_err(|e| error_after_read_term(e, 0)); - match term_write_result { - Ok(term_write_result) => Ok(Some(term_write_result)), + match term { + Ok(term) => Ok(Some(term)), Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => { let value = self.machine_st.registers[2]; self.machine_st.unify_atom(atom!("end_of_file"), value); @@ -6305,42 +6326,50 @@ impl Machine { #[inline(always)] pub(crate) fn read_from_chars(&mut self) -> CallResult { - if let Some(atom_or_string) = self + let atom_or_string = self .machine_st .value_to_str_like(self.machine_st.registers[1]) - { - if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? { - let result = heap_loc_as_cell!(term_write_result.heap_loc); - let var = self.deref_register(2).as_var().unwrap(); + .unwrap(); - self.machine_st.bind(var, result); - } + if let Some(mut term) = self.read_term_from_atom(atom_or_string)? { + let heap_len = self.machine_st.heap.len(); - Ok(()) - } else { - unreachable!() + self.machine_st.heap.extend( + copy_and_align_iter(term.heap.drain(..), 0, heap_len as i64), + ); + + let result = heap_loc_as_cell!(heap_len + term.focus); + let var = self.deref_register(2).as_var().unwrap(); + + self.machine_st.bind(var, result); } + + Ok(()) } #[inline(always)] pub(crate) fn read_term_from_chars(&mut self) -> CallResult { - if let Some(atom_or_string) = self + let atom_or_string = self .machine_st .value_to_str_like(self.machine_st.registers[1]) - { - if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? { - self.machine_st.read_term_body(term_write_result) - } else { - if !self.machine_st.fail { - // wrote end_of_file term in this case. - self.machine_st.write_read_term_options(vec![], vec![])?; - } + .unwrap(); - Ok(()) - } - } else { - unreachable!() - } + let string = match atom_or_string { + AtomOrString::Atom(atom!("[]")) => "".to_owned(), + _ => atom_or_string.into(), + }; + + let chars = CharReader::new(ByteStream::from_string(string)); + let term_write_result = self.machine_st.read(chars, &self.indices.op_dir) + .map(|(term, _)| term.to_machine_heap(&mut self.machine_st)) + .map_err(|e| { + let e = self.machine_st.session_error(SessionError::from(e)); + let stub = functor_stub(atom!("read_term_from_chars"), 3); + + self.machine_st.error_form(e, stub) + })?; + + self.machine_st.read_term_body(term_write_result) } #[inline(always)] @@ -8095,8 +8124,13 @@ impl Machine { match devour_whitespace(&mut parser) { Ok(false) => { - // not at EOF. + // not at EOF ... stream.add_lines_read(parser.lines_read()); + + // ... unless we are. + if stream.at_end_of_stream() { + self.machine_st.fail = true; + } } Ok(true) => { stream.add_lines_read(parser.lines_read()); diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs index 686a8c19..58c6e2c8 100644 --- a/src/machine/term_stream.rs +++ b/src/machine/term_stream.rs @@ -20,11 +20,11 @@ pub struct LoadStatePayload { pub(super) module_op_exports: ModuleOpExports, pub(super) non_counted_bt_preds: IndexSet, pub(super) predicates: PredicateQueue, - pub(super) clause_clauses: Vec<(Term, Term)>, + pub(super) clause_clauses: Vec, } pub trait TermStream: Sized { - fn next(&mut self, op_dir: &CompositeOpDir) -> Result; + fn next(&mut self, op_dir: &CompositeOpDir) -> Result; fn eof(&mut self) -> Result; fn listing_src(&self) -> &ListingSource; } @@ -52,7 +52,7 @@ impl<'a> BootstrappingTermStream<'a> { impl<'a> TermStream for BootstrappingTermStream<'a> { #[inline] - fn next(&mut self, op_dir: &CompositeOpDir) -> Result { + fn next(&mut self, op_dir: &CompositeOpDir) -> Result { self.parser.reset(); self.parser .read_term(op_dir, Tokens::Default) @@ -72,7 +72,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> { } pub struct LiveTermStream { - pub(super) term_queue: VecDeque, + pub(super) term_queue: VecDeque, pub(super) listing_src: ListingSource, } @@ -108,7 +108,7 @@ impl LoadStatePayload { impl TermStream for LiveTermStream { #[inline] - fn next(&mut self, _: &CompositeOpDir) -> Result { + fn next(&mut self, _: &CompositeOpDir) -> Result { Ok(self.term_queue.pop_front().unwrap()) } @@ -126,8 +126,8 @@ impl TermStream for LiveTermStream { pub struct InlineTermStream {} impl TermStream for InlineTermStream { - fn next(&mut self, _: &CompositeOpDir) -> Result { - Err(CompilationError::from(ParserError::unexpected_eof())) + fn next(&mut self, _: &CompositeOpDir) -> Result { + Err(CompilationError::from(ParserError::unexpected_eof(ParserErrorSrc::default()))) } fn eof(&mut self) -> Result { diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 2e9dd54b..05ba4749 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -705,13 +705,16 @@ fn bind_with_occurs_check(unifier: &mut U, r: Ref, value: HeapCellVa let mut occurs_triggered = false; - if !value.is_constant() { - let machine_st: &mut MachineState = unifier.deref_mut(); + let machine_st: &mut MachineState = unifier.deref_mut(); + let value = machine_st.store(MachineState::deref(machine_st, value)); + + if value.is_ref() && !value.is_stack_var() { + let root_loc = value.get_value() as usize; for cell in stackful_preorder_iter::( &mut machine_st.heap, &mut machine_st.stack, - value, + root_loc, // value, ) { let cell = unmark_cell_bits!(cell); diff --git a/src/macros.rs b/src/macros.rs index 4b4b51f9..d78a9fea 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -346,6 +346,11 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; + ($cell:ident, Atom, (_, $arity:ident), $code:expr) => {{ + let $arity = cell_as_atom_cell!($cell).get_arity(); + #[allow(unused_braces)] + $code + }}; ($cell:ident, PStr, $atom:ident, $code:expr) => {{ let $atom = cell_as_atom!($cell); #[allow(unused_braces)] diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 9a400c36..c080b7ea 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -2,15 +2,19 @@ use crate::arena::*; use crate::atom_table::*; +use crate::forms::PredicateKey; +use crate::machine::copier::*; +use crate::machine::heap::*; use crate::machine::machine_indices::*; -use crate::parser::char_reader::*; -use crate::types::HeapCellValueTag; +use crate::machine::machine_state::*; +use crate::types::*; -use std::cell::{Cell, Ref, RefCell, RefMut}; +use std::cell::{Ref, RefCell, RefMut}; +use std::collections::VecDeque; use std::fmt; use std::hash::{Hash, Hasher}; use std::io::{Error as IOError, ErrorKind}; -use std::ops::{Deref, Neg}; +use std::ops::{Deref, Neg, RangeBounds}; use std::rc::Rc; use std::sync::Arc; use std::vec::Vec; @@ -426,35 +430,42 @@ pub enum ArithmeticError { UninstantiatedVar, } -#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Default)] +pub struct ParserErrorSrc { + pub col_num: usize, + pub line_num: usize, +} + #[derive(Debug)] pub enum ParserError { - BackQuotedString(usize, usize), - IO(IOError), - IncompleteReduction(usize, usize), - InfiniteFloat(usize, usize), - InvalidSingleQuotedCharacter(char), - LexicalError(lexical::Error), - MissingQuote(usize, usize), - NonPrologChar(usize, usize), - ParseBigInt(usize, usize), - UnexpectedChar(char, usize, usize), + BackQuotedString(ParserErrorSrc), + IO(IOError, ParserErrorSrc), + IncompleteReduction(ParserErrorSrc), + InfiniteFloat(ParserErrorSrc), + InvalidSingleQuotedCharacter(char, ParserErrorSrc), + LexicalError(lexical::Error, ParserErrorSrc), + MissingQuote(ParserErrorSrc), + NonPrologChar(ParserErrorSrc), + ParseBigInt(ParserErrorSrc), + UnexpectedChar(char, ParserErrorSrc), // UnexpectedEOF, - Utf8Error(usize, usize), + Utf8Error(ParserErrorSrc), } impl ParserError { - pub fn line_and_col_num(&self) -> Option<(usize, usize)> { + pub fn err_src(&self) -> ParserErrorSrc { match self { - &ParserError::BackQuotedString(line_num, col_num) - | &ParserError::IncompleteReduction(line_num, col_num) - | &ParserError::InfiniteFloat(line_num, col_num) - | &ParserError::MissingQuote(line_num, col_num) - | &ParserError::NonPrologChar(line_num, col_num) - | &ParserError::ParseBigInt(line_num, col_num) - | &ParserError::UnexpectedChar(_, line_num, col_num) - | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)), - _ => None, + &ParserError::BackQuotedString(err_src) + | &ParserError::IO(_, err_src) + | &ParserError::IncompleteReduction(err_src) + | &ParserError::InfiniteFloat(err_src) + | &ParserError::InvalidSingleQuotedCharacter(_, err_src) + | &ParserError::LexicalError(_, err_src) + | &ParserError::MissingQuote(err_src) + | &ParserError::NonPrologChar(err_src) + | &ParserError::ParseBigInt(err_src) + | &ParserError::UnexpectedChar(_, err_src) + | &ParserError::Utf8Error(err_src) => err_src, } } @@ -468,14 +479,14 @@ impl ParserError { ParserError::InfiniteFloat(..) => { atom!("infinite_float") } - ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => { + ParserError::IO(e, _) if e.kind() == ErrorKind::UnexpectedEof => { atom!("unexpected_end_of_file") } - ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => { + ParserError::IO(e, _) if e.kind() == ErrorKind::InvalidData => { atom!("invalid_data") } - ParserError::IO(_) => atom!("input_output_error"), - ParserError::LexicalError(_) => atom!("lexical_error"), + ParserError::IO(..) => atom!("input_output_error"), + ParserError::LexicalError(..) => atom!("lexical_error"), ParserError::MissingQuote(..) => atom!("missing_quote"), ParserError::NonPrologChar(..) => atom!("non_prolog_character"), ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"), @@ -485,23 +496,23 @@ impl ParserError { } #[inline] - pub fn unexpected_eof() -> Self { - ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof)) + pub fn unexpected_eof(err_src: ParserErrorSrc) -> Self { + ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof), err_src) } #[inline] pub fn is_unexpected_eof(&self) -> bool { - if let ParserError::IO(e) = self { + if let ParserError::IO(e, _) = self { e.kind() == ErrorKind::UnexpectedEof } else { false } } } - +/* impl From for ParserError { - fn from(e: lexical::Error) -> ParserError { - ParserError::LexicalError(e) + fn from((e, err_src): (lexical::Error, ParserErrorSrc)) -> ParserError { + ParserError::LexicalError(e, err_src) } } @@ -520,7 +531,7 @@ impl From<&IOError> for ParserError { } } } - +*/ #[derive(Debug, Clone, Copy)] pub struct CompositeOpDir<'a, 'b> { pub primary_op_dir: Option<&'b OpDir>, @@ -694,6 +705,14 @@ impl Deref for VarPtr { } 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() @@ -706,7 +725,7 @@ impl VarPtr { pub(crate) fn to_var_num(&self) -> Option { match *self.borrow() { - Var::Generated(var_num) => Some(var_num), + Var::Generated { var_num, .. } => Some(var_num), _ => None, } } @@ -740,7 +759,8 @@ impl From<&str> for VarPtr { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Var { - Generated(usize), + Anon, + Generated { is_anon: bool, var_num: usize }, InSitu(usize), Named(String), } @@ -764,12 +784,34 @@ impl Var { #[inline(always)] pub fn to_string(&self) -> String { match self { - Var::InSitu(n) | Var::Generated(n) => format!("_{}", n), + Var::Anon => "_".to_owned(), + Var::InSitu(var_num) | Var::Generated { var_num, .. } => format!("_{}", var_num), Var::Named(value) => value.to_owned(), } } } +pub(crate) fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) { + let subterm = heap[subterm_loc]; + + if subterm.is_ref() { + let subterm = heap_bound_deref(heap, subterm); + let subterm_loc = subterm.get_value() as usize; + let subterm = heap_bound_store(heap, subterm); + + let subterm_loc = if subterm.is_ref() { + subterm.get_value() as usize + } else { + subterm_loc + }; + + (subterm_loc, subterm) + } else { + (subterm_loc, subterm) + } +} + +/* #[derive(Debug, Clone)] pub enum Term { AnonVar, @@ -836,3 +878,441 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec { terms.push(term); terms } + */ + +pub(crate) fn fetch_index_ptr( + heap: &[HeapCellValue], + arity: usize, + term_loc: usize, +) -> Option { + if term_loc + arity + 1 >= heap.len() { + return None; + } + + read_heap_cell!(heap[term_loc + arity + 1], + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::IndexPtr, ptr) => { + return Some(CodeIndex::from(ptr)); + } + _ => {} + ); + } + _ => {} + ); + + None +} + +pub(crate) fn blunt_index_ptr( + heap: &mut [HeapCellValue], + key: PredicateKey, + term_loc: usize, +) -> bool { + if fetch_index_ptr(heap, key.1, term_loc).is_some() { + heap[term_loc] = atom_as_cell!(key.0, key.1); + true + } else { + false + } +} + +pub(crate) fn unfold_by_str_once( + heap: &mut [HeapCellValue], + start_term: HeapCellValue, + atom: Atom, +) -> Option { + let start_term = heap_bound_store( + heap, + heap_bound_deref(heap, start_term), + ); + + if let HeapCellValueTag::Str = start_term.get_tag() { + let s = start_term.get_value() as usize; + + let (s_atom, s_arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); + blunt_index_ptr(heap, (s_atom, s_arity), s); + + if (s_atom, s_arity) == (atom, 2) { + return Some(s+1); + } + } + + None +} + +pub fn unfold_by_str( + heap: &mut [HeapCellValue], + mut start_term: HeapCellValue, + atom: Atom, +) -> Vec { + let mut terms = vec![]; + start_term = heap_bound_store(heap, heap_bound_deref(heap, start_term)); + + while let Some(fst_loc) = unfold_by_str_once(heap, start_term, atom) { + let (_, snd) = subterm_index(heap, fst_loc + 1); + let (_, fst) = subterm_index(heap, fst_loc); + terms.push(fst); + start_term = snd; + } + + terms +} + +/* +pub fn unfold_by_str_locs( + heap: &mut [HeapCellValue], + mut term_loc: usize, + atom: Atom, +) -> Vec<(HeapCellValue, usize)> { + let mut terms = vec![]; + let mut current_term = heap_bound_store( + heap, + heap_bound_deref(heap, heap[term_loc]), + ); + + while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) { + (term_loc, current_term) = subterm_index(heap, fst_loc + 1); + let (fst_loc, fst) = subterm_index(heap, fst_loc); + terms.push((fst, fst_loc)); + } + + terms.push((current_term, term_loc)); + terms +} +*/ + +pub fn unfold_by_str_locs( + heap: &mut [HeapCellValue], + mut term_loc: usize, + atom: Atom, +) -> Vec<(HeapCellValue, usize)> { + let mut terms = vec![]; + let mut current_term = heap[term_loc]; + + while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) { + term_loc = fst_loc+1; + current_term = heap[term_loc]; + let fst = heap[fst_loc]; + terms.push((fst, fst_loc)); + } + + terms.push((current_term, term_loc)); + terms +} + +pub fn term_name(heap: &[HeapCellValue], mut term_loc: usize) -> Option { + loop { + read_heap_cell!(heap[term_loc], + (HeapCellValueTag::Atom, (name, _arity)) => { + return Some(name); + } + (HeapCellValueTag::Str, s) => { + term_loc = s; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h != term_loc { + term_loc = h; + } else { + return None; + } + } + _ => { + return None; + } + ); + } +} + +pub fn term_arity(heap: &[HeapCellValue], mut term_loc: usize) -> usize { + loop { + read_heap_cell!(heap[term_loc], + (HeapCellValueTag::Atom, (_name, arity)) => { + return arity; + } + (HeapCellValueTag::Str, s) => { + term_loc = s; + } + (HeapCellValueTag::Lis) => { + return 2; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h != term_loc { + term_loc = h; + } else { + return 0; + } + } + _ => { + return 0; + } + ); + } +} + +pub fn var_locs_from_iter>(iter: I) -> VarLocs { + let mut occurrence_set: IndexMap = + IndexMap::with_hasher(FxBuildHasher::default()); + + for term in iter { + if term.is_var() { + let var_count = occurrence_set.entry(term).or_insert(0); + *var_count += 1; + } + } + + 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() + }; + + (key, queue) + }) + .collect() + ) +} + +/* +pub fn term_deref(heap: &[HeapCellValue], mut term_loc: usize) -> HeapCellValue { + loop { + read_heap_cell!(heap[term_loc], + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h != term_loc { + term_loc = h; + } else { + return heap[h]; + } + } + _ => { + return heap[term_loc]; + } + ) + } +} +*/ + +pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Option { + loop { + read_heap_cell!(heap[term_loc], + (HeapCellValueTag::Str, s) => { + return if cell_as_atom_cell!(heap[s]).get_arity() >= n { + Some(s+n) + } else { + None + }; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + return if arity >= n { + Some(term_loc + n) + } else { + None + }; + } + (HeapCellValueTag::Lis, l) => { + return if 1 <= n && n <= 2 { + Some(l+n-1) + } else if n == 0 { + Some(term_loc) + } else { + None + }; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h != term_loc { + term_loc = h; + } else { + return None; + } + } + _ => { + return None; + } + ); + } +} + +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); + } +} + +#[derive(Debug)] +pub struct FocusedHeap { + pub heap: Vec, + pub focus: usize, + pub var_locs: VarLocs, +} + +impl FocusedHeap { + pub fn empty() -> Self { + Self { + heap: vec![], + focus: 0, + var_locs: VarLocs::default(), + } + } + + pub fn copy_term_from_machine_heap( + &mut self, + machine_st: &mut MachineState, + cell: HeapCellValue, + ) { + let hb = machine_st.heap.len(); + + copy_term( + CopyBallTerm::new( + &mut machine_st.attr_var_init.attr_var_queue, + &mut machine_st.stack, + &mut machine_st.heap, + &mut self.heap, + ), + cell, + AttrVarPolicy::DeepCopy, + ); + + for cell in self.heap.iter_mut() { + *cell = *cell - hb; + } + } + + pub fn as_ref_mut(&mut self, focus: usize) -> FocusedHeapRefMut { + FocusedHeapRefMut { + heap: &mut self.heap, + focus, + // var_locs: &self.var_locs, + } + } + + pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue { + use crate::machine::heap::*; + + let cell = self.heap[term_loc]; + heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell)) + } + + pub fn name(&self, term_loc: usize) -> Option { + term_name(&self.heap, term_loc) + } + + pub fn arity(&self, term_loc: usize) -> usize { + term_arity(&self.heap, term_loc) + } + + pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option { + term_nth_arg(&self.heap, term_loc, n) + } +} + +pub struct FocusedHeapRefMut<'a> { + pub heap: &'a mut Vec, + pub focus: usize, +} + +impl<'a> FocusedHeapRefMut<'a> { + pub fn name(&self, term_loc: usize) -> Option { + term_name(&self.heap, term_loc) + } + + pub fn arity(&self, term_loc: usize) -> usize { + term_arity(&self.heap, term_loc) + } + + pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue { + use crate::machine::heap::*; + + let cell = self.heap[term_loc]; + heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell)) + } + + pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option { + term_nth_arg(self.heap, term_loc, n) + } + + pub fn from_cell(heap: &'a mut Vec, cell: HeapCellValue) -> Self { + let focus = read_heap_cell!(cell, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + h + } + _ => { + let h = heap.len(); + heap.push(cell); + + h + } + ); + + Self { heap, focus } + } +} diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 75700f38..556f69ed 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -1,5 +1,8 @@ use crate::arena::F64Ptr; use crate::arena::TypedArenaPtr; +use lexical::{FromLexicalLossy, parse_lossy}; + +use crate::arena::ArenaAllocated; use crate::atom_table::*; pub use crate::machine::machine_state::*; use crate::parser::ast::*; @@ -130,17 +133,22 @@ impl<'a, R: CharRead> Lexer<'a, R> { pub fn lookahead_char(&mut self) -> Result { match self.reader.peek_char() { Some(Ok(c)) => Ok(c), - _ => Err(ParserError::unexpected_eof()), + _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())), } } pub fn read_char(&mut self) -> Result { match self.reader.read_char() { Some(Ok(c)) => Ok(c), - _ => Err(ParserError::unexpected_eof()), + _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())), } } + #[inline] + pub fn loc_to_err_src(&self) -> ParserErrorSrc { + ParserErrorSrc { line_num: self.line_num, col_num: self.col_num } + } + #[inline(always)] fn return_char(&mut self, c: char) { self.reader.put_back_char(c); @@ -212,10 +220,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { match comment_loop() { Err(e) if e.is_unexpected_eof() => { - return Err(ParserError::IncompleteReduction( - self.line_num, - self.col_num, - )); + return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); } Err(e) => { return Err(e); @@ -227,7 +232,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { self.skip_char(c); Ok(true) } else { - Err(ParserError::NonPrologChar(self.line_num, self.col_num)) + Err(ParserError::NonPrologChar(self.loc_to_err_src())) } } else { self.return_char('/'); @@ -244,7 +249,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { if !back_quote_char!(c2) { self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) } else { self.skip_char(c2); Ok(c2) @@ -269,7 +274,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { Ok(None) } else { self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) } } else { self.get_back_quoted_char().map(Some) @@ -291,10 +296,10 @@ impl<'a, R: CharRead> Lexer<'a, R> { self.skip_char(c); Ok(token) } else { - Err(ParserError::MissingQuote(self.line_num, self.col_num)) + Err(ParserError::MissingQuote(self.loc_to_err_src())) } } else { - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) } } @@ -325,7 +330,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { if !single_quote_char!(c2) { self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) } else { self.skip_char(c2); Ok(c2) @@ -366,7 +371,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { if !double_quote_char!(c2) { self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) } else { self.skip_char(c2); Ok(c2) @@ -390,7 +395,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { 't' => '\t', 'n' => '\n', 'r' => '\r', - c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)), + c => return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())), }; self.skip_char(c); @@ -408,10 +413,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { if hexadecimal_digit_char!(c) { self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16) } else { - Err(ParserError::IncompleteReduction( - self.line_num, - self.col_num, - )) + Err(ParserError::IncompleteReduction(self.loc_to_err_src())) } } @@ -437,17 +439,14 @@ impl<'a, R: CharRead> Lexer<'a, R> { if backslash_char!(c) { self.skip_char(c); u32::from_str_radix(&token, radix).map_or_else( - |_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)), + |_| Err(ParserError::ParseBigInt(self.loc_to_err_src())), |n| { char::try_from(n) - .map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num)) + .map_err(|_| ParserError::Utf8Error(self.loc_to_err_src())) }, ) } else { - Err(ParserError::IncompleteReduction( - self.line_num, - self.col_num, - )) + Err(ParserError::IncompleteReduction(self.loc_to_err_src())) } } @@ -459,7 +458,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { Ok(c) } else { if !backslash_char!(c) { - return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)); + return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())); } self.skip_char(c); @@ -490,7 +489,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { self.skip_char(c); Ok(token) } else { - Err(ParserError::MissingQuote(self.line_num, self.col_num)) + Err(ParserError::MissingQuote(self.loc_to_err_src())) } } @@ -515,7 +514,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { .map(NumberToken::Number) } else { self.return_char(start); - Err(ParserError::ParseBigInt(self.line_num, self.col_num)) + Err(ParserError::ParseBigInt(self.loc_to_err_src())) } } @@ -540,7 +539,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { .map(NumberToken::Number) } else { self.return_char(start); - Err(ParserError::ParseBigInt(self.line_num, self.col_num)) + Err(ParserError::ParseBigInt(self.loc_to_err_src())) } } @@ -565,7 +564,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { .map(NumberToken::Number) } else { self.return_char(start); - Err(ParserError::ParseBigInt(self.line_num, self.col_num)) + Err(ParserError::ParseBigInt(self.loc_to_err_src())) } } @@ -636,11 +635,11 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } } else { - return Err(ParserError::InvalidSingleQuotedCharacter(c)); + return Err(ParserError::InvalidSingleQuotedCharacter(c, self.loc_to_err_src())); } } else { match self.get_back_quoted_string() { - Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)), + Ok(_) => return Err(ParserError::BackQuotedString(self.loc_to_err_src())), Err(e) => return Err(e), } } @@ -655,10 +654,17 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } - fn vacate_with_float(&mut self, mut token: String) -> Result { + fn parse_lossy_wrapper(&self, token: String) -> Result { + match parse_lossy::(token.as_bytes()) { + Ok(n) => Ok(n), + Err(e) => return Err(ParserError::LexicalError(e, self.loc_to_err_src())), + } + } + + fn vacate_with_float(&mut self, mut token: String) -> Result { self.return_char(token.pop().unwrap()); - let n = parse_float_lossy(&token)?; - Ok(Number::Float(float_alloc!(n, self.machine_st.arena))) + let n = self.parse_lossy_wrapper::(token)?; + Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena)))) } fn skip_underscore_in_number(&mut self) -> Result { @@ -672,7 +678,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { if decimal_digit_char!(c) { Ok(c) } else { - Err(ParserError::ParseBigInt(self.line_num, self.col_num)) + Err(ParserError::ParseBigInt(self.loc_to_err_src())) } } else { Ok(c) @@ -1038,7 +1044,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { } if c == '\u{0}' { - return Err(ParserError::unexpected_eof()); + return Err(ParserError::unexpected_eof(self.loc_to_err_src())); } self.name_token(c) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index dd7b007b..bffca39b 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -3,17 +3,22 @@ use dashu::Rational; use crate::arena::*; use crate::atom_table::*; +use crate::machine::heap::{heap_bound_deref, heap_bound_store}; +use crate::machine::partial_string::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::lexer::*; +use crate::types::*; + +use fxhash::FxBuildHasher; +use indexmap::IndexMap; -use std::cell::Cell; use std::mem; use std::ops::Neg; #[derive(Debug, Clone, Copy, PartialEq)] enum TokenType { - Term, + Term { heap_loc: HeapCellValue }, Open, OpenCT, OpenList, // '[' @@ -26,6 +31,23 @@ enum TokenType { End, } +impl TokenType { + fn sep_to_atom(self) -> Option { + match self { + TokenType::Open | TokenType::OpenCT => Some(atom!("(")), + TokenType::Close => Some(atom!(")")), + TokenType::OpenList => Some(atom!("[")), + TokenType::CloseList => Some(atom!("]")), + TokenType::OpenCurly => Some(atom!("{")), + TokenType::CloseCurly => Some(atom!("}")), + TokenType::HeadTailSeparator => Some(atom!("|")), + TokenType::Comma => Some(atom!(",")), + TokenType::End => Some(atom!(".")), + _ => None, + } + } +} + /* Specifies whether the token sequence should be read from the lexer or provided via the Provided variant. @@ -61,80 +83,6 @@ struct TokenDesc { unfold_bounds: usize, } -pub(crate) fn as_partial_string( - head: Term, - mut tail: Term, -) -> Result<(String, Option>), Term> { - let mut string = match &head { - Term::Literal(_, Literal::Atom(atom)) => { - if let Some(c) = atom.as_char() { - c.to_string() - } else { - return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); - } - } - Term::Literal(_, Literal::Char(c)) => c.to_string(), - _ => { - return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); - } - }; - - let mut orig_tail = Box::new(tail); - let mut tail_ref = &mut orig_tail; - - loop { - match &mut **tail_ref { - Term::Cons(_, prev, succ) => { - match prev.as_ref() { - Term::Literal(_, Literal::Atom(atom)) => { - if let Some(c) = atom.as_char() { - string.push(c); - } else { - return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail)); - } - } - Term::Literal(_, Literal::Char(c)) => { - string.push(*c); - } - _ => { - tail = Term::Cons( - Cell::default(), - Box::new((**prev).clone()), - Box::new((**succ).clone()), - ); - break; - } - } - - tail_ref = succ; - } - Term::PartialString(_, pstr, tail) => { - string += pstr; - tail_ref = tail; - } - Term::CompleteString(_, cstr) => { - string += &*cstr.as_str(); - tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); - break; - } - tail_ref => { - tail = mem::replace(tail_ref, Term::AnonVar); - break; - } - } - } - - match &tail { - Term::AnonVar | Term::Var(..) => Ok((string, Some(Box::new(tail)))), - Term::Literal(_, Literal::Atom(atom!("[]"))) => Ok((string, None)), - Term::Literal(_, Literal::String(tail)) => { - string += &*tail.as_str(); - Ok((string, None)) - } - _ => Ok((string, Some(Box::new(tail)))), - } -} - pub fn get_op_desc(name: Atom, op_dir: &CompositeOpDir) -> Option { let mut op_desc = CompositeOpDesc { pre: 0, @@ -234,7 +182,9 @@ pub struct Parser<'a, R> { pub lexer: Lexer<'a, R>, tokens: Vec, stack: Vec, - terms: Vec, + terms: Vec, + var_locs: VarLocs, + var_names_to_locs: VarNamesToLocs, } fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> { @@ -251,10 +201,7 @@ fn read_tokens(lexer: &mut Lexer) -> Result, ParserEr } } Err(e) if e.is_unexpected_eof() && !tokens.is_empty() => { - return Err(ParserError::IncompleteReduction( - lexer.line_num, - lexer.col_num, - )); + return Err(ParserError::IncompleteReduction(lexer.loc_to_err_src())); } Err(e) => { return Err(e); @@ -267,14 +214,7 @@ fn read_tokens(lexer: &mut Lexer) -> Result, ParserEr Ok(tokens) } -fn atomize_term(atom_tbl: &AtomTable, term: &Term) -> Option { - match term { - Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c), - _ => None, - } -} - -fn atomize_constant(atom_tbl: &AtomTable, c: Literal) -> Option { +fn atomize_literal(atom_tbl: &AtomTable, c: Literal) -> Option { match c { Literal::Atom(ref name) => Some(*name), Literal::Char(c) => Some(AtomTable::build_with(atom_tbl, &c.to_string())), @@ -282,6 +222,102 @@ fn atomize_constant(atom_tbl: &AtomTable, c: Literal) -> Option { } } +pub(crate) fn as_partial_string( + heap: &[HeapCellValue], + head: HeapCellValue, + tail: HeapCellValue, +) -> Option<(String, Option)> { + let head = heap_bound_store(heap, heap_bound_deref(heap, head)); + let mut tail = heap_bound_store(heap, heap_bound_deref(heap, tail)); + + let mut string = read_heap_cell!(head, + (HeapCellValueTag::Atom, (atom, arity)) => { + if arity == 0 { + if let Some(c) = atom.as_char() { + c.to_string() + } else { + return None; + } + } else { + return None; + } + } + (HeapCellValueTag::Char, c) => { + c.to_string() + } + _ => { + return None; + } + ); + + loop { + read_heap_cell!(tail, + (HeapCellValueTag::Lis, l) => { + read_heap_cell!(heap[l], + (HeapCellValueTag::Atom, (atom, arity)) => { + if arity == 0 { + if let Some(c) = atom.as_char() { + string.push(c); + } else { + return None; + } + } else { + break; + } + } + (HeapCellValueTag::Char, c) => { + string.push(c); + } + _ => { + return None; + } + ); + + tail = heap[l+1]; + } + (HeapCellValueTag::PStrLoc, l) => { + let (index, n) = pstr_loc_and_offset(&heap, l); + let n = n.get_num() as usize; + + string += &*cell_as_string!(heap[index]).as_str_from(n); + tail = heap[l+1]; + } + (HeapCellValueTag::CStr, cstr_atom) => { + string += &*cstr_atom.as_str(); + tail = empty_list_as_cell!(); + break; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if heap[h] != tail { + tail = heap[h]; + } else { + break; + } + } + _ => { + // Anon + break; + } + ); + } + + read_heap_cell!(tail, + (HeapCellValueTag::Var) => { + Some((string, Some(tail))) + } + (HeapCellValueTag::Atom, (atom, arity)) => { + if atom == atom!("[]") && arity == 0 { + Some((string, None)) + } else { + Some((string, Some(tail))) + } + } + _ => { + Some((string, Some(tail))) + } + ) +} + impl<'a, R: CharRead> Parser<'a, R> { pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self { Parser { @@ -289,6 +325,8 @@ impl<'a, R: CharRead> Parser<'a, R> { tokens: vec![], stack: vec![], terms: vec![], + var_locs: VarLocs::default(), + var_names_to_locs: IndexMap::with_hasher(FxBuildHasher::default()), } } @@ -298,50 +336,67 @@ impl<'a, R: CharRead> Parser<'a, R> { tokens: vec![], stack: vec![], terms: vec![], + var_locs: VarLocs::default(), + var_names_to_locs: IndexMap::with_hasher(FxBuildHasher::default()), } } - fn sep_to_atom(&mut self, tt: TokenType) -> Option { - match tt { - TokenType::Open | TokenType::OpenCT => Some(atom!("(")), - TokenType::Close => Some(atom!(")")), - TokenType::OpenList => Some(atom!("[")), - TokenType::CloseList => Some(atom!("]")), - TokenType::OpenCurly => Some(atom!("{")), - TokenType::CloseCurly => Some(atom!("}")), - TokenType::HeadTailSeparator => Some(atom!("|")), - TokenType::Comma => Some(atom!(",")), - TokenType::End => Some(atom!(".")), - _ => None, - } - } - - fn get_term_name(&mut self, td: TokenDesc) -> Option { + fn get_term_name(&self, td: TokenDesc) -> Option { match td.tt { TokenType::HeadTailSeparator => Some(atom!("|")), TokenType::Comma => Some(atom!(",")), - TokenType::Term => match self.terms.pop() { - Some(Term::Literal(_, Literal::Atom(atom))) => Some(atom), - Some(term) => { - self.terms.push(term); + TokenType::Term { heap_loc } => { + if heap_loc.is_ref() { + term_name(&self.terms, heap_loc.get_value() as usize) + } else { None } - _ => None, - }, + } _ => None, } } - fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) { - if let Some(arg2) = self.terms.pop() { - if let Some(name) = self.get_term_name(td) { - if let Some(arg1) = self.terms.pop() { - let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]); + #[inline] + pub fn line_num(&self) -> usize { + self.lexer.line_num + } + + #[inline] + pub fn col_num(&self) -> usize { + self.lexer.col_num + } + + fn push_binary_op( + &mut self, + op: TokenDesc, + operand_1: TokenDesc, + operand_2: TokenDesc, + spec: Specifier, + ) { + if let TokenDesc { + tt: TokenType::Term { heap_loc: arg2 }, + .. + } = operand_2 + { + if let TokenDesc { + tt: TokenType::Term { heap_loc: arg1 }, + .. + } = operand_1 + { + if let Some(name) = self.get_term_name(op) { + let str_loc = self.terms.len(); + + self.terms.push(atom_as_cell!(name, 2)); + self.terms.push(arg1); + self.terms.push(arg2); + + self.terms.push(str_loc_as_cell!(str_loc)); - self.terms.push(term); self.stack.push(TokenDesc { - tt: TokenType::Term, - priority: td.priority, + tt: TokenType::Term { + heap_loc: heap_loc_as_cell!(str_loc + 3), + }, + priority: op.priority, spec, unfold_bounds: 0, }); @@ -350,20 +405,33 @@ impl<'a, R: CharRead> Parser<'a, R> { } } - fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: OpDeclSpec) { - if let Some(mut arg1) = self.terms.pop() { - if let Some(mut name) = self.terms.pop() { - if assoc.is_postfix() { - mem::swap(&mut arg1, &mut name); - } + fn push_unary_op(&mut self, op: TokenDesc, operand: TokenDesc, spec: Specifier) { + // if is_postfix!(assoc) { + // mem::swap(&mut op, &mut operand); + // } - if let Term::Literal(_, Literal::Atom(name)) = name { - let term = Term::Clause(Cell::default(), name, vec![arg1]); + if let TokenDesc { + tt: TokenType::Term { heap_loc: arg1 }, + .. + } = operand + { + if let TokenDesc { + tt: TokenType::Term { .. }, + .. + } = op + { + if let Some(name) = self.get_term_name(op) { + let str_loc = self.terms.len(); + + self.terms.push(atom_as_cell!(name, 1)); + self.terms.push(arg1); + self.terms.push(str_loc_as_cell!(str_loc)); - self.terms.push(term); self.stack.push(TokenDesc { - tt: TokenType::Term, - priority: td.priority, + tt: TokenType::Term { + heap_loc: heap_loc_as_cell!(str_loc + 2), + }, + priority: op.priority, spec, unfold_bounds: 0, }); @@ -373,10 +441,12 @@ impl<'a, R: CharRead> Parser<'a, R> { } fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) { - self.terms - .push(Term::Literal(Cell::default(), Literal::Atom(atom))); + let h = self.terms.len(); + self.terms.push(atom_as_cell!(atom)); self.stack.push(TokenDesc { - tt: TokenType::Term, + tt: TokenType::Term { + heap_loc: heap_loc_as_cell!(h), + }, priority, spec: assoc, unfold_bounds: 0, @@ -384,45 +454,81 @@ impl<'a, R: CharRead> Parser<'a, R> { } fn shift(&mut self, token: Token, priority: usize, spec: Specifier) { + let heap_loc = heap_loc_as_cell!(self.terms.len()); + let tt = match token { Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_codes() => { - let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); + let mut list = empty_list_as_cell!(); for c in s.as_str().chars().rev() { - list = Term::Cons( - Cell::default(), - Box::new(Term::Literal( - Cell::default(), - Literal::Fixnum(Fixnum::build_with(c as i64)), - )), - Box::new(list), - ); + let h = self.terms.len(); + + self.terms + .push(fixnum_as_cell!(Fixnum::build_with(c as i64))); + self.terms.push(list); + + list = list_loc_as_cell!(h); } self.terms.push(list); - TokenType::Term + + TokenType::Term { heap_loc: list } } Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_chars() => { - self.terms.push(Term::CompleteString(Cell::default(), s)); - TokenType::Term + if s.is_empty() { + self.terms.push(empty_list_as_cell!()); + } else { + self.terms.push(string_as_cstr_cell!(s)); + } + + TokenType::Term { heap_loc } + } + Token::Literal(Literal::Char(c)) => { + // soon this will be gone due to chars being folded + // into atoms + self.terms.push(atom_as_cell!(atomize_literal( + &self.lexer.machine_st.atom_tbl, + Literal::Char(c), + ).unwrap())); + + TokenType::Term { heap_loc } } Token::Literal(c) => { - self.terms.push(Term::Literal(Cell::default(), c)); - TokenType::Term + self.terms.push(HeapCellValue::from(c)); + TokenType::Term { heap_loc } } - Token::Var(v) => { - if v.trim() == "_" { - self.terms.push(Term::AnonVar); - } else { - self.terms.push(Term::Var(Cell::default(), VarPtr::from(v))); + 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); - TokenType::Term - } + if var_string.trim() != "_" { + self.var_names_to_locs.insert(var_string.clone(), 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) + }, + ); + + TokenType::Term { heap_loc } + } + }, Token::Comma => TokenType::Comma, Token::Open => TokenType::Open, Token::Close => TokenType::Close, @@ -451,10 +557,10 @@ impl<'a, R: CharRead> Parser<'a, R> { if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1) || is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1) { - self.push_binary_op(desc2, LTERM); + self.push_binary_op(desc2, desc3, desc1, LTERM); continue; } else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) { - self.push_binary_op(desc2, TERM); + self.push_binary_op(desc2, desc3, desc1, TERM); continue; } else { self.stack.push(desc3); @@ -462,16 +568,16 @@ impl<'a, R: CharRead> Parser<'a, R> { } if is_yf!(desc1.spec) && affirm_yf(desc1, desc2) { - self.push_unary_op(desc1, LTERM, YF); + self.push_unary_op(desc1, desc2, LTERM); continue; } else if is_xf!(desc1.spec) && affirm_xf(desc1, desc2) { - self.push_unary_op(desc1, LTERM, XF); + self.push_unary_op(desc1, desc2, LTERM); continue; } else if is_fy!(desc2.spec) && affirm_fy(priority, desc1, desc2) { - self.push_unary_op(desc2, TERM, FY); + self.push_unary_op(desc2, desc1, TERM); continue; } else if is_fx!(desc2.spec) && affirm_fx(priority, desc1, desc2) { - self.push_unary_op(desc2, TERM, FX); + self.push_unary_op(desc2, desc1, TERM); continue; } else { self.stack.push(desc2); @@ -515,6 +621,14 @@ impl<'a, R: CharRead> Parser<'a, R> { None } + fn term_from_stack(&self, idx: usize) -> Option { + if let TokenType::Term { heap_loc } = self.stack[idx].tt { + Some(heap_loc) + } else { + None + } + } + fn reduce_term(&mut self) -> bool { if self.stack.is_empty() { return false; @@ -541,45 +655,77 @@ impl<'a, R: CharRead> Parser<'a, R> { return false; } - if self.terms.len() < 1 + arity { + if self.terms.len() < arity { return false; } let stack_len = self.stack.len() - 2 * arity - 1; - let idx = self.terms.len() - arity; + let term_idx = self.terms.len(); - if TokenType::Term == self.stack[stack_len].tt - && atomize_term(&self.lexer.machine_st.atom_tbl, &self.terms[idx - 1]).is_some() - { - self.stack.truncate(stack_len + 1); + let push_structure = |parser: &mut Self, name: Atom| -> TokenType { + parser.terms.push(atom_as_cell!(name, arity)); - let mut subterms: Vec<_> = self.terms.drain(idx..).collect(); + for idx in (stack_len + 2..parser.stack.len()).step_by(2) { + let subterm = parser.term_from_stack(idx).unwrap(); + parser.terms.push(subterm); + } - if let Some(name) = self - .terms - .pop() - .and_then(|t| atomize_term(&self.lexer.machine_st.atom_tbl, &t)) - { + let str_loc_idx = parser.terms.len(); + parser.terms.push(str_loc_as_cell!(term_idx)); + + TokenType::Term { + heap_loc: heap_loc_as_cell!(str_loc_idx), + } + }; + + if let TokenDesc { + tt: TokenType::Term { heap_loc }, + .. + } = self.stack[stack_len] + { + let idx = heap_loc.get_value() as usize; + + if let Some(name) = term_name(&self.terms, idx) { // reduce the '.' functor to a cons cell if it applies. - if name == atom!(".") && subterms.len() == 2 { - let tail = subterms.pop().unwrap(); - let head = subterms.pop().unwrap(); + let new_tt = if name == atom!(".") && arity == 2 { + let head = self.term_from_stack(stack_len + 2).unwrap(); + let tail = self.term_from_stack(stack_len + 4).unwrap(); - self.terms.push(match as_partial_string(head, tail) { - Ok((string_buf, Some(tail))) => { - Term::PartialString(Cell::default(), string_buf, tail) + match as_partial_string(&self.terms, head, tail) { + Some((string_buf, Some(tail))) => { + let atom = + AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); + + self.terms.push(string_as_pstr_cell!(atom)); + self.terms.push(tail); + self.terms.push(pstr_loc_as_cell!(term_idx)); + + TokenType::Term { + heap_loc: heap_loc_as_cell!(term_idx + 2), + } } - Ok((string_buf, None)) => { + Some((string_buf, None)) => { let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); - Term::CompleteString(Cell::default(), atom) + TokenType::Term { + heap_loc: string_as_cstr_cell!(atom), + } } - Err(term) => term, - }); + None => { + self.terms.push(head); + self.terms.push(tail); + self.terms.push(list_loc_as_cell!(term_idx)); + + TokenType::Term { + heap_loc: heap_loc_as_cell!(term_idx + 2), + } + } + } } else { - self.terms - .push(Term::Clause(Cell::default(), name, subterms)); - } + push_structure(self, name) + }; + + self.stack.truncate(stack_len + 1); if let Some(&mut TokenDesc { ref mut tt, @@ -592,38 +738,62 @@ impl<'a, R: CharRead> Parser<'a, R> { return false; } - *tt = TokenType::Term; + *tt = new_tt; *priority = 0; *spec = TERM; *unfold_bounds = 0; } + } else { + return false; + }; - return true; - } + return true; } false } pub fn reset(&mut self) { - self.stack.clear() + self.stack.clear(); + self.var_names_to_locs.clear(); } fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { - if let Some(mut term) = self.terms.pop() { + if let Some(term) = self.term_from_stack(index - 1) { let mut op_desc = self.stack[index - 1]; - - if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority { + let mut term = heap_bound_store( + &self.terms, + heap_bound_deref( + &self.terms, + term, + ), + ); + + if term.is_ref() && + 0 < op_desc.priority && op_desc.priority < self.stack[index].priority + { /* '|' is a head-tail separator here, not * an operator, so expand the * terms it compacted out again. */ - if let (Some(atom!(",")), 2) = (term.name(), term.arity()) { + + let focus = term.get_value() as usize; + let name_opt = term_name(&self.terms, focus); + let arity = term_arity(&self.terms, focus); + + if name_opt == Some(atom!(",")) && arity == 2 { let terms = if op_desc.unfold_bounds == 0 { - unfold_by_str(term, atom!(",")) + unfold_by_str(&mut self.terms, term, atom!(",")) } else { let mut terms = vec![]; - while let Some((fst, snd)) = unfold_by_str_once(&mut term, atom!(",")) { + while let Some(fst_loc) = unfold_by_str_once( + &mut self.terms, + term, + atom!(","), + ) { + let (_, snd) = subterm_index(&self.terms, fst_loc + 1); + let (_, fst) = subterm_index(&self.terms, fst_loc); + terms.push(fst); term = snd; @@ -639,13 +809,17 @@ impl<'a, R: CharRead> Parser<'a, R> { }; let arity = terms.len() - 1; - - self.terms.extend(terms); + self.stack.extend(terms.into_iter().map(|heap_loc| { + TokenDesc { + tt: TokenType::Term { heap_loc }, + priority: 0, + spec: 0, + unfold_bounds: 0, + } + })); return arity; } } - - self.terms.push(term); } 0 @@ -685,13 +859,17 @@ impl<'a, R: CharRead> Parser<'a, R> { } if let Some(ref mut td) = self.stack.last_mut() { + // parsed an empty list token if td.tt == TokenType::OpenList { + let h = self.terms.len(); + self.terms.push(empty_list_as_cell!()); + td.spec = TERM; - td.tt = TokenType::Term; + td.tt = TokenType::Term { + heap_loc: heap_loc_as_cell!(h), + }; td.priority = 0; - self.terms - .push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))); return Ok(true); } } @@ -705,52 +883,105 @@ impl<'a, R: CharRead> Parser<'a, R> { // we know that self.stack.len() >= 2 by this point. let idx = self.stack.len() - 2; - let list_len = self.stack.len() - 2 * arity; + let list_start_idx = self.stack.len() - 2 * arity; - let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { - Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))) + let mut tail_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { + empty_list_as_cell!() } else { - let term = match self.terms.pop() { + let tail_term = match self.term_from_stack(idx + 1) { Some(term) => term, - _ => { + None => { return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )) + self.lexer.loc_to_err_src(), + )); } }; + self.stack.pop(); + if self.stack[idx].priority > 1000 { arity += self.expand_comma_compacted_terms(idx); } + // decrement for the removal of tail term. arity -= 1; - - term + tail_term }; if arity > self.terms.len() { return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, + self.lexer.loc_to_err_src(), )); } - let idx = self.terms.len() - arity; + let pre_terms_len = self.terms.len(); - let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| { - Term::Cons(Cell::default(), Box::new(t), Box::new(acc)) - }); + while let Some(token_desc) = self.stack.pop() { + let subterm = match token_desc.tt { + TokenType::Term { heap_loc } => { + heap_loc + } + _ => { + continue; + } + }; + + arity -= 1; + + let link_cell = list_loc_as_cell!(self.terms.len() + 1); + + self.terms.push(link_cell); + self.terms.push(subterm); + self.terms.push(tail_term); + + tail_term = link_cell; + + if arity == 0 { + break; + } + } + + debug_assert_eq!(arity, 0); + + self.stack.truncate(list_start_idx); + + let list_loc = self.terms.len() - 3; + + let head_term = self.terms[list_loc + 1]; + let tail_term = self.terms[list_loc + 2]; + + let heap_loc = match as_partial_string(&self.terms, head_term, tail_term) { + Some((string_buf, Some(tail))) => { + self.terms.truncate(pre_terms_len); - self.stack.truncate(list_len); + let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); + + self.terms.push(string_as_pstr_cell!(atom)); + self.terms.push(tail); + self.terms.push(pstr_loc_as_cell!(pre_terms_len)); + + heap_loc_as_cell!(pre_terms_len + 2) + } + Some((string_buf, None)) => { + self.terms.truncate(pre_terms_len); + let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); + self.terms.push(string_as_cstr_cell!(atom)); + + heap_loc_as_cell!(pre_terms_len) + } + None => { + heap_loc_as_cell!(list_loc) // head_term + } + }; self.stack.push(TokenDesc { - tt: TokenType::Term, + tt: TokenType::Term { heap_loc }, priority: 0, spec: TERM, unfold_bounds: 0, }); + /* self.terms.push(match list { Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) { Ok((string_buf, Some(tail))) => { @@ -764,6 +995,7 @@ impl<'a, R: CharRead> Parser<'a, R> { }, term => term, }); + */ Ok(true) } @@ -775,13 +1007,15 @@ impl<'a, R: CharRead> Parser<'a, R> { if let Some(ref mut td) = self.stack.last_mut() { if td.tt == TokenType::OpenCurly { - td.tt = TokenType::Term; + let h = self.terms.len(); + self.terms.push(atom_as_cell!(atom!("{}"))); + + td.tt = TokenType::Term { + heap_loc: heap_loc_as_cell!(h), + }; td.priority = 0; td.spec = TERM; - let term = Term::Literal(Cell::default(), Literal::Atom(atom!("{}"))); - - self.terms.push(term); return Ok(true); } } @@ -791,29 +1025,41 @@ impl<'a, R: CharRead> Parser<'a, R> { if self.stack.len() > 1 { if let Some(td) = self.stack.pop() { if let Some(ref mut oc) = self.stack.last_mut() { - if td.tt != TokenType::Term { + if !matches!(td.tt, TokenType::Term { .. }) { return Ok(false); } if oc.tt == TokenType::OpenCurly { - oc.tt = TokenType::Term; - oc.priority = 0; - oc.spec = TERM; - - let term = match self.terms.pop() { - Some(term) => term, - _ => { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )) - } - }; - - self.terms - .push(Term::Clause(Cell::default(), atom!("{}"), vec![term])); - - return Ok(true); + if let TokenType::Term { heap_loc } = td.tt { + let curly_idx = self.terms.len(); + + oc.tt = TokenType::Term { + heap_loc: heap_loc_as_cell!(curly_idx + 2), + }; + oc.priority = 0; + oc.spec = TERM; + + self.terms.push(atom_as_cell!(atom!("{}"), 1)); + self.terms.push(heap_loc); + self.terms.push(str_loc_as_cell!(curly_idx)); + + /* + let term = match self.terms.pop() { + Some(term) => term, + _ => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } + }; + + self.terms + .push(Term::Clause(Cell::default(), atom!("{}"), vec![term])); + */ + + return Ok(true); + } } } } @@ -833,8 +1079,9 @@ impl<'a, R: CharRead> Parser<'a, R> { return false; } - if let Some(TokenType::Open | TokenType::OpenCT) = self.stack.last().map(|token| token.tt) { - return false; + match self.stack.last().map(|token| token.tt) { + Some(TokenType::Open | TokenType::OpenCT) => return false, + _ => {} } let idx = self.stack.len() - 2; @@ -846,13 +1093,16 @@ impl<'a, R: CharRead> Parser<'a, R> { return false; } - if let Some(atom) = self.sep_to_atom(self.stack[idx].tt) { - self.terms - .push(Term::Literal(Cell::default(), Literal::Atom(atom))); - } + let term = if self.stack[idx].tt.sep_to_atom().is_some() { + atom_as_cell!(atom!("|")) + // self.terms + // .push(Term::Literal(Cell::default(), Literal::Atom(atom))); + } else { + self.term_from_stack(idx).unwrap() + }; self.stack[idx].spec = BTERM; - self.stack[idx].tt = TokenType::Term; + self.stack[idx].tt = TokenType::Term { heap_loc: term }; self.stack[idx].priority = 0; true @@ -870,7 +1120,11 @@ impl<'a, R: CharRead> Parser<'a, R> { }) = get_op_desc(name, op_dir) { if (pre > 0 && inf + post > 0) || is_negate!(spec) { - match self.tokens.last().ok_or(ParserError::unexpected_eof())? { + match self + .tokens + .last() + .ok_or(ParserError::unexpected_eof(self.lexer.loc_to_err_src()))? + { // do this when layout hasn't been inserted, // ie. why we don't match on Token::Open. Token::OpenCT => { @@ -927,15 +1181,17 @@ impl<'a, R: CharRead> Parser<'a, R> { Negator: Fn(N, &mut Arena) -> N, ToLiteral: Fn(N, &mut Arena) -> Literal, { - if let Some(desc) = self.stack.last().cloned() { - if let Some(term) = self.terms.last().cloned() { - match term { - Term::Literal(_, Literal::Atom(name)) - if name == atom!("-") - && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => - { + match self.stack.last().cloned() { + Some( + td @ TokenDesc { + tt: TokenType::Term { .. }, + spec, + .. + }, + ) => { + if let Some(name) = self.get_term_name(td) { + if name == atom!("-") && (is_prefix!(spec) || is_negate!(spec)) { self.stack.pop(); - self.terms.pop(); let arena = &mut self.lexer.machine_st.arena; let literal = constr(negator(n, arena), arena); @@ -944,9 +1200,9 @@ impl<'a, R: CharRead> Parser<'a, R> { return; } - _ => {} } } + _ => {} } let literal = constr(n, &mut self.lexer.machine_st.arena); @@ -978,8 +1234,7 @@ impl<'a, R: CharRead> Parser<'a, R> { } Token::Literal(Literal::Float(n)) if F64Ptr::from_offset(n).is_infinite() => { return Err(ParserError::InfiniteFloat( - self.lexer.line_num, - self.lexer.col_num, + self.lexer.loc_to_err_src(), )); } Token::Literal(Literal::Float(n)) => self.negate_number( @@ -988,7 +1243,7 @@ impl<'a, R: CharRead> Parser<'a, R> { |n, arena| Literal::from(float_alloc!(n, arena)), ), Token::Literal(c) => { - let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c); + let atomized = atomize_literal(&self.lexer.machine_st.atom_tbl, c); if let Some(name) = atomized { if !self.shift_op(name, op_dir)? { @@ -1004,8 +1259,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::Close => { if !self.reduce_term() && !self.reduce_brackets() { return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, + self.lexer.loc_to_err_src(), )); } } @@ -1013,8 +1267,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::CloseList => { if !self.reduce_list()? { return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, + self.lexer.loc_to_err_src(), )); } } @@ -1022,8 +1275,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::CloseCurly => { if !self.reduce_curly()? { return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, + self.lexer.loc_to_err_src(), )); } } @@ -1059,8 +1311,7 @@ impl<'a, R: CharRead> Parser<'a, R> { | Some(TokenType::HeadTailSeparator) | Some(TokenType::Comma) => { return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, + self.lexer.loc_to_err_src(), )) } _ => {} @@ -1070,11 +1321,6 @@ impl<'a, R: CharRead> Parser<'a, R> { Ok(()) } - #[inline] - pub fn add_lines_read(&mut self, lines_read: usize) { - self.lexer.line_num += lines_read; - } - #[inline] pub fn lines_read(&self) -> usize { self.lexer.line_num @@ -1085,7 +1331,7 @@ impl<'a, R: CharRead> Parser<'a, R> { &mut self, op_dir: &CompositeOpDir, tokens: Tokens, - ) -> Result { + ) -> Result { self.tokens = match tokens { Tokens::Default => read_tokens(&mut self.lexer)?, Tokens::Provided(tokens) => tokens, @@ -1097,27 +1343,23 @@ impl<'a, R: CharRead> Parser<'a, R> { self.reduce_op(1400); - if self.terms.len() > 1 || self.stack.len() > 1 { + if self.stack.len() > 1 || self.terms.is_empty() { return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, + self.lexer.loc_to_err_src(), )); } - match self.terms.pop() { - Some(term) => { - if self.terms.is_empty() { - Ok(term) - } else { - Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )) - } - } + match self.stack.pop() { + Some(TokenDesc { + tt: TokenType::Term { heap_loc }, + .. + }) => 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()), + }), _ => Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, + self.lexer.loc_to_err_src(), )), } } diff --git a/src/raw_block.rs b/src/raw_block.rs index da757415..9e3b4a7b 100644 --- a/src/raw_block.rs +++ b/src/raw_block.rs @@ -19,7 +19,7 @@ pub struct RawBlock { impl RawBlock { #[inline] - fn empty_block() -> Self { + pub(crate) fn empty_block() -> Self { RawBlock { base: ptr::null(), top: ptr::null(), diff --git a/src/read.rs b/src/read.rs index c13c0250..9759caf3 100644 --- a/src/read.rs +++ b/src/read.rs @@ -2,19 +2,12 @@ use crate::parser::ast::*; use crate::parser::parser::*; use crate::atom_table::*; -use crate::forms::*; -use crate::iterators::*; -use crate::machine::heap::*; use crate::machine::machine_errors::*; -use crate::machine::machine_indices::*; -use crate::machine::machine_state::MachineState; +use crate::machine::machine_state::{MachineState, copy_and_align_iter}; use crate::machine::streams::*; use crate::parser::char_reader::*; #[cfg(feature = "repl")] use crate::repl_helper::Helper; -use crate::types::*; - -use fxhash::FxBuildHasher; #[cfg(feature = "repl")] use rustyline::error::ReadlineError; @@ -23,14 +16,11 @@ use rustyline::history::DefaultHistory; #[cfg(feature = "repl")] use rustyline::{Config, Editor}; -use std::collections::VecDeque; use std::io::{Cursor, Read}; #[cfg(feature = "repl")] use std::io::{Error, ErrorKind}; use std::sync::Arc; -type SubtermDeque = VecDeque<(usize, usize)>; - pub(crate) fn devour_whitespace( parser: &mut Parser<'_, R>, ) -> Result { @@ -41,46 +31,72 @@ pub(crate) fn devour_whitespace( } } -pub(crate) fn error_after_read_term( +pub(crate) fn error_after_read_term( err: ParserError, prior_num_lines_read: usize, - parser: &Parser, ) -> CompilationError { if err.is_unexpected_eof() { - let line_num = parser.lexer.line_num; - let col_num = parser.lexer.col_num; + let ParserErrorSrc { line_num, col_num } = err.err_src(); // rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here if !(line_num == prior_num_lines_read && col_num == 0) { - return CompilationError::from(ParserError::IncompleteReduction(line_num, col_num)); + return CompilationError::from(ParserError::IncompleteReduction(err.err_src())); } } CompilationError::from(err) } +impl FocusedHeap { + pub fn to_machine_heap(mut self, machine_st: &mut MachineState) -> TermWriteResult { + let heap_len = machine_st.heap.len(); + machine_st.heap.extend(copy_and_align_iter(self.heap.drain(..), 0, heap_len as i64)); + + let mut var_locs = VarLocs::default(); + + for (var_loc, var_ptrs) in self.var_locs.drain(..) { + var_locs.insert(var_loc + heap_len, var_ptrs); + } + + TermWriteResult { + heap_loc: self.focus + heap_len, + var_locs, + } + } +} + impl MachineState { - pub(crate) fn read( + pub(crate) fn read( &mut self, - mut inner: Stream, + inner: R, op_dir: &OpDir, - ) -> Result { - let (term, num_lines_read) = { - let prior_num_lines_read = inner.lines_read(); - let mut parser = Parser::new(inner, self); - let op_dir = CompositeOpDir::new(op_dir, None); + ) -> Result<(FocusedHeap, usize), ParserError> { + let mut parser = Parser::new(inner, self); + let op_dir = CompositeOpDir::new(op_dir, None); - parser.add_lines_read(prior_num_lines_read); + let term_result = parser.read_term(&op_dir, Tokens::Default); + let lines_read = parser.lines_read(); - let term = parser - .read_term(&op_dir, Tokens::Default) - .map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from + term_result.map(|term| (term, lines_read)) + } - (term, parser.lines_read() - prior_num_lines_read) + pub(crate) fn read_to_heap( + &mut self, + mut inner: Stream, + op_dir: &OpDir, + ) -> Result { + let prior_num_lines_read = inner.lines_read(); + let term = match self.read(inner, op_dir) { + Ok((term, num_lines_read)) => { + inner.add_lines_read(num_lines_read); + term + } + Err(e) => { + return Err(error_after_read_term(e, prior_num_lines_read)); + } }; - inner.add_lines_read(num_lines_read); - write_term_to_heap(&term, &mut self.heap, &self.atom_tbl) + Ok(term.to_machine_heap(self)) } } @@ -279,7 +295,6 @@ impl CharRead for ReadlineStream { } } } - #[inline] fn consume(&mut self, nread: usize) { self.pending_input.consume(nread); @@ -291,199 +306,8 @@ impl CharRead for ReadlineStream { } } -#[inline] -pub(crate) fn write_term_to_heap( - term: &Term, - heap: &mut Heap, - atom_tbl: &AtomTable, -) -> Result { - let term_writer = TermWriter::new(heap, atom_tbl); - term_writer.write_term_to_heap(term) -} - -#[derive(Debug)] -struct TermWriter<'a, 'b> { - heap: &'a mut Heap, - atom_tbl: &'b AtomTable, - queue: SubtermDeque, - var_dict: HeapVarDict, -} - #[derive(Debug)] pub struct TermWriteResult { pub heap_loc: usize, - pub var_dict: HeapVarDict, -} - -impl<'a, 'b> TermWriter<'a, 'b> { - #[inline] - fn new(heap: &'a mut Heap, atom_tbl: &'b AtomTable) -> Self { - TermWriter { - heap, - atom_tbl, - queue: SubtermDeque::new(), - var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()), - } - } - - #[inline] - fn modify_head_of_queue(&mut self, term: &TermRef, h: usize) { - if let Some((arity, site_h)) = self.queue.pop_front() { - self.heap[site_h] = self.term_as_addr(term, h); - - if arity > 1 { - self.queue.push_front((arity - 1, site_h + 1)); - } - } - } - - #[inline] - fn push_stub_addr(&mut self) { - let h = self.heap.len(); - self.heap.push(heap_loc_as_cell!(h)); - } - - fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue { - match term { - &TermRef::Cons(..) => list_loc_as_cell!(h), - &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h), - TermRef::CompleteString(_, _, src) => { - if src.as_str().is_empty() { - empty_list_as_cell!() - } else if self.heap[h].get_tag() == HeapCellValueTag::CStr { - heap_loc_as_cell!(h) - } else { - pstr_loc_as_cell!(h) - } - } - &TermRef::PartialString(..) => pstr_loc_as_cell!(h), - &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal), - &TermRef::Clause(_, _, _, subterms) if subterms.is_empty() => heap_loc_as_cell!(h), - &TermRef::Clause(..) => str_loc_as_cell!(h), - } - } - - fn write_term_to_heap(mut self, term: &Term) -> Result { - let heap_loc = self.heap.len(); - - for term in breadth_first_iter(term, RootIterationPolicy::Iterated) { - let h = self.heap.len(); - - match &term { - &TermRef::Cons(Level::Root, ..) => { - self.queue.push_back((2, h + 1)); - self.heap.push(list_loc_as_cell!(h + 1)); - - self.push_stub_addr(); - self.push_stub_addr(); - - continue; - } - &TermRef::Cons(..) => { - self.queue.push_back((2, h)); - - self.push_stub_addr(); - self.push_stub_addr(); - } - &TermRef::Clause(Level::Root, _, name, subterms) => { - if subterms.len() > MAX_ARITY { - return Err(CompilationError::ExceededMaxArity); - } - - self.heap.push(if subterms.is_empty() { - heap_loc_as_cell!(heap_loc + 1) - } else { - str_loc_as_cell!(heap_loc + 1) - }); - - self.queue.push_back((subterms.len(), h + 2)); - let named = atom_as_cell!(name, subterms.len()); - - self.heap.push(named); - - for _ in 0..subterms.len() { - self.push_stub_addr(); - } - - continue; - } - &TermRef::Clause(_, _, name, subterms) => { - self.queue.push_back((subterms.len(), h + 1)); - let named = atom_as_cell!(name, subterms.len()); - - self.heap.push(named); - - for _ in 0..subterms.len() { - self.push_stub_addr(); - } - } - &TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => { - let addr = self.term_as_addr(&term, h); - self.heap.push(addr); - } - &TermRef::Var(Level::Root, _, ref var_ptr) => { - let addr = self.term_as_addr(&term, h); - self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr); - self.heap.push(addr); - } - &TermRef::AnonVar(_) => { - if let Some((arity, site_h)) = self.queue.pop_front() { - self.var_dict - .insert(VarKey::AnonVar(h), heap_loc_as_cell!(site_h)); - - if arity > 1 { - self.queue.push_front((arity - 1, site_h + 1)); - } - } - - continue; - } - TermRef::CompleteString(_, _, src) => { - let src = src.as_str().to_owned(); - put_complete_string(self.heap, &src, self.atom_tbl); - } - &TermRef::PartialString(lvl, _, src, _) => { - if let Level::Root = lvl { - // Var tags can't refer directly to partial strings, - // so a PStrLoc cell must be pushed. - self.heap.push(pstr_loc_as_cell!(heap_loc + 1)); - } - - allocate_pstr(self.heap, src.as_str(), self.atom_tbl); - - let h = self.heap.len(); - self.queue.push_back((1, h - 1)); - - if let Level::Root = lvl { - continue; - } - } - TermRef::Var(.., var) => { - if let Some((arity, site_h)) = self.queue.pop_front() { - let var_key = VarKey::VarPtr(var.clone()); - - if let Some(addr) = self.var_dict.get(&var_key).cloned() { - self.heap[site_h] = addr; - } else { - self.var_dict.insert(var_key, heap_loc_as_cell!(site_h)); - } - - if arity > 1 { - self.queue.push_front((arity - 1, site_h + 1)); - } - } - - continue; - } - _ => {} - }; - - self.modify_head_of_queue(&term, h); - } - - Ok(TermWriteResult { - heap_loc, - var_dict: self.var_dict, - }) - } + pub var_locs: VarLocs, } diff --git a/src/targets.rs b/src/targets.rs index 4a1ce362..c2d7cde9 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -3,17 +3,12 @@ use crate::parser::ast::*; use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; -use crate::iterators::*; use crate::types::*; pub(crate) struct FactInstruction; pub(crate) struct QueryInstruction; pub(crate) trait CompilationTarget<'a> { - type Iterator: Iterator>; - - fn iter(term: &'a Term) -> Self::Iterator; - fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction; fn to_list(lvl: Level, r: RegType) -> Instruction; fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction; @@ -41,12 +36,6 @@ pub(crate) trait CompilationTarget<'a> { } impl<'a> CompilationTarget<'a> for FactInstruction { - type Iterator = FactIterator<'a>; - - fn iter(term: &'a Term) -> Self::Iterator { - breadth_first_iter(term, RootIterationPolicy::NotIterated) - } - fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg) } @@ -115,12 +104,6 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } impl<'a> CompilationTarget<'a> for QueryInstruction { - type Iterator = QueryIterator<'a>; - - fn iter(term: &'a Term) -> Self::Iterator { - post_order_iter(term) - } - fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction { Instruction::PutStructure(name, arity, r) } diff --git a/src/tests/builtins.pl b/src/tests/builtins.pl index a87fc22a..1a437413 100644 --- a/src/tests/builtins.pl +++ b/src/tests/builtins.pl @@ -46,7 +46,7 @@ test_queries_on_builtins :- \+ float([1,2,_]), \+ (X is 3 rdiv 4, float(X)), \+ \+ (X is 3 rdiv 4, rational(X)), - \+ rational(3), + rational(3), \+ rational(f(_)), \+ rational("sdfa"), \+ rational(atom), diff --git a/src/variable_records.rs b/src/variable_records.rs index b3546f4c..528ded35 100644 --- a/src/variable_records.rs +++ b/src/variable_records.rs @@ -87,7 +87,7 @@ pub enum VarAlloc { safety: VarSafetyStatus, to_perm_var_num: Option, }, - Perm(usize, PermVarAllocation), // stack offset, allocation info + Perm { reg: usize, allocation: PermVarAllocation }, // stack offset, allocation info } impl VarAlloc { @@ -95,14 +95,14 @@ impl VarAlloc { pub(crate) fn as_reg_type(&self) -> RegType { match *self { VarAlloc::Temp { temp_reg, .. } => RegType::Temp(temp_reg), - VarAlloc::Perm(r, _) => RegType::Perm(r), + VarAlloc::Perm { reg, .. } => RegType::Perm(reg), } } #[inline] pub(crate) fn set_register(&mut self, reg_num: usize) { match self { - VarAlloc::Perm(ref mut p, _) => *p = reg_num, + VarAlloc::Perm { ref mut reg, .. } => *reg = reg_num, VarAlloc::Temp { ref mut temp_reg, .. } => *temp_reg = reg_num, @@ -151,7 +151,7 @@ pub struct VariableRecord { impl Default for VariableRecord { fn default() -> Self { VariableRecord { - allocation: VarAlloc::Perm(0, PermVarAllocation::Pending), + allocation: VarAlloc::Perm { reg: 0, allocation: PermVarAllocation::Pending }, num_occurrences: 0, running_count: 0, } diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index f0edd5d8..a187f14d 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -35,7 +35,7 @@ fn hello_world() { fn syntax_error() { load_module_test( "tests-pl/syntax_error.pl", - " error(syntax_error(incomplete_reduction),read_term/3:6).\n", + " error(syntax_error(incomplete_reduction),read_term/3:3).\n", ); }