From 34ac85bb6d4596ba0a6bab684ebace7f4f6ebb7c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 13 May 2024 14:40:09 -0600 Subject: [PATCH 001/122] restore ubuntu testing to ci.yml with rust version 1.77 --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70f8d1a2..3e0bde90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,7 @@ jobs: # Cargo.toml rust-version - { os: ubuntu-22.04, rust-version: "1.85", target: 'x86_64-unknown-linux-gnu'} # rust versions + - { os: ubuntu-22.04, rust-version: "1.77", target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu', miri: true, components: "miri"} defaults: From 1ef681bd216317f01caeb2f75fb8549b51821b7f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 16 Jul 2024 15:38:22 -0600 Subject: [PATCH 002/122] remove Term --- build/instructions_template.rs | 4 +- src/allocator.rs | 16 +- src/arithmetic.rs | 90 ++- src/codegen.rs | 1114 +++++++++++++++++---------- src/debray_allocator.rs | 212 +++-- src/forms.rs | 158 ++-- src/heap_iter.rs | 152 ++-- src/heap_print.rs | 34 +- src/indexing.rs | 68 +- src/iterators.rs | 476 +++++------- src/lib/atts.pl | 2 +- src/lib/builtins.pl | 20 +- src/lib/si.pl | 1 - src/loader.pl | 2 + src/machine/arithmetic_ops.rs | 13 +- src/machine/attributed_variables.rs | 14 +- src/machine/compile.rs | 68 +- src/machine/disjuncts.rs | 825 +++++++++++--------- src/machine/dispatch.rs | 26 + src/machine/gc.rs | 12 + src/machine/load_state.rs | 8 +- src/machine/loader.rs | 273 +++---- src/machine/machine_errors.rs | 15 +- src/machine/machine_indices.rs | 34 +- src/machine/machine_state.rs | 101 ++- src/machine/mock_wam.rs | 65 +- src/machine/preprocessor.rs | 742 +++++++++--------- src/machine/raw_block.rs | 16 +- src/machine/stack.rs | 7 + src/machine/streams.rs | 2 +- src/machine/system_calls.rs | 180 +++-- src/machine/term_stream.rs | 14 +- src/machine/unify.rs | 9 +- src/macros.rs | 5 + src/parser/ast.rs | 560 +++++++++++++- src/parser/lexer.rs | 78 +- src/parser/parser.rs | 824 +++++++++++++------- src/raw_block.rs | 2 +- src/read.rs | 272 ++----- src/targets.rs | 17 - src/tests/builtins.pl | 2 +- src/variable_records.rs | 8 +- tests/scryer/src_tests.rs | 2 +- 43 files changed, 3823 insertions(+), 2720 deletions(-) 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) } } +*/ -fn push_literal(interm: &mut Vec, c: &Literal) -> Result<(), ArithmeticError> { +#[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> { 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(); + let mut stack = Stack::uninitialized(); + let mut iter = query_iterator::(&mut src.heap, &mut stack, term_loc); - 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(); + 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::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 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), + _ => self.mark_var::(var_num, Level::Shallow, context, 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; - } - } - _ => {} - } -} - 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(); - } else { - self.marker - .mark_anon_var::(lvl, term_loc, &mut target); + 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, + ); + } } } - 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::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 { + 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, + ); + } + } + } + } + (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); - for subterm in terms { - self.subterm_to_instr::(subterm, term_loc, &mut target); - } + let head_r_opt = self.subterm_to_instr::( + head, + var_locs, + head_loc, + context, + index_ptrs, + &mut target, + ); - for subterm in terms { + 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, subterm, + self, r, + ); + } + + if let Some(r) = tail_r_opt { + as AddToFreeList<'a, Target>>::add_subterm_to_free_list( + 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") + ), + InlinedClauseType::IsAtomic(..) => read_heap_cell!(term, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); + + if var_ptr.is_anon() { + instr!("$fail") + } else { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + var_ptr.to_var_num().unwrap(), + 1, + context, + code, + ); + + instr!("atomic", r) + } } - Term::Literal(_, Literal::String(_)) => { - instr!("$fail") - } - Term::Literal(..) => { + (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!("atomic", r) + (HeapCellValueTag::Cons, cons_ptr) => { + match cons_ptr.get_tag() { + ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => { + instr!("$succeed") + } + _ => { + instr!("$fail") + } + } } - }, - InlinedClauseType::IsCompound(..) => match &terms[0] { - Term::Clause(..) - | Term::Cons(..) - | Term::PartialString(..) - | Term::CompleteString(..) - | Term::Literal(_, Literal::String(..)) => { + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + instr!("$succeed") + } else { + instr!("$fail") + } + } + (HeapCellValueTag::Lis + | HeapCellValueTag::Str + | HeapCellValueTag::PStrLoc + | HeapCellValueTag::CStr) => { + instr!("$fail") + } + _ => { + if Literal::try_from(term).is_ok() { + instr!("$succeed") + } else { + instr!("$fail") + } + } + ), + InlinedClauseType::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!("compound", r) + instr!("float", r) + } } _ => { instr!("$fail") } - }, - InlinedClauseType::IsRational(..) => match terms[0] { - Term::Literal(_, Literal::Rational(_)) => { - 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, - ); - instr!("rational", r) + + 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!("$fail") + if Number::try_from(term).is_ok() { + instr!("$succeed") + } else { + instr!("$fail") + } } - }, - InlinedClauseType::IsFloat(..) => match terms[0] { - Term::Literal(_, Literal::Float(_)) => { - instr!("$succeed") - } - 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!("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) => { - self.marker.reset_arg(1); - - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); - - instr!("number", r) - } - _ => { - instr!("$fail") - } - }, - InlinedClauseType::IsNonVar(..) => match terms[0] { - Term::AnonVar => { - instr!("$fail") - } - Term::Var(ref vr, ref name) => { - self.marker.reset_arg(1); - - let r = self.marker.mark_non_callable( - name.to_var_num().unwrap(), - 1, - term_loc, - vr, - code, - ); - - 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(); + + let fact_focus = fact.term.focus; + let mut stack = Stack::uninitialized(); + self.marker.var_data = var_data; + self.marker.reset_at_head(&mut fact.term, fact_focus); - if let Term::Clause(_, _, args) = &fact.head { - self.marker.reset_at_head(args); + let iter = fact_iterator::( + &mut fact.term.heap, &mut stack, fact_focus, + ); - let iter = FactInstruction::iter(&fact.head); - let compiled_fact = self.compile_target::(iter, GenContext::Head); + 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); + 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()); + + let query = self.compile_target::( + iter, + &clause.code_indices, + &mut term.var_locs, + context, + ); code.extend(query); - - match term { - &QueryTerm::Clause(_, ref ct, _, call_policy) => { - self.add_call(code, ct.to_instr(), call_policy); - } - _ => unreachable!(), - }; + 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 { @@ -183,34 +160,39 @@ impl ChunkedTermVec { } #[derive(Debug)] -pub enum QueryTerm { - // register, clause type, subterms, clause call policy. - Clause(Cell, ClauseType, Vec, CallPolicy), - Fail, - LocalCut { var_num: usize, cut_prev: bool }, // var_num - GlobalCut(usize), // var_num - GetCutPoint { var_num: usize, prev_b: bool }, - GetLevel(usize), // var_num +pub struct QueryClause { + pub ct: ClauseType, + pub arity: usize, + pub term: HeapCellValue, + pub code_indices: IndexMap, + pub call_policy: CallPolicy, } -impl QueryTerm { - pub(crate) fn arity(&self) -> usize { - match self { - QueryTerm::Clause(_, _, subterms, ..) => subterms.len(), - &QueryTerm::GetLevel(_) | &QueryTerm::GetCutPoint { .. } => 1, - _ => 0, - } +impl QueryClause { + pub fn term_loc(&self) -> usize { + self.term.get_value() as usize } } +#[derive(Debug)] +pub enum QueryTerm { + Clause(QueryClause), + Fail, + Succeed, + LocalCut { var_num: usize, cut_prev: bool }, + GlobalCut(usize), // var_num + GetCutPoint { var_num: usize, prev_b: bool }, + GetLevel(usize), // var_num +} + #[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 => { + 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, + ); + } + (HeapCellValueTag::Lis + | HeapCellValueTag::CStr + | HeapCellValueTag::PStrLoc) => { clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); self.index_list(index); } - &Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => { - 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()); + _ => { + match Literal::try_from(optimal_arg) { + Ok(lit) => { + let overlapping_constants = self.index_constant(atom_tbl, lit, index); - self.index_structure(name, terms.len(), index); + clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( + self.optimal_index, + 0, + lit, + overlapping_constants, + ); + } + _ => {} + } } - &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); - } - _ => {} - } + ); } 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, - } - } -} -*/ - -#[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), -} - -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()) - } - Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant), - Term::PartialString(cell, string_buf, tail) => { - TermIterState::InitialPartialString(lvl, cell, string_buf, tail) - } - Term::CompleteString(cell, atom) => TermIterState::CompleteString(lvl, cell, *atom), - Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()), - } - } +pub(crate) trait TermIterator: + Deref + Iterator +{ + fn focus(&self) -> IterStackLoc; + fn level(&mut self) -> Level; } #[derive(Debug)] -pub(crate) struct QueryIterator<'a> { - state_stack: Vec>, +pub(crate) struct TargetIterator { + shallow_terms: IndexMap, FxBuildHasher>, + root_terms: BitSet, + iter: I, + arg_c: usize, } -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 record_path( + heap: &[HeapCellValue], + root_terms: &mut BitSet, + mut root_loc: usize, +) -> usize { + loop { + let cell = heap[root_loc]; + root_terms.insert(root_loc); - /* - 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(); - - QueryIterator { state_stack } - } - */ - - fn from_term(term: &'a Term) -> Self { - let state = match term { - Term::AnonVar - | Term::Cons(..) - | Term::Literal(..) - | Term::PartialString(..) - | Term::CompleteString(..) => { - return QueryIterator { - state_stack: vec![], + read_heap_cell!(cell, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h == root_loc { + break; + } else { + root_loc = h; } } - 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()), - }; + (HeapCellValueTag::Lis) => { + root_terms.insert(root_loc); + break; + } + _ => { + if cell.is_ref() { + root_terms.insert(cell.get_value() as usize); + } - QueryIterator { - state_stack: vec![state], + break; + } + ); + } + + root_loc +} + +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) +} + +fn find_shallow_terms( + heap: &[HeapCellValue], + root_loc: usize, +) -> IndexMap, FxBuildHasher> { + let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default()); + + let (h, arity) = read_heap_cell!(heap[root_loc], + (HeapCellValueTag::Str, s) => { + (s+1, cell_as_atom_cell!(heap[s]).get_arity()) + } + (HeapCellValueTag::Lis, l) => { + (l, 2) + } + (HeapCellValueTag::Atom, (_name, arity)) => { + (root_loc + 1, arity) + } + _ => { + (root_loc, 0) + } + ); + + for idx in 0..arity { + let mut shallow_terms = BitSet::default(); + record_path(heap, &mut shallow_terms, h + idx); + shallow_terms_map.insert(idx + 1, shallow_terms); + } + + 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; - pub fn new(term: &'a QueryTerm) -> Self { - let mut iter = QueryIterator { - state_stack: vec![], - }; - iter.extend_state(Level::Root, term); - iter + 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; + } + } + + 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 level(&mut self) -> Level { + let lvl = self.current_level(1); + + if let Level::Shallow = lvl { + self.arg_c += 1; + } + + lvl + } +} + +impl<'a, const SKIP_ROOT: bool> TermIterator for QueryIterator<'a, SKIP_ROOT> { + fn focus(&self) -> IterStackLoc { + self.iter.focus() + } + + fn level(&mut self) -> Level { + let lvl = self.current_level(0); + + if let Level::Shallow = lvl { + self.arg_c += 1; + } + + lvl + } +} + +impl Iterator for TargetIterator { + type Item = HeapCellValue; 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, - )); + loop { + let next_term = self.iter.next(); - 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)); - - 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)); - } - }; - } - - None - } -} - -#[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)); - } - - 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(); - - FactIterator { - state_queue, - iterable_root: RootIterationPolicy::NotIterated, - } - } - - fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self { - let states = match term { - Term::AnonVar => { - vec![TermIterState::AnonVar(Level::Root)] + if next_term.is_none() { + return None; } - 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, - } - } -} + let focus = self.iter.focus().value() as usize; -impl<'a> Iterator for FactIterator<'a> { - type Item = TermRef<'a>; - - 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); - } - - 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); - - 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)); - } - _ => {} + if SKIP_ROOT && self.root_terms.contains(focus) { + continue; + } else { + return next_term; } } - - None } } -pub(crate) fn post_order_iter(term: &'_ Term) -> QueryIterator { - QueryIterator::from_term(term) +impl Deref for TargetIterator { + type Target = [HeapCellValue]; + + fn deref(&self) -> &Self::Target { + self.iter.deref() + } } -pub(crate) fn breadth_first_iter( - term: &'_ Term, - iterable_root: RootIterationPolicy, -) -> FactIterator { - FactIterator::new(term, iterable_root) +impl FocusedHeapIter for TargetIterator { + fn focus(&self) -> IterStackLoc { + self.iter.focus() + } +} + +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())); - } - - let branch_info = branch_info_v.last_mut().unwrap(); - let needs_new_chunk = branch_info.chunks.is_empty(); - - if needs_new_chunk { - branch_info.chunks.push(ChunkInfo { - 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); + while let Some(subterm) = iter.next() { + if !subterm.is_var() { + lvl = Level::Deep; + continue; } + + let h = subterm.get_value() as usize; + let var_ptr = term.var_locs.read_next_var_ptr_at_key(h).unwrap().clone(); + + // the body of the if let here is an inlined + // "probe_head_var". note the difference between it + // and "probe_body_var". + let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default(); + let needs_new_branch = branch_info_v.is_empty(); + + if needs_new_branch { + branch_info_v.push(BranchInfo::new(self.current_branch_num.clone())); + } + + let branch_info = branch_info_v.last_mut().unwrap(); + let needs_new_chunk = branch_info.chunks.is_empty(); + + 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); - } - } - } - 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 - }); + macro_rules! add_chunk { + ($classifier:ident, $key:expr, $tag:expr, $term_loc:expr) => {{ + if update_chunk_data($classifier, $key) { + build_stack.add_chunk(); } - 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 (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)); - } - - 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).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![], + 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, ))); - state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); - state_stack.push(TraversalState::Fail); - state_stack.push(TraversalState::CutPrev(self.var_num)); - state_stack.push(TraversalState::ResetGlobalCutVarOverride( - self.global_cut_var_num_override, - )); - state_stack.push(TraversalState::Term(not_term)); - state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num)); - state_stack.push(TraversalState::GetCutPoint { - var_num: self.var_num, - prev_b: false, - }); + }}; + } - self.current_chunk_type = ChunkType::Mid; - self.current_chunk_num += 1; - - self.var_num += 1; - } - Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => { - let predicate_name = terms.pop().unwrap(); - let module_name = terms.pop().unwrap(); - - match (module_name, predicate_name) { - ( - Term::Literal(_, Literal::Atom(module_name)), - Term::Literal(_, Literal::Atom(predicate_name)), - ) => { - if update_chunk_data(self, predicate_name, 0) { - build_stack.add_chunk(); - } - - 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(); - } - - for (arg_c, term) in terms.iter().enumerate() { - self.probe_body_term(arg_c + 1, terms.len(), term); - } - - build_stack.push_chunk_term(qualified_clause_to_query_term( - loader, - module_name, - name, - terms, - self.call_policy, - )); - } - (module_name, predicate_name) => { - if update_chunk_data(self, atom!("call"), 2) { - build_stack.add_chunk(); - } - - self.probe_body_term(1, 0, &module_name); - self.probe_body_term(2, 0, &predicate_name); - - terms.push(module_name); - terms.push(predicate_name); - - build_stack.push_chunk_term(clause_to_query_term( - loader, - atom!("call"), - vec![Term::Clause(Cell::default(), atom!(":"), terms)], - self.call_policy, - )); - } - } - } - 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())); - - 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) { + 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(); } - self.probe_body_term(1, 1, &var); + for (arg_c, term_loc) in + ($term_loc + 1..$term_loc + $key.1 + 1).enumerate() + { + $classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc); + } - build_stack.push_chunk_term(clause_to_query_term( - loader, - atom!("call"), - vec![var], - self.call_policy, + 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, + ), )); - } - 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) + }}; + } + + loop { + read_heap_cell!(subterm, + (HeapCellValueTag::Str, subterm_loc) => { + let (name, arity) = cell_as_atom_cell!(terms.heap[subterm_loc]) + .get_name_and_arity(); + + match (name, arity) { + (atom!("->") | atom!(";") | atom!(","), 3) => { + if blunt_index_ptr(&mut terms.heap, (name, 2), subterm_loc) { + subterm = terms.heap[subterm_loc]; + continue; + } + + add_chunk!(self, (name, 2), HeapCellValueTag::Str, subterm_loc); + } + (atom!(","), 2) => { + let head_loc = terms.nth_arg(subterm_loc, 1).unwrap(); + let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + let head = terms.heap[head_loc]; + + let 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); + } + (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); + + state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); + state_stack.push(TraversalState::Term { subterm, term_loc }); + + self.call_policy = CallPolicy::Counted; + } + (name, arity) => { + add_chunk!(self, (name, arity), HeapCellValueTag::Str, subterm_loc); + } + } + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + if name == atom!("!") { + 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); - - 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, (name, 0), HeapCellValueTag::Var, term_loc); + } } + (HeapCellValueTag::Char, c) => { + if c == '!' { + state_stack.push(self.new_cut_state()); + } else { + return Err(CompilationError::InadmissibleQueryTerm); + } + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h != term_loc { + subterm = terms.heap[h]; + term_loc = h; + continue; + } - build_stack.push_chunk_term(clause_to_query_term( - loader, - name, - vec![], - self.call_policy, - )); - } - _ => { - return Err(CompilationError::InadmissibleQueryTerm); - } + add_chunk!(self, (atom!("call"), 1), HeapCellValueTag::Var, h); + } + _ => { + 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 { - let machine_st = LS::machine_st(&mut self.payload); - let cell = machine_st[r]; + pub(crate) fn copy_term_from_heap(&mut self, cell: HeapCellValue) -> FocusedHeap { + use crate::iterators::fact_iterator; - machine_st.read_term_from_heap(cell) + let mut term = FocusedHeap::empty(); + let mut stack = Stack::uninitialized(); + let machine_st = LS::machine_st(&mut self.payload); + + term.copy_term_from_machine_heap(machine_st, cell); + term.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(); - self.payload.clause_clauses.push((head, body)); + 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)); + + 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(&term)?; + self.add_clause_clause_if_dynamic(value)?; + + 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 name = match term.name(focus+3) { + Some(name) => name, + None => return Err(CompilationError::InconsistentEntry), }; - let spec = match terms.pop().unwrap() { - Term::Literal(_, Literal::Atom(name)) => name, - other => { - return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclSpecDomain(other), - )) - } + let spec = match term.name(focus+2) { + Some(name) => name, + None => return Err(CompilationError::InconsistentEntry), }; - let spec = to_op_decl_spec(spec)?; - - 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(); +fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result { + let name_opt = term.name(term.focus); + let arity = term.arity(term.focus); - 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)?; + if let (Some(atom!("/") | atom!("//")), 2) = (name_opt, arity) { + let arity_loc = term.nth_arg(term.focus, 2).unwrap(); - let name = match name { - Term::Literal(_, Literal::Atom(name)) => Some(name), - _ => None, - } - .ok_or(CompilationError::InvalidModuleExport)?; - - if *slash == atom!("/") { - Ok((name, arity)) - } else { - Ok((name, arity + 2)) - } + 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, } - _ => Err(CompilationError::InvalidModuleExport), + .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 name_opt == Some(atom!("/")) { + Ok((name, arity)) + } else { + Ok((name, arity + 2)) + } + } 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![]; + let mut focus = term.focus; - while let Term::Cons(_, t1, t2) = export_list { - let module_export = setup_module_export(*t1, atom_tbl)?; + 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)?); - exports.push(module_export); - export_list = *t2; + 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); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + Ok(ModuleSource::File(name)) + } else { + Err(CompilationError::InvalidUseModuleDecl) } } - Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)), - _ => 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)); + (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); - } - }, + } _ => { 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(); + 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 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), + 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)?)) - } - (atom!("non_counted_backtracking"), 1) => { - let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; - Ok(Declaration::NonCountedBacktracking(name, arity)) - } - (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)?; + loop { + read_heap_cell!(term.heap[focus], + (HeapCellValueTag::Atom, (name, arity)) => { + let term = FocusedHeapRefMut { heap: term.heap, focus }; - Ok(Declaration::UseQualifiedModule(name, exports)) + 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!("meta_predicate"), 1) => { - let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?; - Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) + (HeapCellValueTag::Str, s) => { + focus = s; } - _ => Err(CompilationError::InvalidDirective( - DirectiveError::InvalidDirective(name, terms.len()), - )), - }, - other => Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(other), - )), + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if focus != h { + focus = h; + } else { + return Err(CompilationError::InvalidDirective( + DirectiveError::ExpectedDirective(heap_loc_as_cell!(h)), + )); + } + } + _ => { + return Err(CompilationError::InvalidDirective( + DirectiveError::ExpectedDirective(term.heap[focus]) + )); + } + ); } } 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); + let code_indices = + build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs); - return QueryTerm::Clause( - Cell::default(), - ClauseType::Named(arity, name, idx), - terms, + 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); + let code_indices = + build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs); - return QueryTerm::Clause( - Cell::default(), - ClauseType::Named(arity, name, idx), - terms, + 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()); + 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)?; - let (head, var_data) = classifier.classify_fact(term)?; - Ok((Fact { head }, var_data)) - } - _ => Err(CompilationError::InadmissibleFact), + 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; + let name = term.name(term.focus); + let arity = term.arity(term.focus); - if is_rule { - let tail = terms.pop().unwrap(); - let head = terms.pop().unwrap(); - - 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(err, stub_gen())); + return Err(self.error_form(e, 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 - } - Token::Literal(c) => { - self.terms.push(Term::Literal(Cell::default(), c)); - TokenType::Term - } - Token::Var(v) => { - if v.trim() == "_" { - self.terms.push(Term::AnonVar); + if s.is_empty() { + self.terms.push(empty_list_as_cell!()); } else { - self.terms.push(Term::Var(Cell::default(), VarPtr::from(v))); + self.terms.push(string_as_cstr_cell!(s)); } - TokenType::Term + 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(HeapCellValue::from(c)); + TokenType::Term { heap_loc } + } + Token::Var(var_string) => match self.var_names_to_locs.get(&var_string).cloned() { + Some(heap_loc) => { + let heap_idx = heap_loc.get_value() as usize; + + self.var_locs.push_at_key(heap_idx, VarPtr::from(var_string)); + self.terms.push(heap_loc); + + TokenType::Term { heap_loc } + } + None => { + self.terms.push(heap_loc); + + 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() + let push_structure = |parser: &mut Self, name: Atom| -> TokenType { + parser.terms.push(atom_as_cell!(name, arity)); + + for idx in (stack_len + 2..parser.stack.len()).step_by(2) { + let subterm = parser.term_from_stack(idx).unwrap(); + parser.terms.push(subterm); + } + + 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] { - self.stack.truncate(stack_len + 1); + let idx = heap_loc.get_value() as usize; - let mut subterms: Vec<_> = self.terms.drain(idx..).collect(); - - if let Some(name) = self - .terms - .pop() - .and_then(|t| atomize_term(&self.lexer.machine_st.atom_tbl, &t)) - { + 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) - } - Ok((string_buf, None)) => { + 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); - Term::CompleteString(Cell::default(), atom) + + 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), + } } - Err(term) => term, - }); + Some((string_buf, None)) => { + let atom = + AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); + TokenType::Term { + heap_loc: string_as_cstr_cell!(atom), + } + } + 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]; + let mut term = heap_bound_store( + &self.terms, + heap_bound_deref( + &self.terms, + term, + ), + ); - if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority { + 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; + } + }; - self.stack.truncate(list_len); + 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); + + 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; + if let TokenType::Term { heap_loc } = td.tt { + let curly_idx = self.terms.len(); - let term = match self.terms.pop() { - Some(term) => term, - _ => { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )) - } - }; + oc.tt = TokenType::Term { + heap_loc: heap_loc_as_cell!(curly_idx + 2), + }; + oc.priority = 0; + oc.spec = TERM; - self.terms - .push(Term::Clause(Cell::default(), atom!("{}"), vec![term])); + self.terms.push(atom_as_cell!(atom!("{}"), 1)); + self.terms.push(heap_loc); + self.terms.push(str_loc_as_cell!(curly_idx)); - return Ok(true); + /* + 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, + inner: R, + op_dir: &OpDir, + ) -> Result<(FocusedHeap, usize), ParserError> { + let mut parser = Parser::new(inner, self); + let op_dir = CompositeOpDir::new(op_dir, None); + + let term_result = parser.read_term(&op_dir, Tokens::Default); + let lines_read = parser.lines_read(); + + term_result.map(|term| (term, lines_read)) + } + + pub(crate) fn read_to_heap( &mut self, mut inner: Stream, 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); - - parser.add_lines_read(prior_num_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, parser.lines_read() - prior_num_lines_read) + 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", ); } From f7bbdfe73ade58235ca49fbefa1d8ef4f7ebf890 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 31 Jul 2024 14:04:55 -0600 Subject: [PATCH 003/122] variable revision --- build/instructions_template.rs | 2 +- src/allocator.rs | 2 +- src/arithmetic.rs | 57 ++- src/codegen.rs | 613 +++++++++++-------------- src/debray_allocator.rs | 39 +- src/forms.rs | 99 +++- src/heap_print.rs | 12 +- src/iterators.rs | 38 +- src/machine/arithmetic_ops.rs | 2 +- src/machine/compile.rs | 32 +- src/machine/disjuncts.rs | 262 ++++++----- src/machine/gc.rs | 5 +- src/machine/lib_machine/mod.rs | 94 ++-- src/machine/loader.rs | 6 +- src/machine/machine_errors.rs | 4 +- src/machine/machine_state.rs | 45 +- src/machine/mock_wam.rs | 6 +- src/parser/ast.rs | 245 ++-------- src/parser/parser.rs | 54 +-- src/read.rs | 10 +- src/tests/call_with_inference_limit.pl | 4 +- src/variable_records.rs | 1 + 22 files changed, 738 insertions(+), 894 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index eaf1881c..84d0abad 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -911,7 +911,7 @@ fn generate_instruction_preface() -> TokenStream { functor!(atom!("intermediate"), [fixnum(i)]) } ArithmeticTerm::Number(n) => { - vec![HeapCellValue::from((n, arena))] + functor!(atom!("number"), [cell(HeapCellValue::from((n, arena)))]) } } } diff --git a/src/allocator.rs b/src/allocator.rs index cd32f41f..27def1d6 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -12,7 +12,7 @@ pub(crate) trait Allocator { lvl: Level, context: GenContext, code: &mut CodeDeque, - ); + ) -> RegType; fn mark_non_var<'a, Target: CompilationTarget<'a>>( &mut self, diff --git a/src/arithmetic.rs b/src/arithmetic.rs index c26d3cec..9253ee49 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -7,6 +7,7 @@ use crate::debray_allocator::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::*; +use crate::machine::disjuncts::*; use crate::machine::stack::Stack; use crate::parser::ast::FocusedHeap; use crate::targets::QueryInstruction; @@ -173,7 +174,7 @@ fn push_literal(interm: &mut Vec, c: Literal) -> Result<(), Arit Literal::Atom(name) if name == atom!("epsilon") => interm.push(ArithmeticTerm::Number( Number::Float(OrderedFloat(f64::EPSILON)), )), - _ => return Err(ArithmeticError::NonEvaluableFunctor(c, 0)), + _ => return Err(ArithmeticError::NonEvaluableFunctor(HeapCellValue::from(c), 0)), } Ok(()) @@ -216,7 +217,7 @@ impl<'a> ArithmeticEvaluator<'a> { atom!("float_fractional_part") => Ok(Instruction::FloatFractionalPart(a1, t)), atom!("sign") => Ok(Instruction::Sign(a1, t)), atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)), - _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)), + _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 1)), } } @@ -248,7 +249,7 @@ impl<'a> ArithmeticEvaluator<'a> { atom!("rem") => Ok(Instruction::Rem(a1, a2, t)), atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)), atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)), - _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)), + _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 2)), } } @@ -304,7 +305,7 @@ impl<'a> ArithmeticEvaluator<'a> { self.get_binary_instr(name, a1, a2, ninterm) } _ => Err(ArithmeticError::NonEvaluableFunctor( - Literal::Atom(name), + atom_as_cell!(name), arity, )), } @@ -321,30 +322,38 @@ impl<'a> ArithmeticEvaluator<'a> { let mut stack = Stack::uninitialized(); let mut iter = query_iterator::(&mut src.heap, &mut stack, term_loc); + let chunk_num = context.chunk_num(); + while let Some(term) = iter.next() { read_heap_cell!(term, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { let lvl = iter.level(); - let var_ptr = src.var_locs.read_next_var_ptr_at_key(h).unwrap(); - let var_num = var_ptr.to_var_num().unwrap(); - let old_r = self.marker.get_var_binding(var_num); - let r = if lvl == Level::Root { - self.marker.mark_non_callable(var_num, arg, context, &mut code) - } else if context.is_last() || old_r.reg_num() == 0 { - let r = old_r; + let r = match self.marker.var_data.var_locs_to_nums.get(VarPtrIndex { chunk_num, term_loc }) { + VarPtr::Numbered(var_num) => { + let old_r = self.marker.get_var_binding(var_num); - if r.reg_num() == 0 { - self.marker.mark_var::( - var_num, lvl, context, &mut code, - ) - } else { - self.marker.increment_running_count(var_num); - r + if lvl == Level::Root { + self.marker.mark_non_callable(var_num, arg, context, &mut code) + } else if context.is_last() || old_r.reg_num() == 0 { + let r = old_r; + + if r.reg_num() == 0 { + self.marker.mark_var::( + var_num, lvl, context, &mut code, + ) + } else { + self.marker.increment_running_count(var_num); + r + } + } else { + self.marker.increment_running_count(var_num); + old_r + } + } + VarPtr::Anon => { + self.marker.mark_anon_var::(lvl, context, &mut code) } - } else { - self.marker.increment_running_count(var_num); - old_r }; self.interm.push(ArithmeticTerm::Reg(r)); @@ -359,7 +368,7 @@ impl<'a> ArithmeticEvaluator<'a> { _ => { match Literal::try_from(term) { Ok(lit) => push_literal(&mut self.interm, lit)?, - _ => unreachable!() + _ => return Err(ArithmeticError::NonEvaluableFunctor(term, 0)), } } ); @@ -547,6 +556,7 @@ impl Div for Number { } } + impl PartialEq for Number { fn eq(&self, rhs: &Self) -> bool { match (self, rhs) { @@ -630,6 +640,7 @@ impl PartialOrd for Number { } } + impl Ord for Number { fn cmp(&self, rhs: &Number) -> Ordering { match (self, rhs) { diff --git a/src/codegen.rs b/src/codegen.rs index 24f90c8b..06d8c8e4 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -420,28 +420,27 @@ impl<'b> CodeGenerator<'b> { fn subterm_to_instr<'a, Target: crate::targets::CompilationTarget<'a>>( &mut self, subterm: HeapCellValue, - var_locs: &mut VarLocs, heap_loc: usize, context: GenContext, index_ptrs: &IndexMap, target: &mut CodeDeque, ) -> Option { let subterm = unmark_cell_bits!(subterm); + let chunk_num = context.chunk_num(); read_heap_cell!(subterm, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - let var_ptr = var_locs.read_next_var_ptr_at_key(h).unwrap(); - - if var_ptr.is_anon() { - Self::add_or_increment_void_instr::(target); - } else { - let var_num = var_ptr.to_var_num().unwrap(); - - self.deep_var_instr::( - var_num, - context, - target, - ); + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { + match self.marker.var_data.var_locs_to_nums.get(VarPtrIndex { chunk_num, term_loc }) { + VarPtr::Numbered(var_num) => { + self.deep_var_instr::( + var_num, + context, + target, + ); + } + VarPtr::Anon => { + Self::add_or_increment_void_instr::(target); + } } None @@ -482,7 +481,6 @@ impl<'b> CodeGenerator<'b> { &mut self, mut iter: Iter, index_ptrs: &IndexMap, - var_locs: &mut VarLocs, context: GenContext, ) -> CodeDeque where @@ -491,29 +489,33 @@ impl<'b> CodeGenerator<'b> { CodeGenerator<'b>: AddToFreeList<'a, Target>, { let mut target = CodeDeque::new(); + let chunk_num = context.chunk_num(); while let Some(term) = iter.next() { let lvl = iter.level(); let term = unmark_cell_bits!(term); read_heap_cell!(term, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { if lvl == Level::Shallow { - let var_ptr = var_locs.read_next_var_ptr_at_key(h).unwrap(); - - if var_ptr.is_anon() { - if let GenContext::Head = context { - self.marker.advance_arg(); - } else { - self.marker.mark_anon_var::(lvl, context, &mut target); + match self.marker.var_data.var_locs_to_nums.get( + VarPtrIndex { chunk_num, term_loc } + ) { + VarPtr::Numbered(var_num) => { + self.marker.mark_var::( + var_num, + lvl, + context, + &mut target, + ); + } + VarPtr::Anon => { + if let GenContext::Head = context { + self.marker.advance_arg(); + } else { + self.marker.mark_anon_var::(lvl, context, &mut target); + } } - } else { - self.marker.mark_var::( - var_ptr.to_var_num().unwrap(), - lvl, - context, - &mut target, - ); } } } @@ -544,7 +546,7 @@ impl<'b> CodeGenerator<'b> { let (subterm_loc, subterm) = subterm_index(iter.deref(), subterm_loc); self.subterm_to_instr::( - subterm, var_locs, subterm_loc, context, index_ptrs, &mut target, + subterm, subterm_loc, context, index_ptrs, &mut target, ) }) .collect(); @@ -580,7 +582,6 @@ impl<'b> CodeGenerator<'b> { let head_r_opt = self.subterm_to_instr::( head, - var_locs, head_loc, context, index_ptrs, @@ -589,7 +590,6 @@ impl<'b> CodeGenerator<'b> { let tail_r_opt = self.subterm_to_instr::( tail, - var_locs, tail_loc, context, index_ptrs, @@ -623,7 +623,7 @@ impl<'b> CodeGenerator<'b> { let (tail_loc, tail) = subterm_index(iter.deref(), heap_loc + 1); self.subterm_to_instr::( - tail, var_locs, tail_loc, context, index_ptrs, &mut target, + tail, tail_loc, context, index_ptrs, &mut target, ); } (HeapCellValueTag::PStrOffset, l) => { @@ -644,7 +644,7 @@ impl<'b> CodeGenerator<'b> { target.push_back(Target::to_pstr(lvl, pstr_offset_atom, r, true)); self.subterm_to_instr::( - tail, var_locs, tail_loc, context, index_ptrs, &mut target, + tail, tail_loc, context, index_ptrs, &mut target, ); } _ if lvl == Level::Shallow => { @@ -693,21 +693,53 @@ impl<'b> CodeGenerator<'b> { context: GenContext, code: &mut CodeDeque, ) -> Result<(), CompilationError> { - let term = terms.heap[terms.nth_arg(term_loc, 1).unwrap()]; + let first_arg_loc = terms.nth_arg(term_loc, 1).unwrap(); + let first_arg = terms.deref_loc(first_arg_loc); + + let chunk_num = context.chunk_num(); + let mut variable_marker = |marker: &mut DebrayAllocator| { + read_heap_cell!(first_arg, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, first_arg_loc) => { + match marker.var_data.var_locs_to_nums.get( + VarPtrIndex { chunk_num, term_loc: first_arg_loc }, + ) { + VarPtr::Numbered(var_num) => { + Some(marker.mark_non_callable( + var_num, + 1, + context, + code, + )) + } + VarPtr::Anon => { + Some(marker.mark_anon_var::( + Level::Shallow, + context, + code, + )) + } + } + } + _ => { + marker.advance_arg(); + None + } + ) + }; let call_instr = match ct { &InlinedClauseType::CompareNumber(mut cmp) => { self.marker.reset_arg(2); let (mut lcode, at_1) = - self.compile_arith_expr(terms, term_loc + 1, 1, context, 1)?; - - if !terms.deref_loc(term_loc + 1).is_var() { - self.marker.advance_arg(); - } + if let Some(r) = variable_marker(&mut self.marker) { + (CodeDeque::default(), Some(ArithmeticTerm::Reg(r))) + } else { + self.compile_arith_expr(terms, first_arg_loc, 1, context, 1)? + }; let (mut rcode, at_2) = - self.compile_arith_expr(terms, term_loc + 2, 2, context, 2)?; + self.compile_arith_expr(terms, first_arg_loc + 1, 2, context, 2)?; code.append(&mut lcode); code.append(&mut rcode); @@ -717,65 +749,175 @@ impl<'b> CodeGenerator<'b> { compare_number_instr!(cmp, at_1, at_2) } - InlinedClauseType::IsAtom(..) => read_heap_cell!(term, - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity == 0 { + InlinedClauseType::IsAtom(..) => { + self.marker.reset_arg(1); + + if let Some(r) = variable_marker(&mut self.marker) { + instr!("atom", r) + } else { + read_heap_cell!(first_arg, + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + instr!("$succeed") + } else { + instr!("$fail") + } + } + (HeapCellValueTag::Char) => { + instr!("$succeed") + } + _ => { + instr!("$fail") + } + ) + } + } + InlinedClauseType::IsAtomic(..) => { + self.marker.reset_arg(1); + + if let Some(r) = variable_marker(&mut self.marker) { + instr!("atomic", r) + } else { + read_heap_cell!(first_arg, + (HeapCellValueTag::Fixnum | + HeapCellValueTag::Char | + HeapCellValueTag::F64) => { + instr!("$succeed") + } + (HeapCellValueTag::Cons, cons_ptr) => { + match cons_ptr.get_tag() { + ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => { + instr!("$succeed") + } + _ => { + instr!("$fail") + } + } + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + instr!("$succeed") + } else { + instr!("$fail") + } + } + (HeapCellValueTag::Lis + | HeapCellValueTag::Str + | HeapCellValueTag::PStrLoc + | HeapCellValueTag::CStr) => { + instr!("$fail") + } + _ => { + if Literal::try_from(first_arg).is_ok() { + instr!("$succeed") + } else { + instr!("$fail") + } + } + ) + } + } + InlinedClauseType::IsCompound(..) => { + self.marker.reset_arg(1); + + if let Some(r) = variable_marker(&mut self.marker) { + instr!("compound", r) + } else { + read_heap_cell!(first_arg, + (HeapCellValueTag::Atom, (_, arity)) => { + if arity > 0 { + instr!("$succeed") + } else { + instr!("$fail") + } + } + (HeapCellValueTag::Lis + | HeapCellValueTag::Str + | HeapCellValueTag::PStrLoc + | HeapCellValueTag::CStr) => { + instr!("$succeed") + } + _ => { + instr!("$fail") + } + ) + } + } + InlinedClauseType::IsRational(..) => { + self.marker.reset_arg(1); + + if let Some(r) = variable_marker(&mut self.marker) { + instr!("rational", r) + } else { + read_heap_cell!(first_arg, + (HeapCellValueTag::Cons, cons_ptr) => { + match cons_ptr.get_tag() { + ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => { + instr!("$succeed") + } + _ => { + instr!("$fail") + } + } + } + (HeapCellValueTag::Fixnum) => { + instr!("$succeed") + } + _ => { + instr!("$fail") + } + ) + } + } + InlinedClauseType::IsFloat(..) => { + self.marker.reset_arg(1); + + if let Some(r) = variable_marker(&mut self.marker) { + instr!("float", r) + } else { + read_heap_cell!(first_arg, + (HeapCellValueTag::F64) => { + instr!("$succeed") + } + _ => { + instr!("$fail") + } + ) + } + } + InlinedClauseType::IsNumber(..) => { + self.marker.reset_arg(1); + if let Some(r) = variable_marker(&mut self.marker) { + instr!("number", r) + } else { + if Number::try_from(first_arg).is_ok() { instr!("$succeed") } else { instr!("$fail") } } - (HeapCellValueTag::Char) => { - instr!("$succeed") - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); - self.marker.reset_arg(1); + } + InlinedClauseType::IsNonVar(..) => { + self.marker.reset_arg(1); - if var_ptr.is_anon() { + if let Some(r) = variable_marker(&mut self.marker) { + instr!("nonvar", r) + } else { + if first_arg.is_var() { instr!("$fail") } else { - let r = self.marker.mark_non_callable( - var_ptr.to_var_num().unwrap(), - 1, - context, - code, - ); - - instr!("atom", r) + instr!("$succeed") } } - _ => { - instr!("$fail") - } - ), - InlinedClauseType::IsAtomic(..) => read_heap_cell!(term, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); + } + InlinedClauseType::IsInteger(..) => { + self.marker.reset_arg(1); - 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) - } - } - (HeapCellValueTag::Fixnum | - HeapCellValueTag::Char | - HeapCellValueTag::F64) => { - instr!("$succeed") - } - (HeapCellValueTag::Cons, cons_ptr) => { - match cons_ptr.get_tag() { - ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => { + if let Some(r) = variable_marker(&mut self.marker) { + instr!("integer", r) + } else { + match Number::try_from(first_arg) { + Ok(Number::Integer(_) | Number::Fixnum(_)) => { instr!("$succeed") } _ => { @@ -783,233 +925,24 @@ impl<'b> CodeGenerator<'b> { } } } - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity == 0 { + }, + InlinedClauseType::IsVar(..) => { + self.marker.reset_arg(1); + + if let Some(r) = variable_marker(&mut self.marker) { + instr!("var", r) + } else { + if first_arg.is_var() { instr!("$succeed") } else { instr!("$fail") } } - (HeapCellValueTag::Lis - | HeapCellValueTag::Str - | HeapCellValueTag::PStrLoc - | HeapCellValueTag::CStr) => { - instr!("$fail") - } - _ => { - if Literal::try_from(term).is_ok() { - instr!("$succeed") - } else { - instr!("$fail") - } - } - ), - InlinedClauseType::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") - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); - self.marker.reset_arg(1); - - if var_ptr.is_anon() { - instr!("$fail") - } else { - let r = self.marker.mark_non_callable( - var_ptr.to_var_num().unwrap(), - 1, - context, - code, - ); - - instr!("float", r) - } - } - _ => { - instr!("$fail") - } - ), - InlinedClauseType::IsNumber(..) => read_heap_cell!(term, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); - self.marker.reset_arg(1); - - if var_ptr.is_anon() { - instr!("$fail") - } else { - let r = self.marker.mark_non_callable( - var_ptr.to_var_num().unwrap(), - 1, - context, - code, - ); - - instr!("number", r) - } - } - _ => { - if Number::try_from(term).is_ok() { - instr!("$succeed") - } else { - instr!("$fail") - } - } - ), - InlinedClauseType::IsNonVar(..) => read_heap_cell!(term, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); - self.marker.reset_arg(1); - - 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!("$succeed") - } - ), - InlinedClauseType::IsInteger(..) => { - read_heap_cell!(term, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); - self.marker.reset_arg(1); - - 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); - - 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!("var", r) - } - } - _ => { - instr!("$fail") - } - ), + }, }; // inlined predicates are never counted, so this overrides nothing. self.add_call(code, call_instr, CallPolicy::Counted); - Ok(()) } @@ -1052,34 +985,15 @@ impl<'b> CodeGenerator<'b> { }; let at = read_heap_cell!(var, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); - let var_num = var_ptr.to_var_num().unwrap(); - - if self.marker.var_data.records[var_num].num_occurrences > 1 { - self.marker.mark_var::( - var_num, - Level::Shallow, - context, - code, - ); - - self.marker.mark_safe_var_unconditionally(var_num); - compile_expr!(self, terms, context, code) - } else { - /* - if var.is_var() { - let h = var.get_value() as usize; - - let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap(); - let var_num = var_ptr.to_var_num().unwrap(); - - // if var is an anonymous variable, insert - // is/2 call so that an instantiation error is - // thrown when the predicate is run. + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { + let chunk_num = context.chunk_num(); + match self.marker.var_data.var_locs_to_nums.get( + VarPtrIndex { chunk_num, term_loc }, + ) { + VarPtr::Numbered(var_num) => { if self.marker.var_data.records[var_num].num_occurrences > 1 { - let r = self.marker.mark_var::( + self.marker.mark_var::( var_num, Level::Shallow, context, @@ -1087,17 +1001,12 @@ impl<'b> CodeGenerator<'b> { ); self.marker.mark_safe_var_unconditionally(var_num); - - let at = ArithmeticTerm::Reg(r); - self.add_call(code, instr!("$get_number", at), call_policy); - - return Ok(()); } } - */ + VarPtr::Anon => {} + }; - compile_expr!(self, terms, context, code) - } + compile_expr!(self, terms, context, code) } _ => { if Number::try_from(var).is_ok() { @@ -1115,25 +1024,23 @@ impl<'b> CodeGenerator<'b> { let at = at.unwrap_or(interm!(1)); self.add_call(code, instr!("is", temp_v!(1), at), call_policy); - Ok(()) } fn compile_seq( &mut self, - terms: &mut FocusedHeap, + focused_heap: &mut FocusedHeap, clauses: &ChunkedTermVec, code: &mut CodeDeque, ) -> Result<(), CompilationError> { - let mut chunk_num = 0; let mut branch_code_stack = BranchCodeStack::new(); let mut clause_iter = ClauseIterator::new(clauses); while let Some(clause_item) = clause_iter.next() { match clause_item { - ClauseItem::Chunk(chunk) => { - for (idx, term) in chunk.iter().enumerate() { - let context = if idx + 1 < chunk.len() { + ClauseItem::Chunk { chunk_num, terms } => { + for (idx, term) in terms.iter().enumerate() { + let context = if idx + 1 < terms.len() { GenContext::Mid(chunk_num) } else { self.marker.in_tail_position = clause_iter.in_tail_position(); @@ -1201,7 +1108,7 @@ impl<'b> CodeGenerator<'b> { .. }, ) => self.compile_is_call( - terms, + focused_heap, clause.term_loc(), branch_code_stack.code(code), context, @@ -1214,7 +1121,7 @@ impl<'b> CodeGenerator<'b> { }, ) => self.compile_inlined( ct, - terms, + focused_heap, clause.term_loc(), context, branch_code_stack.code(code), @@ -1241,7 +1148,7 @@ impl<'b> CodeGenerator<'b> { } QueryTerm::Clause(clause) => { self.compile_query_line( - terms, + focused_heap, clause, context, branch_code_stack.code(code), @@ -1254,7 +1161,6 @@ impl<'b> CodeGenerator<'b> { } } - chunk_num += 1; self.marker.in_tail_position = false; self.marker.reset_contents(); } @@ -1324,7 +1230,6 @@ impl<'b> CodeGenerator<'b> { let fact = self.compile_target::( iter, &IndexMap::with_hasher(FxBuildHasher::default()), - &mut term.var_locs, GenContext::Head, ); @@ -1360,7 +1265,6 @@ impl<'b> CodeGenerator<'b> { let compiled_fact = self.compile_target::( iter, &IndexMap::with_hasher(FxBuildHasher::default()), - &mut fact.term.var_locs, GenContext::Head, ); @@ -1389,7 +1293,6 @@ impl<'b> CodeGenerator<'b> { let query = self.compile_target::( iter, &clause.code_indices, - &mut term.var_locs, context, ); diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index b473d9d1..4577b1e6 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -1,9 +1,9 @@ use crate::allocator::*; use crate::atom_table::*; use crate::codegen::SubsumedBranchHits; -use crate::forms::Level; +use crate::forms::{GenContext, Level}; use crate::instructions::*; -use crate::machine::disjuncts::VarData; +use crate::machine::disjuncts::*; use crate::machine::heap::{heap_bound_deref, heap_bound_store}; use crate::parser::ast::*; use crate::targets::*; @@ -556,7 +556,10 @@ impl DebrayAllocator { VarAlloc::Temp { safety, .. } => { *safety = VarSafetyStatus::unneeded(branch_designator); } - _ => unreachable!(), + _ => { + // the (permanent) variable might have been freed by + // this point, in which case we do nothing. + } } } @@ -703,7 +706,7 @@ impl Allocator for DebrayAllocator { lvl: Level, context: GenContext, code: &mut CodeDeque, - ) { + ) -> RegType { let r = RegType::Temp(self.alloc_reg_to_non_var()); match lvl { @@ -720,6 +723,8 @@ impl Allocator for DebrayAllocator { code.push_back(Target::argument_to_variable(r, k)); } }; + + r } fn mark_non_var<'a, Target: CompilationTarget<'a>>( @@ -934,17 +939,23 @@ impl Allocator for DebrayAllocator { continue; } - let h = var.get_value() as usize; - let var_ptr = term.var_locs.peek_next_var_ptr_at_key(h).unwrap(); - let var_num = var_ptr.to_var_num().unwrap(); - let r = self.get_var_binding(var_num); + let term_loc = var.get_value() as usize; - 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); + match self.var_data.var_locs_to_nums.get( + VarPtrIndex { chunk_num: 0, term_loc }, + ) { + VarPtr::Numbered(var_num) => { + let r = self.get_var_binding(var_num); + + if !r.is_perm() && r.reg_num() == 0 { + self.in_use.insert(idx + 1); + self.shallow_temp_mappings.insert(idx + 1, var_num); + self.var_data.records[var_num] + .allocation + .set_register(idx + 1); + } + } + VarPtr::Anon => {} } } } diff --git a/src/forms.rs b/src/forms.rs index 4dee7439..be96e30c 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -72,6 +72,37 @@ pub enum CallPolicy { Counted, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum GenContext { + Head, + Mid(usize), + Last(usize), // Mid & Last: chunk_num +} + +impl GenContext { + #[inline] + pub fn chunk_num(&self) -> usize { + match self { + GenContext::Head => 0, + &GenContext::Mid(cn) | &GenContext::Last(cn) => cn, + } + } + + #[inline] + pub fn chunk_type(&self) -> ChunkType { + match self { + GenContext::Head => ChunkType::Head, + GenContext::Mid(_) => ChunkType::Mid, + GenContext::Last(_) => ChunkType::Last, + } + } + + #[inline] + pub fn is_last(self) -> bool { + matches!(self, GenContext::Last(_)) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ChunkType { Head, @@ -98,12 +129,14 @@ impl ChunkType { #[derive(Debug)] pub enum ChunkedTerms { Branch(Vec>), - Chunk(VecDeque), + Chunk { chunk_num: usize, terms: VecDeque }, } #[derive(Debug)] pub struct ChunkedTermVec { pub chunk_vec: VecDeque, + pub current_chunk_num: usize, + pub current_chunk_type: ChunkType, } impl Deref for ChunkedTermVec { @@ -128,6 +161,8 @@ impl ChunkedTermVec { pub fn new() -> Self { Self { chunk_vec: VecDeque::new(), + current_chunk_num: 0, + current_chunk_type: ChunkType::Mid, } } @@ -136,24 +171,70 @@ impl ChunkedTermVec { .push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity))); } + pub fn push_branch_arm(&mut self, branch: VecDeque) { + match self.chunk_vec.back_mut().unwrap() { + ChunkedTerms::Branch(branches) => { + branches.push(branch); + } + ChunkedTerms::Chunk { .. } => { + self.chunk_vec.push_back(ChunkedTerms::Branch(vec![branch])); + } + } + } + + pub fn try_set_chunk_at_inlined_boundary(&mut self) -> bool { + if self.current_chunk_type.is_last() { + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; + true + } else { + false + } + } + + pub fn try_set_chunk_at_call_boundary(&mut self) -> bool { + if self.current_chunk_type.is_last() { + self.current_chunk_num += 1; + true + } else { + self.current_chunk_type = ChunkType::Last; + false + } + } + #[inline] pub fn add_chunk(&mut self) { - self.chunk_vec - .push_back(ChunkedTerms::Chunk(VecDeque::from(vec![]))); + let chunk = ChunkedTerms::Chunk { + chunk_num: self.current_chunk_num, + terms: VecDeque::from(vec![]), + }; + self.chunk_vec.push_back(chunk); + } + + pub fn current_gen_context(&self) -> GenContext { + self.current_chunk_type.to_gen_context(self.current_chunk_num) } pub fn push_chunk_term(&mut self, term: QueryTerm) { match self.chunk_vec.back_mut() { Some(ChunkedTerms::Branch(_)) => { - self.chunk_vec - .push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term]))); + let chunk = ChunkedTerms::Chunk { + chunk_num: self.current_chunk_num, + terms: VecDeque::from(vec![term]), + }; + + self.chunk_vec.push_back(chunk); } - Some(ChunkedTerms::Chunk(chunk)) => { - chunk.push_back(term); + Some(ChunkedTerms::Chunk { terms, .. }) => { + terms.push_back(term); } None => { - self.chunk_vec - .push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term]))); + let chunk = ChunkedTerms::Chunk { + chunk_num: self.current_chunk_num, + terms: VecDeque::from(vec![term]), + }; + + self.chunk_vec.push_back(chunk); } } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 26f48cb3..8d434b15 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -479,7 +479,7 @@ pub struct HCPrinter<'a, Outputter> { toplevel_spec: Option, last_item_idx: usize, parent_of_first_op: Option<(DirectedOp, usize)>, - pub var_names: IndexMap, + pub var_names: IndexMap, pub numbervars_offset: Integer, pub numbervars: bool, pub quoted: bool, @@ -795,7 +795,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if let Some(var) = self.var_names.get(&cell) { read_heap_cell!(cell, (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - return Some(var.borrow().to_string()); + return Some(var.to_string()); } _ => { self.iter.push_stack(h); @@ -837,7 +837,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { // short-circuits handle_heap_term. // self.iter.pop_stack(); - let var_str = var.borrow().to_string(); + let var_str = var.to_string(); push_space_if_amb!(self, &var_str, { append_str!(self, &var_str); @@ -865,7 +865,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { Some(var) => { // If the term is bound to a named variable, // print the variable's name to output. - let var_str = var.borrow().to_string(); + let var_str = var.to_string(); push_space_if_amb!(self, &var_str, { append_str!(self, &var_str); @@ -1924,7 +1924,7 @@ mod tests { printer .var_names - .insert(list_loc_as_cell!(1), VarPtr::from("L")); + .insert(list_loc_as_cell!(1), Rc::new("L".to_string())); let output = printer.print(); @@ -1993,7 +1993,7 @@ mod tests { printer .var_names - .insert(list_loc_as_cell!(1), VarPtr::from("L")); + .insert(list_loc_as_cell!(1), Rc::new("L".to_string())); let output = printer.print(); diff --git a/src/iterators.rs b/src/iterators.rs index 030daf81..c139f006 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -232,7 +232,7 @@ pub(crate) enum ClauseItem<'a> { FirstBranch(usize), NextBranch, BranchEnd(usize), - Chunk(&'a VecDeque), + Chunk { chunk_num: usize, terms: &'a VecDeque }, } #[derive(Debug)] @@ -275,9 +275,10 @@ impl<'a> ClauseIterator<'a> { while let Some(state) = self.state_stack.pop() { match state { - ClauseIteratorState::RemainingBranches(terms, focus) if terms.len() == focus => { - depth += 1; - } + ClauseIteratorState::RemainingBranches(terms, focus) + if terms.len() == focus => { + depth += 1; + } _ => { self.state_stack.push(state); break; @@ -295,24 +296,25 @@ impl<'a> Iterator for ClauseIterator<'a> { fn next(&mut self) -> Option { while let Some(state) = self.state_stack.pop() { match state { - ClauseIteratorState::RemainingChunks(chunks, focus) if focus < chunks.len() => { - if focus + 1 < chunks.len() { - self.state_stack - .push(ClauseIteratorState::RemainingChunks(chunks, focus + 1)); - } else { - self.remaining_chunks_on_stack -= 1; - } - - match &chunks[focus] { - ChunkedTerms::Branch(branches) => { + ClauseIteratorState::RemainingChunks(chunks, focus) + if focus < chunks.len() => { + if focus + 1 < chunks.len() { self.state_stack - .push(ClauseIteratorState::RemainingBranches(branches, 0)); + .push(ClauseIteratorState::RemainingChunks(chunks, focus + 1)); + } else { + self.remaining_chunks_on_stack -= 1; } - ChunkedTerms::Chunk(chunk) => { - return Some(ClauseItem::Chunk(chunk)); + + match &chunks[focus] { + ChunkedTerms::Branch(branches) => { + self.state_stack + .push(ClauseIteratorState::RemainingBranches(branches, 0)); + } + &ChunkedTerms::Chunk { chunk_num, ref terms } => { + return Some(ClauseItem::Chunk { chunk_num, terms }); + } } } - } ClauseIteratorState::RemainingChunks(chunks, focus) => { debug_assert_eq!(chunks.len(), focus); } diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index cdd7c515..496007bd 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1156,7 +1156,7 @@ impl MachineState { ) -> Result { let stub_gen = || functor_stub(atom!("is"), 2); - let root_loc = if value.is_ref() { + let root_loc = if value.is_ref() && !value.is_stack_var() { value.get_value() as usize } else { let type_error = self.type_error(ValidType::Evaluable, value); diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 4ddf1f33..983f5961 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -2283,40 +2283,36 @@ impl Machine { term_reg: RegType, vars: Vec, ) -> Result<(), SessionError> { - let cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg])); - - // append the variables of vars. - let focus = cell.get_value() as usize; - let header_loc = term_nth_arg(&self.machine_st.heap, focus, 0).unwrap(); - let name = term_name(&self.machine_st.heap, header_loc).unwrap(); - let old_arity = term_arity(&self.machine_st.heap, header_loc); + let body_cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg])); let new_header_loc = self.machine_st.heap.len(); - let new_arity = old_arity + vars.len(); + let 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]); - } + self.machine_st.heap.push(atom_as_cell!(atom!(""), arity)); for var in vars { self.machine_st.heap.push(var); } - let value = if new_arity > 0 { + let head_loc = if arity > 0 { str_loc_as_cell!(new_header_loc) } else { heap_loc_as_cell!(new_header_loc) }; - let mut compile = |cell| { + let term_loc = self.machine_st.heap.len(); + + self.machine_st.heap.push(atom_as_cell!(atom!(":-"), 2)); + self.machine_st.heap.push(head_loc); + self.machine_st.heap.push(body_cell); + + let mut compile = || { use crate::heap_iter::eager_stackful_preorder_iter; let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(self, InlineTermStream {}); - let mut term = loader.copy_term_from_heap(cell); + let mut term = loader.copy_term_from_heap(str_loc_as_cell!(term_loc)); let settings = CodeGenSettings { global_clock_tick: None, @@ -2326,14 +2322,14 @@ impl Machine { let value = term.heap[term.focus]; - term.var_locs = var_locs_from_iter( + term.inverse_var_locs = inverse_var_locs_from_iter( eager_stackful_preorder_iter(&mut term.heap, value), ); loader.compile_standalone_clause(term, settings) }; - let StandaloneCompileResult { clause_code, .. } = compile(value)?; + let StandaloneCompileResult { clause_code, .. } = compile()?; self.code.extend(clause_code); Ok(()) diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index 801ce078..d7f35155 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -80,9 +80,34 @@ impl BranchNumber { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ClassifiedVar { + Anon { term_loc: usize }, + InSitu { var_num: usize }, + Generated { term_loc: usize }, +} + +impl ClassifiedVar { + fn term_loc(&self) -> Option { + if let &ClassifiedVar::Generated { term_loc } = self { + Some(term_loc) + } else { + None + } + } +} + +fn to_classified_var(inverse_var_locs: &InverseVarLocs, term_loc: usize) -> ClassifiedVar { + if inverse_var_locs.contains_key(&term_loc) { + ClassifiedVar::Generated { term_loc } + } else { + ClassifiedVar::Anon { term_loc } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct VarInfo { - var_ptr: VarPtr, + var: ClassifiedVar, chunk_type: ChunkType, classify_info: ClassifyInfo, lvl: Level, @@ -90,7 +115,6 @@ pub struct VarInfo { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ChunkInfo { - chunk_num: usize, term_loc: GenContext, // pointer to incidence, term occurrence arity. vars: Vec, @@ -111,7 +135,7 @@ impl BranchInfo { } } -type BranchMapInt = IndexMap>; +type BranchMapInt = IndexMap>; #[derive(Debug, Clone)] pub struct BranchMap(BranchMapInt); @@ -174,8 +198,6 @@ enum TraversalState { pub struct VariableClassifier { call_policy: CallPolicy, current_branch_num: BranchNumber, - current_chunk_num: usize, - current_chunk_type: ChunkType, branch_map: BranchMap, var_num: usize, root_set: RootSet, @@ -183,11 +205,42 @@ pub struct VariableClassifier { global_cut_var_num_override: Option, } +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct VarPtrIndex { + pub chunk_num: usize, + pub term_loc: usize, +} + +#[derive(Debug)] +pub enum VarPtr { + Numbered(usize), + Anon, +} + +#[derive(Debug, Default)] +pub struct VarLocsToNums { + map: IndexMap, +} + +impl VarLocsToNums { + pub fn insert(&mut self, key: VarPtrIndex, var_num: usize) { + self.map.insert(key, var_num); + } + + pub fn get(&self, idx: VarPtrIndex) -> VarPtr { + self.map.get(&idx) + .cloned() + .map(VarPtr::Numbered) + .unwrap_or_else(|| VarPtr::Anon) + } +} + #[derive(Debug, Default)] pub struct VarData { pub records: VariableRecords, pub global_cut_var_num: Option, pub allocates: bool, + pub var_locs_to_nums: VarLocsToNums, } impl VarData { @@ -211,10 +264,13 @@ impl VarData { match build_stack.front_mut() { Some(ChunkedTerms::Branch(_)) => { - build_stack.push_front(ChunkedTerms::Chunk(VecDeque::from(vec![term]))); + build_stack.push_front(ChunkedTerms::Chunk { + chunk_num: 0, + terms: VecDeque::from(vec![term]), + }); } - Some(ChunkedTerms::Chunk(chunk)) => { - chunk.push_front(term); + Some(ChunkedTerms::Chunk { terms, .. }) => { + terms.push_front(term); } None => { unreachable!() @@ -256,8 +312,6 @@ impl VariableClassifier { Self { call_policy, current_branch_num: BranchNumber::default(), - current_chunk_num: 0, - current_chunk_type: ChunkType::Head, branch_map: BranchMap(BranchMapInt::new()), root_set: RootSet::new(), var_num: 0, @@ -276,7 +330,7 @@ impl VariableClassifier { Ok(self.branch_map.separate_and_classify_variables( self.var_num, self.global_cut_var_num, - self.current_chunk_num, + 0, )) } @@ -298,7 +352,7 @@ impl VariableClassifier { let mut var_data = self.branch_map.separate_and_classify_variables( self.var_num, self.global_cut_var_num, - self.current_chunk_num, + query_terms.current_chunk_num, ); var_data.emit_initial_get_level(&mut query_terms); @@ -327,32 +381,13 @@ impl VariableClassifier { } } - fn try_set_chunk_at_inlined_boundary(&mut self) -> bool { - if self.current_chunk_type.is_last() { - self.current_chunk_type = ChunkType::Mid; - self.current_chunk_num += 1; - true - } else { - false - } - } - - fn try_set_chunk_at_call_boundary(&mut self) -> bool { - if self.current_chunk_type.is_last() { - self.current_chunk_num += 1; - true - } else { - self.current_chunk_type = ChunkType::Last; - false - } - } - fn probe_body_term( &mut self, arg_c: usize, arity: usize, term: &mut FocusedHeap, term_loc: usize, + context: GenContext, ) { let classify_info = ClassifyInfo { arg_c, arity }; @@ -372,23 +407,24 @@ impl VariableClassifier { } let var_loc = subterm.get_value() as usize; - let var_ptr = term.var_locs.read_next_var_ptr_at_key(var_loc).unwrap(); + let var = to_classified_var(&term.inverse_var_locs, var_loc); - self.probe_body_var(VarInfo { - var_ptr: var_ptr.clone(), - lvl, - classify_info, - chunk_type: self.current_chunk_type, - }); + self.probe_body_var( + context, + VarInfo { + var, + lvl, + classify_info, + chunk_type: context.chunk_type(), + }, + ); } } - fn probe_body_var(&mut self, var_info: VarInfo) { - let term_loc = self - .current_chunk_type - .to_gen_context(self.current_chunk_num); - - let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone()).or_default(); + fn probe_body_var(&mut self, context: GenContext, var_info: VarInfo) { + let chunk_num = context.chunk_num(); + let branch_info_v = self.branch_map.entry(var_info.var) + .or_default(); let needs_new_branch = if let Some(last_bi) = branch_info_v.last() { !self.root_set.contains(&last_bi.branch_num) @@ -403,15 +439,14 @@ impl VariableClassifier { let branch_info = branch_info_v.last_mut().unwrap(); let needs_new_chunk = if let Some(last_ci) = branch_info.chunks.last() { - last_ci.chunk_num != self.current_chunk_num + last_ci.term_loc.chunk_num() != chunk_num } else { true }; if needs_new_chunk { branch_info.chunks.push(ChunkInfo { - chunk_num: self.current_chunk_num, - term_loc, + term_loc: context, vars: vec![], }); } @@ -420,17 +455,17 @@ impl VariableClassifier { chunk_info.vars.push(var_info); } - fn probe_in_situ_var(&mut self, var_num: usize) { + fn probe_in_situ_var(&mut self, context: GenContext, var_num: usize) { let classify_info = ClassifyInfo { arg_c: 1, arity: 1 }; let var_info = VarInfo { - var_ptr: VarPtr::from(Var::InSitu(var_num)), + var: ClassifiedVar::InSitu { var_num }, classify_info, - chunk_type: self.current_chunk_type, + chunk_type: context.chunk_type(), lvl: Level::Shallow, }; - self.probe_body_var(var_info); + self.probe_body_var(context, var_info); } fn classify_head_variables( @@ -473,13 +508,13 @@ impl VariableClassifier { continue; } - let h = subterm.get_value() as usize; - let var_ptr = term.var_locs.read_next_var_ptr_at_key(h).unwrap().clone(); + let term_loc = subterm.get_value() as usize; + let var = to_classified_var(&term.inverse_var_locs, term_loc); // the body of the if let here is an inlined // "probe_head_var". note the difference between it // and "probe_body_var". - let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default(); + let branch_info_v = self.branch_map.entry(var).or_default(); let needs_new_branch = branch_info_v.is_empty(); if needs_new_branch { @@ -491,7 +526,6 @@ impl VariableClassifier { if needs_new_chunk { branch_info.chunks.push(ChunkInfo { - chunk_num: self.current_chunk_num, term_loc: GenContext::Head, vars: vec![], }); @@ -499,9 +533,9 @@ impl VariableClassifier { let chunk_info = branch_info.chunks.last_mut().unwrap(); let var_info = VarInfo { - var_ptr, + var, classify_info, - chunk_type: self.current_chunk_type, + chunk_type: ChunkType::Head, lvl, }; @@ -515,7 +549,7 @@ impl VariableClassifier { Ok(()) } - fn new_cut_state(&mut self) -> TraversalState { + fn new_cut_state(&mut self, context: GenContext) -> TraversalState { let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override { (var_num, false) } else if let Some(var_num) = self.global_cut_var_num { @@ -529,7 +563,7 @@ impl VariableClassifier { (var_num, true) }; - self.probe_in_situ_var(var_num); + self.probe_in_situ_var(context, var_num); TraversalState::Cut { var_num, is_global } } @@ -546,8 +580,6 @@ impl VariableClassifier { }]; let mut build_stack = ChunkedTermVec::new(); - self.current_chunk_type = ChunkType::Mid; - 'outer: while let Some(traversal_st) = state_stack.pop() { match traversal_st { TraversalState::AddBranchNum(branch_num) => { @@ -568,21 +600,22 @@ impl VariableClassifier { TraversalState::BuildDisjunct(preceding_len) => { flatten_into_disjunct(&mut build_stack, preceding_len); - self.current_chunk_type = ChunkType::Mid; - self.current_chunk_num += 1; + build_stack.current_chunk_type = ChunkType::Mid; + build_stack.current_chunk_num += 1; } TraversalState::BuildFinalDisjunct(preceding_len) => { flatten_into_disjunct(&mut build_stack, preceding_len); - self.current_chunk_type = ChunkType::Mid; - self.current_chunk_num += 1; + build_stack.current_chunk_type = ChunkType::Mid; + build_stack.current_chunk_num += 1; } TraversalState::GetCutPoint { var_num, prev_b } => { - if self.try_set_chunk_at_inlined_boundary() { + if build_stack.try_set_chunk_at_inlined_boundary() { build_stack.add_chunk(); } - self.probe_in_situ_var(var_num); + let context = build_stack.current_gen_context(); + self.probe_in_situ_var(context, var_num); build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b }); } TraversalState::OverrideGlobalCutVar(var_num) => { @@ -592,11 +625,12 @@ impl VariableClassifier { self.global_cut_var_num_override = old_override; } TraversalState::Cut { var_num, is_global } => { - if self.try_set_chunk_at_inlined_boundary() { + if build_stack.try_set_chunk_at_inlined_boundary() { build_stack.add_chunk(); } - self.probe_in_situ_var(var_num); + let context = build_stack.current_gen_context(); + self.probe_in_situ_var(context, var_num); build_stack.push_chunk_term(if is_global { QueryTerm::GlobalCut(var_num) @@ -608,11 +642,12 @@ impl VariableClassifier { }); } TraversalState::CutPrev(var_num) => { - if self.try_set_chunk_at_inlined_boundary() { + if build_stack.try_set_chunk_at_inlined_boundary() { build_stack.add_chunk(); } - self.probe_in_situ_var(var_num); + let context = build_stack.current_gen_context(); + self.probe_in_situ_var(context, var_num); build_stack.push_chunk_term(QueryTerm::LocalCut { var_num, @@ -630,24 +665,26 @@ impl VariableClassifier { mut term_loc, } => { // return true iff new chunk should be added. - let update_chunk_data = |classifier: &mut Self, key: PredicateKey| { + let update_chunk_data = |build_stack: &mut ChunkedTermVec, key: PredicateKey| { if ClauseType::is_inlined(key.0, key.1) { - classifier.try_set_chunk_at_inlined_boundary() + build_stack.try_set_chunk_at_inlined_boundary() } else { - classifier.try_set_chunk_at_call_boundary() + build_stack.try_set_chunk_at_call_boundary() } }; macro_rules! add_chunk { - ($classifier:ident, $key:expr, $tag:expr, $term_loc:expr) => {{ - if update_chunk_data($classifier, $key) { + ($key:expr, $tag:expr, $term_loc:expr) => {{ + if update_chunk_data(&mut build_stack, $key) { build_stack.add_chunk(); } + let context = build_stack.current_gen_context(); + for (arg_c, term_loc) in ($term_loc + 1 ..= $term_loc + $key.1).enumerate() { - $classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc); + self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context); } build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( @@ -655,21 +692,23 @@ impl VariableClassifier { $key, terms.as_ref_mut($term_loc), HeapCellValue::build_with($tag, $term_loc as u64), - $classifier.call_policy, + self.call_policy, ))); }}; } macro_rules! add_qualified_chunk { - ($classifier:ident, $module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{ - if update_chunk_data($classifier, $key) { + ($module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{ + if update_chunk_data(&mut build_stack, $key) { build_stack.add_chunk(); } + let context = build_stack.current_gen_context(); + for (arg_c, term_loc) in ($term_loc + 1..$term_loc + $key.1 + 1).enumerate() { - $classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc); + self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context); } build_stack.push_chunk_term(QueryTerm::Clause( @@ -679,7 +718,7 @@ impl VariableClassifier { $module_name, terms.as_ref_mut($term_loc), HeapCellValue::build_with($tag, $term_loc as u64), - $classifier.call_policy, + self.call_policy, ), )); }}; @@ -698,7 +737,7 @@ impl VariableClassifier { continue; } - add_chunk!(self, (name, 2), HeapCellValueTag::Str, subterm_loc); + add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc); } (atom!(","), 2) => { let head_loc = terms.nth_arg(subterm_loc, 1).unwrap(); @@ -764,8 +803,8 @@ impl VariableClassifier { TraversalState::BuildFinalDisjunct(build_stack_len); } - self.current_chunk_type = ChunkType::Mid; - self.current_chunk_num += 1; + build_stack.current_chunk_type = ChunkType::Mid; + build_stack.current_chunk_num += 1; } (atom!("->"), 2) => { let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); @@ -841,8 +880,8 @@ impl VariableClassifier { }); state_stack.push(TraversalState::AddBranchNum(branch_num)); - self.current_chunk_type = ChunkType::Mid; - self.current_chunk_num += 1; + build_stack.current_chunk_type = ChunkType::Mid; + build_stack.current_chunk_num += 1; self.var_num += 1; } @@ -862,7 +901,6 @@ impl VariableClassifier { .get_name_and_arity(); add_qualified_chunk!( - self, module_name, key, HeapCellValueTag::Str, @@ -874,7 +912,6 @@ impl VariableClassifier { let key = (predicate_name, predicate_arity); add_qualified_chunk!( - self, module_name, key, HeapCellValueTag::Str, @@ -890,12 +927,14 @@ impl VariableClassifier { _ => {} ); - if update_chunk_data(self, (atom!("call"), 2)) { + if update_chunk_data(&mut build_stack, (atom!("call"), 2)) { build_stack.add_chunk(); } - self.probe_body_term(1, 0, terms, module_name_loc); - self.probe_body_term(2, 0, terms, predicate_term_loc); + let context = build_stack.current_gen_context(); + + self.probe_body_term(1, 0, terms, module_name_loc, context); + self.probe_body_term(2, 0, terms, predicate_term_loc, context); let h = terms.heap.len(); @@ -920,7 +959,7 @@ impl VariableClassifier { self.call_policy = CallPolicy::Counted; } (name, arity) => { - add_chunk!(self, (name, arity), HeapCellValueTag::Str, subterm_loc); + add_chunk!((name, arity), HeapCellValueTag::Str, subterm_loc); } } } @@ -928,14 +967,16 @@ impl VariableClassifier { debug_assert_eq!(arity, 0); if name == atom!("!") { - state_stack.push(self.new_cut_state()); + let context = build_stack.current_gen_context(); + state_stack.push(self.new_cut_state(context)); } else { - add_chunk!(self, (name, 0), HeapCellValueTag::Var, term_loc); + add_chunk!((name, 0), HeapCellValueTag::Var, term_loc); } } (HeapCellValueTag::Char, c) => { if c == '!' { - state_stack.push(self.new_cut_state()); + let context = build_stack.current_gen_context(); + state_stack.push(self.new_cut_state(context)); } else { return Err(CompilationError::InadmissibleQueryTerm); } @@ -947,7 +988,7 @@ impl VariableClassifier { continue; } - add_chunk!(self, (atom!("call"), 1), HeapCellValueTag::Var, h); + add_chunk!((atom!("call"), 1), HeapCellValueTag::Var, h); } _ => { return Err(CompilationError::InadmissibleQueryTerm); @@ -975,13 +1016,13 @@ impl BranchMap { records: VariableRecords::new(var_num), global_cut_var_num, allocates: current_chunk_num > 0, + var_locs_to_nums: VarLocsToNums::default(), }; for (var, branches) in self.iter_mut() { - let (mut var_num, var_num_incr) = if let Var::InSitu(var_num) = *var.borrow() { - (var_num, false) - } else { - (var_data.records.len(), true) + let (mut var_num, var_num_incr) = match var { + &ClassifiedVar::InSitu { var_num} => (var_num, false), + _ => (var_data.records.len(), true) }; for branch in branches.iter_mut() { @@ -999,10 +1040,13 @@ impl BranchMap { for var_info in chunk.vars.iter_mut() { if var_info.lvl == Level::Shallow { - let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num); + let context = var_info + .chunk_type + .to_gen_context(chunk.term_loc.chunk_num()); + temp_var_data .use_set - .insert((term_loc, var_info.classify_info.arg_c)); + .insert((context, var_info.classify_info.arg_c)); } } @@ -1018,9 +1062,13 @@ impl BranchMap { for chunk in branch.chunks.iter_mut() { var_data.records[var_num].num_occurrences += chunk.vars.len(); - for var_info in chunk.vars.iter_mut() { - let is_anon = var_info.var_ptr.is_anon(); - var_info.var_ptr.set(Var::Generated { is_anon, var_num }); + if let Some(term_loc) = var.term_loc() { + let chunk_num = chunk.term_loc.chunk_num(); + + var_data.var_locs_to_nums.insert( + VarPtrIndex { chunk_num, term_loc }, + var_num, + ); } } } diff --git a/src/machine/gc.rs b/src/machine/gc.rs index 4d3d45ec..456f075f 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -33,10 +33,12 @@ pub(crate) trait UnmarkPolicy { } } +#[cfg(test)] pub(crate) struct IteratorUMP { mark_phase: bool, } +#[cfg(test)] fn invert_marker(iter: &mut StacklessPreOrderHeapIter) { if iter.heap[iter.start].get_forwarding_bit() { while !iter.backward() {} @@ -50,6 +52,7 @@ fn invert_marker(iter: &mut StacklessPreOrderHeapIter) { while iter.forward().is_some() {} } +#[cfg(test)] impl UnmarkPolicy for IteratorUMP { #[inline(always)] fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option { @@ -150,8 +153,8 @@ impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> { } } +#[cfg(test)] impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> { - #[cfg(test)] pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self { heap[start].set_forwarding_bit(true); let next = heap[start].get_value(); diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index 887d2a23..79a8a1cf 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -467,11 +467,20 @@ impl Iterator for QueryState<'_> { // this should halt the search for solutions as it // does in the Scryer top-level. the exception term is // contained in self.machine_st.ball. - let h = machine.machine_st.heap.len(); - machine + let h = machine.machine_st.heap.cell_len(); + + if let Err(resource_err_loc) = machine .machine_st .heap - .extend(machine.machine_st.ball.stub.clone()); + .append(&machine.machine_st.ball.stub) + { + return Some(Err(Term::from_heapcell( + machine, + machine.machine_st.heap[resource_err_loc], + &mut IndexMap::new(), + ))); + } + let exception_term = Term::from_heapcell(machine, machine.machine_st.heap[h], &mut var_names.clone()); @@ -487,7 +496,7 @@ impl Iterator for QueryState<'_> { } if machine.machine_st.p == LIB_QUERY_SUCCESS { - if term_write_result.var_dict.is_empty() { + if term_write_result.inverse_var_locs.is_empty() { self.machine.machine_st.backtrack(); return Some(Ok(LeafAnswer::True)); } @@ -496,47 +505,39 @@ impl Iterator for QueryState<'_> { } let mut bindings: BTreeMap = BTreeMap::new(); + let inverse_var_locs = &term_write_result.inverse_var_locs; - let var_dict = &term_write_result.var_dict; - - for (var_key, term_to_be_printed) in var_dict.iter() { - let mut var_name = var_key.to_string(); + for (var_loc, var_name) in inverse_var_locs.iter() { if var_name.starts_with('_') { - let should_print = var_names.values().any(|x| match x.borrow().clone() { - Var::Named(v) => v == var_name, - _ => false, - }); + let should_print = var_names.values().any(|v| v == var_name); if !should_print { continue; } } - let mut term = - Term::from_heapcell(machine, *term_to_be_printed, &mut var_names.clone()); + let var_loc = *var_loc; + let term = + Term::from_heapcell(machine, heap_loc_as_cell!(var_loc), &mut var_names.clone()); if let Term::Var(ref term_str) = term { - if *term_str == var_name { + if *term_str == **var_name { continue; } - // Var dict is in the order things appear in the query. If var_name appears - // after term in the query, switch their places. - let var_name_idx = var_dict - .get_index_of(&VarKey::VarPtr(Var::Named(var_name.clone()).into())) - .unwrap(); - let term_idx = - var_dict.get_index_of(&VarKey::VarPtr(Var::Named(term_str.clone()).into())); - if let Some(idx) = term_idx { - if idx < var_name_idx { - let new_term = Term::Var(var_name); - let new_var_name = term_str.into(); - term = new_term; - var_name = new_var_name; - } + // inverse_var_locs is in the order things appear in + // the query. If var_name appears after term in the + // query, switch their places. + let var_cell = machine + .machine_st + .store(machine.machine_st.deref(machine.machine_st.heap[var_loc])); + + if (var_cell.get_value() as usize) < var_loc { + bindings.insert(term_str.clone(), Term::Var(var_name.to_string())); + continue; } } - bindings.insert(var_name, term); + bindings.insert(var_name.to_string(), term); } // NOTE: there are outstanding choicepoints, backtrack @@ -605,27 +606,10 @@ impl Machine { self.allocate_stub_choice_point(); - // Write parsed term to heap - let term_write_result = - write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl) - .expect("couldn't write term to heap"); - - let var_names: IndexMap<_, _> = term_write_result - .var_dict - .iter() - .map(|(var_key, cell)| match var_key { - // NOTE: not the intention behind Var::InSitu here but - // we can hijack it to store anonymous variables - // without creating problems. - VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))), - VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()), - }) - .collect(); - // Write term to heap - self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc]; - + self.machine_st.registers[1] = self.machine_st.heap[term.focus]; self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC; + let call_index_p = self .indices .code_dir @@ -634,12 +618,22 @@ impl Machine { .local() .unwrap(); + let var_names: IndexMap<_, _> = term + .inverse_var_locs + .iter() + .map(|(var_loc, var)| { + let cell = self.machine_st.heap[*var_loc]; + (cell, var.clone()) + }) + .collect(); + self.machine_st.execute_at_index(1, call_index_p); let stub_b = self.machine_st.b; + QueryState { machine: self, - term: term_write_result, + term, stub_b, var_names, called: false, diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 5b96fe37..40800f97 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -499,7 +499,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let machine_st = LS::machine_st(&mut self.payload); term.copy_term_from_machine_heap(machine_st, cell); - term.var_locs = var_locs_from_iter( + term.inverse_var_locs = inverse_var_locs_from_iter( fact_iterator::( &mut term.heap, &mut stack, @@ -1107,7 +1107,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ); let value = term.heap[term.focus]; - term.var_locs = var_locs_from_iter(eager_stackful_preorder_iter(&mut term.heap, value)); + term.inverse_var_locs = inverse_var_locs_from_iter( + eager_stackful_preorder_iter(&mut term.heap, value), + ); Ok(term) } diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 511695d9..ea8db552 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -472,8 +472,8 @@ impl MachineState { fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError { match err { ArithmeticError::UninstantiatedVar => self.instantiation_error(), - ArithmeticError::NonEvaluableFunctor(literal, arity) => { - let culprit = functor!(atom!("/"), [literal(literal), fixnum(arity)]); + ArithmeticError::NonEvaluableFunctor(cell, arity) => { + let culprit = functor!(atom!("/"), [cell(cell), fixnum(arity)]); self.type_error(ValidType::Evaluable, culprit) } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index bd2b217f..1c18f16a 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -22,6 +22,7 @@ use indexmap::IndexMap; use std::convert::TryFrom; use std::fmt; use std::ops::{Index, IndexMut}; +use std::rc::Rc; use std::sync::Arc; pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1]; @@ -202,13 +203,13 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn fn push_var_eq_functors( heap: &mut Heap, - iter: impl Iterator, // (&'a VarPtr, &'a HeapCellValue)>, + iter: impl Iterator, atom_tbl: &AtomTable, ) -> Vec { let mut list_of_var_eqs = vec![]; - for (var_loc, var_ptr) in iter { // (var, binding) in iter { - let var_atom = AtomTable::build_with(atom_tbl, &*var_ptr.borrow().to_string()); + for (var_loc, var) in iter { // (var, binding) in iter { + let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); let h = heap.len(); let binding = heap[var_loc]; @@ -541,20 +542,15 @@ impl MachineState { pub fn write_read_term_options( &mut self, - mut var_list: Vec<(VarPtr, HeapCellValue, usize)>, + mut var_list: Vec<(Var, HeapCellValue, usize)>, singleton_var_list: Vec, ) -> CallResult { var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2)); let list_of_var_eqs = push_var_eq_functors( &mut self.heap, - var_list.iter().filter_map(|(var_ptr, var, _)| { - if var_ptr.is_anon() { - None - } else { - let var_loc = var.get_value() as usize; - Some((var_loc, var_ptr.clone())) - } + var_list.iter().map(|(var_name, var, _)| { + (var.get_value() as usize, var_name.clone()) }), &self.atom_tbl, ); @@ -630,20 +626,14 @@ impl MachineState { let singleton_var_list = push_var_eq_functors( &mut self.heap, - term.var_locs + term.inverse_var_locs .iter() - .filter_map(|(var_loc, var_ptrs)| { - let var_ptr = var_ptrs.front().unwrap(); - - if var_ptr.is_anon() { - return None; - } - + .filter_map(|(var_loc, var_name)| { // add h to offset the term variable into its heap location. - let r = Ref::heap_cell(var_loc); + let r = Ref::heap_cell(*var_loc); if singleton_var_set.get(&r).cloned().unwrap_or(false) { - Some((var_loc, var_ptr.clone())) + Some((*var_loc, var_name.clone())) } else { None } @@ -659,13 +649,12 @@ impl MachineState { let mut var_list = Vec::with_capacity(singleton_var_set.len()); - for (var_loc, var_ptrs) in term.var_locs.iter() { - let var_ptr = var_ptrs.front().unwrap().clone(); + for (var_loc, var_name) in term.inverse_var_locs { let r = Ref::heap_cell(var_loc); let cell = self.heap[var_loc]; if let Some(idx) = singleton_var_set.get_index_of(&r) { - var_list.push((var_ptr, cell, idx)); + var_list.push((var_name, cell, idx)); } } @@ -787,7 +776,7 @@ impl MachineState { let printer = match self.try_from_list(self.registers[6], stub_gen) { Ok(addrs) => { - let mut var_names: IndexMap = IndexMap::new(); + let mut var_names: IndexMap = IndexMap::new(); for addr in addrs { read_heap_cell!(addr, @@ -805,18 +794,18 @@ impl MachineState { read_heap_cell!(atom, (HeapCellValueTag::Char, c) => { - var_names.insert(var, VarPtr::from(c.to_string())); + var_names.insert(var, Rc::new(c.to_string())); } (HeapCellValueTag::Atom, (name, _arity)) => { debug_assert_eq!(_arity, 0); - var_names.insert(var, VarPtr::from(&*name.as_str())); + var_names.insert(var, Rc::new(name.as_str().to_owned())); } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.heap[s]) .get_name_and_arity(); debug_assert_eq!(arity, 0); - var_names.insert(var, VarPtr::from(&*name.as_str())); + var_names.insert(var, Rc::new(name.as_str().to_owned())); } _ => { unreachable!(); diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 5b0096fc..badd6255 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -59,10 +59,10 @@ impl MockWAM { print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc); let var_names = term_write_result - .var_locs + .inverse_var_locs .iter() - .map(|(var_loc, var_ptrs)| { - (self.machine_st.heap[var_loc], var_ptrs.front().unwrap().clone()) + .map(|(var_loc, var_name)| { + (self.machine_st.heap[*var_loc], var_name.clone()) }) .collect(); diff --git a/src/parser/ast.rs b/src/parser/ast.rs index c080b7ea..727e9b78 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -9,12 +9,10 @@ use crate::machine::machine_indices::*; use crate::machine::machine_state::*; use crate::types::*; -use std::cell::{Ref, RefCell, RefMut}; -use std::collections::VecDeque; use std::fmt; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::io::{Error as IOError, ErrorKind}; -use std::ops::{Deref, Neg, RangeBounds}; +use std::ops::Neg; use std::rc::Rc; use std::sync::Arc; use std::vec::Vec; @@ -311,26 +309,11 @@ macro_rules! temp_v { }; } -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum GenContext { - Head, - Mid(usize), - Last(usize), // Mid & Last: chunk_num -} - -impl GenContext { - #[inline] - pub fn chunk_num(self) -> usize { - match self { - GenContext::Head => 0, - GenContext::Mid(cn) | GenContext::Last(cn) => cn, - } - } - - #[inline] - pub fn is_last(self) -> bool { - matches!(self, GenContext::Last(_)) - } +#[macro_export] +macro_rules! perm_v { + ($x:expr) => { + $crate::parser::ast::RegType::Perm($x) + }; } #[bitfield] @@ -426,7 +409,7 @@ pub fn default_op_dir() -> OpDir { #[derive(Debug, Clone)] pub enum ArithmeticError { - NonEvaluableFunctor(Literal, usize), + NonEvaluableFunctor(HeapCellValue, usize), UninstantiatedVar, } @@ -685,111 +668,7 @@ impl Literal { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VarPtr(Rc>); - -impl Hash for VarPtr { - #[inline(always)] - fn hash(&self, hasher: &mut H) { - self.borrow().hash(hasher) - } -} - -impl Deref for VarPtr { - type Target = RefCell; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - self.0.deref() - } -} - -impl VarPtr { - #[inline] - pub(crate) fn is_anon(&self) -> bool { - match *self.borrow() { - Var::Anon | Var::Generated { is_anon: true, .. } => true, - _ => false, - } - } - - #[inline(always)] - pub(crate) fn borrow(&self) -> Ref<'_, Var> { - self.0.borrow() - } - - #[inline(always)] - pub(crate) fn borrow_mut(&self) -> RefMut<'_, Var> { - self.0.borrow_mut() - } - - pub(crate) fn to_var_num(&self) -> Option { - match *self.borrow() { - Var::Generated { var_num, .. } => Some(var_num), - _ => None, - } - } - - pub(crate) fn set(&self, var: Var) { - let mut var_ref = self.borrow_mut(); - *var_ref = var; - } -} - -impl From for VarPtr { - #[inline(always)] - fn from(value: Var) -> VarPtr { - VarPtr(Rc::new(RefCell::new(value))) - } -} - -impl From for VarPtr { - #[inline(always)] - fn from(value: String) -> VarPtr { - VarPtr::from(Var::from(value)) - } -} - -impl From<&str> for VarPtr { - #[inline(always)] - fn from(value: &str) -> VarPtr { - VarPtr::from(value.to_owned()) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Var { - Anon, - Generated { is_anon: bool, var_num: usize }, - InSitu(usize), - Named(String), -} - -impl From for Var { - #[inline(always)] - fn from(value: String) -> Var { - Var::Named(value) - } -} - -impl From<&str> for Var { - #[inline(always)] - fn from(value: &str) -> Var { - Var::Named(value.to_owned()) - } -} - -impl Var { - #[allow(clippy::inherent_to_string)] - #[inline(always)] - pub fn to_string(&self) -> String { - match self { - Var::Anon => "_".to_owned(), - Var::InSitu(var_num) | Var::Generated { var_num, .. } => format!("_{}", var_num), - Var::Named(value) => value.to_owned(), - } - } -} +pub type Var = Rc; pub(crate) fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) { let subterm = heap[subterm_loc]; @@ -1050,7 +929,7 @@ pub fn term_arity(heap: &[HeapCellValue], mut term_loc: usize) -> usize { } } -pub fn var_locs_from_iter>(iter: I) -> VarLocs { +pub fn inverse_var_locs_from_iter>(iter: I) -> InverseVarLocs { let mut occurrence_set: IndexMap = IndexMap::with_hasher(FxBuildHasher::default()); @@ -1061,21 +940,20 @@ pub fn var_locs_from_iter>(iter: I) -> VarLocs } } - VarLocs( - occurrence_set - .into_iter() - .map(|(var, count)| { - let key = var.get_value() as usize; - let queue = if count > 1 { - (0 .. count).map(|_| VarPtr::from(format!("_{}", key))).collect() - } else { - (0 .. count).map(|_| VarPtr::from(Var::Anon)).collect() - }; + let mut inverse_var_locs = InverseVarLocs::default(); - (key, queue) - }) - .collect() - ) + for (var, count) in occurrence_set { + let var_loc = var.get_value() as usize; + + if count > 1 { + inverse_var_locs.insert( + var_loc, + Rc::new(format!("_{}", var_loc)), + ); + } + } + + inverse_var_locs } /* @@ -1137,82 +1015,14 @@ pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Op } } -pub type VarNamesToLocs = IndexMap; - -#[derive(Debug, Default)] -pub struct VarLocs(IndexMap, FxBuildHasher>); - -impl VarLocs { - pub fn get(&self, key: usize) -> Option<&VarPtr> { - self.0.get(&key) - .and_then(|queue| { - queue.front() - }) - } - - // if a queue of VarPtr's is stored at location key, pop the front - // if it exists and pass it along to wrapper, returning a value of - // type R. A return value of None indicates that the key doesn't - // exist (the map containing a key necessarily means its queue - // value is non-empty). - fn rotate_latest_mut( - &mut self, - key: usize, - wrapper: impl FnOnce(&VarPtr) -> R, - ) -> Option { - self.0.get_mut(&key) - .and_then(move |queue| { - if let Some(var_ptr) = queue.pop_front() { - let result = wrapper(&var_ptr); - queue.push_back(var_ptr); - Some(result) - } else { - None - } - }) - } - - pub fn peek_next_var_ptr_at_key(&self, key: usize) -> Option<&VarPtr> { - self.0.get(&key).and_then(|queue| queue.front()) - } - - pub fn read_next_var_ptr_at_key(&mut self, key: usize) -> Option { - self.rotate_latest_mut(key, VarPtr::clone) - } - - pub fn push_at_key(&mut self, key: usize, var_ptr: VarPtr) { - let entry = self.0.entry(key).or_default(); - entry.push_back(var_ptr); - } - - #[inline] - pub fn iter(&self) -> impl Iterator)> { - self.0.iter().map(|(&k, v)| (k, v)) - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - #[inline] - pub fn drain(&mut self, range: R) -> indexmap::map::Drain> - where R: RangeBounds - { - self.0.drain(range) - } - - #[inline] - pub fn insert(&mut self, key: usize, var_ptrs: VecDeque) { - self.0.insert(key, var_ptrs); - } -} +pub type VarLocs = IndexMap; +pub type InverseVarLocs = IndexMap; #[derive(Debug)] pub struct FocusedHeap { pub heap: Vec, pub focus: usize, - pub var_locs: VarLocs, + pub inverse_var_locs: InverseVarLocs, } impl FocusedHeap { @@ -1220,7 +1030,7 @@ impl FocusedHeap { Self { heap: vec![], focus: 0, - var_locs: VarLocs::default(), + inverse_var_locs: InverseVarLocs::default(), } } @@ -1251,7 +1061,6 @@ impl FocusedHeap { FocusedHeapRefMut { heap: &mut self.heap, focus, - // var_locs: &self.var_locs, } } diff --git a/src/parser/parser.rs b/src/parser/parser.rs index bffca39b..7eead62c 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -10,11 +10,9 @@ use crate::parser::char_reader::*; use crate::parser::lexer::*; use crate::types::*; -use fxhash::FxBuildHasher; -use indexmap::IndexMap; - use std::mem; use std::ops::Neg; +use std::rc::Rc; #[derive(Debug, Clone, Copy, PartialEq)] enum TokenType { @@ -184,7 +182,7 @@ pub struct Parser<'a, R> { stack: Vec, terms: Vec, var_locs: VarLocs, - var_names_to_locs: VarNamesToLocs, + inverse_var_locs: InverseVarLocs, } fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> { @@ -326,7 +324,7 @@ impl<'a, R: CharRead> Parser<'a, R> { stack: vec![], terms: vec![], var_locs: VarLocs::default(), - var_names_to_locs: IndexMap::with_hasher(FxBuildHasher::default()), + inverse_var_locs: InverseVarLocs::default(), } } @@ -337,7 +335,7 @@ impl<'a, R: CharRead> Parser<'a, R> { stack: vec![], terms: vec![], var_locs: VarLocs::default(), - var_names_to_locs: IndexMap::with_hasher(FxBuildHasher::default()), + inverse_var_locs: InverseVarLocs::default(), } } @@ -501,32 +499,28 @@ impl<'a, R: CharRead> Parser<'a, R> { self.terms.push(HeapCellValue::from(c)); TokenType::Term { heap_loc } } - Token::Var(var_string) => match self.var_names_to_locs.get(&var_string).cloned() { - Some(heap_loc) => { - let heap_idx = heap_loc.get_value() as usize; + Token::Var(var_string) => { + let var = Rc::new(var_string); - 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); - - if var_string.trim() != "_" { - self.var_names_to_locs.insert(var_string.clone(), heap_loc); + match self.var_locs.get(&var).cloned() { + Some(heap_loc) => { + self.terms.push(heap_loc); + TokenType::Term { heap_loc } } + None => { + self.terms.push(heap_loc); - self.var_locs.push_at_key( - heap_loc.get_value() as usize, - if var_string.trim() == "_" { - VarPtr::from(Var::Anon) - } else { - VarPtr::from(var_string) - }, - ); + // if var_string == "_", it not being present + // as a key of self.var_locs means it is + // anonymous. - TokenType::Term { heap_loc } + if var.trim() != "_" { + self.var_locs.insert(var.clone(), heap_loc); + self.inverse_var_locs.insert(heap_loc.get_value() as usize, var); + } + + TokenType::Term { heap_loc } + } } }, Token::Comma => TokenType::Comma, @@ -755,7 +749,7 @@ impl<'a, R: CharRead> Parser<'a, R> { pub fn reset(&mut self) { self.stack.clear(); - self.var_names_to_locs.clear(); + self.var_locs.clear(); } fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { @@ -1356,7 +1350,7 @@ impl<'a, R: CharRead> Parser<'a, R> { }) => Ok(FocusedHeap { heap: mem::replace(&mut self.terms, vec![]), focus: heap_loc.get_value() as usize, - var_locs: mem::replace(&mut self.var_locs, VarLocs::default()), + inverse_var_locs: mem::replace(&mut self.inverse_var_locs, InverseVarLocs::default()), }), _ => Err(ParserError::IncompleteReduction( self.lexer.loc_to_err_src(), diff --git a/src/read.rs b/src/read.rs index 9759caf3..e2fcfa0c 100644 --- a/src/read.rs +++ b/src/read.rs @@ -52,15 +52,15 @@ impl FocusedHeap { let heap_len = machine_st.heap.len(); machine_st.heap.extend(copy_and_align_iter(self.heap.drain(..), 0, heap_len as i64)); - let mut var_locs = VarLocs::default(); + let mut inverse_var_locs = InverseVarLocs::default(); - for (var_loc, var_ptrs) in self.var_locs.drain(..) { - var_locs.insert(var_loc + heap_len, var_ptrs); + for (var_loc, var_name) in self.inverse_var_locs.drain(..) { + inverse_var_locs.insert(var_loc + heap_len, var_name); } TermWriteResult { heap_loc: self.focus + heap_len, - var_locs, + inverse_var_locs, } } } @@ -309,5 +309,5 @@ impl CharRead for ReadlineStream { #[derive(Debug)] pub struct TermWriteResult { pub heap_loc: usize, - pub var_locs: VarLocs, + pub inverse_var_locs: InverseVarLocs, } diff --git a/src/tests/call_with_inference_limit.pl b/src/tests/call_with_inference_limit.pl index 18fda2dd..84b78a75 100644 --- a/src/tests/call_with_inference_limit.pl +++ b/src/tests/call_with_inference_limit.pl @@ -14,7 +14,7 @@ test_queries_on_call_with_inference_limit :- error, true), \+ call_with_inference_limit(g(X), 5, R), - maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), + maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), % TODO this line fails! findall([R,X], call_with_inference_limit(g(X), 11, R), [[true, 1], @@ -30,7 +30,7 @@ test_queries_on_call_with_inference_limit :- [true, 4], [!, 5]]), findall([R,X], - (call_with_inference_limit(g(X), 5, R), call(true)), + (call_with_inference_limit(g(X), 2, R), call(true)), [[true, 1], [true, 2], [inference_limit_exceeded, _]]), diff --git a/src/variable_records.rs b/src/variable_records.rs index 528ded35..a2b98918 100644 --- a/src/variable_records.rs +++ b/src/variable_records.rs @@ -1,4 +1,5 @@ use crate::parser::ast::*; +use crate::forms::GenContext; use bit_set::*; use fxhash::FxBuildHasher; From c0f72704eca9f5ca9904048082e11f16c022cfac Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 13 May 2024 18:00:56 -0600 Subject: [PATCH 004/122] introduce bespoke Heap type for in-heap partial strings --- .github/workflows/ci.yml | 1 - build/instructions_template.rs | 392 ++-- build/static_string_indexing.rs | 39 +- src/allocator.rs | 3 +- src/arena.rs | 37 +- src/arithmetic.rs | 163 +- src/atom_table.rs | 221 ++- src/codegen.rs | 231 +-- src/debray_allocator.rs | 19 +- src/forms.rs | 233 +-- src/functor_macro.rs | 616 +++++++ src/heap_iter.rs | 1221 ++++++------- src/heap_print.rs | 371 ++-- src/indexing.rs | 88 +- src/iterators.rs | 24 +- src/lib.rs | 3 + src/lib/builtins.pl | 6 +- src/loader.pl | 6 +- src/machine/arithmetic_ops.rs | 20 +- src/machine/attributed_variables.pl | 1 + src/machine/attributed_variables.rs | 29 +- src/machine/compile.rs | 83 +- src/machine/copier.rs | 316 ++-- src/machine/cycle_detection.rs | 51 +- src/machine/disjuncts.rs | 172 +- src/machine/dispatch.rs | 374 ++-- src/machine/gc.rs | 1268 ++++++------- src/machine/heap.rs | 1444 +++++++++++++-- src/machine/lib_machine/mod.rs | 88 +- src/machine/load_state.rs | 14 - src/machine/loader.rs | 286 +-- src/machine/machine_errors.rs | 329 ++-- src/machine/machine_indices.rs | 9 + src/machine/machine_state.rs | 358 ++-- src/machine/machine_state_impl.rs | 724 +++----- src/machine/mock_wam.rs | 394 ++-- src/machine/mod.rs | 46 +- src/machine/partial_string.rs | 1159 ++++-------- src/machine/preprocessor.rs | 270 +-- src/machine/streams.rs | 10 +- src/machine/system_calls.rs | 2266 ++++++++++++++---------- src/machine/term_stream.rs | 32 +- src/machine/unify.rs | 296 +--- src/macros.rs | 235 +-- src/parser/ast.rs | 249 +-- src/parser/lexer.rs | 93 +- src/parser/parser.rs | 474 +++-- src/read.rs | 41 +- src/repl_helper.rs | 4 +- src/targets.rs | 36 +- src/tests/call_with_inference_limit.pl | 2 +- src/types.rs | 152 +- tests-pl/invalid_decl11.pl | 2 +- tests-pl/issue2588.pl | 2 +- 54 files changed, 7836 insertions(+), 7167 deletions(-) create mode 100644 src/functor_macro.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e0bde90..70f8d1a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,6 @@ jobs: # Cargo.toml rust-version - { os: ubuntu-22.04, rust-version: "1.85", target: 'x86_64-unknown-linux-gnu'} # rust versions - - { os: ubuntu-22.04, rust-version: "1.77", target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu', miri: true, components: "miri"} defaults: diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 84d0abad..18102af8 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -19,6 +19,7 @@ use to_syn_value_derive::ToDeriveInput; */ use std::any::*; +use std::rc::Rc; use std::str::FromStr; struct ArithmeticTerm; @@ -28,6 +29,7 @@ struct Death; struct HeapCellValue; struct IndexingLine; struct Level; +// struct Literal; struct NextOrFail; struct RegType; @@ -622,7 +624,7 @@ enum InstructionTemplate { #[strum_discriminants(strum(props(Arity = "2", Name = "get_list")))] GetList(Level, RegType), #[strum_discriminants(strum(props(Arity = "4", Name = "get_partial_string")))] - GetPartialString(Level, Atom, RegType, bool), + GetPartialString(Level, Rc, RegType), #[strum_discriminants(strum(props(Arity = "3", Name = "get_structure")))] GetStructure(Level, Atom, usize, RegType), #[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))] @@ -645,7 +647,7 @@ enum InstructionTemplate { #[strum_discriminants(strum(props(Arity = "2", Name = "put_list")))] PutList(Level, RegType), #[strum_discriminants(strum(props(Arity = "4", Name = "put_partial_string")))] - PutPartialString(Level, Atom, RegType, bool), + PutPartialString(Level, Rc, RegType), #[strum_discriminants(strum(props(Arity = "3", Name = "put_structure")))] PutStructure(Atom, usize, RegType), #[strum_discriminants(strum(props(Arity = "2", Name = "put_unsafe_value")))] @@ -875,6 +877,7 @@ fn generate_instruction_preface() -> TokenStream { use crate::arithmetic::*; use crate::atom_table::*; use crate::forms::*; + use crate::functor_macro::*; use crate::machine::heap::*; use crate::machine::machine_errors::MachineStub; use crate::machine::machine_indices::CodeIndex; @@ -885,6 +888,7 @@ fn generate_instruction_preface() -> TokenStream { use indexmap::IndexMap; use std::collections::VecDeque; + use std::rc::Rc; fn reg_type_into_functor(r: RegType) -> MachineStub { match r { @@ -896,9 +900,9 @@ fn generate_instruction_preface() -> TokenStream { impl Level { fn into_functor(self) -> MachineStub { match self { - Level::Root => functor!(atom!("level"), [atom(atom!("root"))]), - Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]), - Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]), + Level::Root => functor!(atom!("level"), [atom_as_cell((atom!("root")))]), + Level::Shallow => functor!(atom!("level"), [atom_as_cell((atom!("shallow")))]), + Level::Deep => functor!(atom!("level"), [atom_as_cell((atom!("deep")))]), } } } @@ -911,7 +915,7 @@ fn generate_instruction_preface() -> TokenStream { functor!(atom!("intermediate"), [fixnum(i)]) } ArithmeticTerm::Number(n) => { - functor!(atom!("number"), [cell(HeapCellValue::from((n, arena)))]) + functor!(atom!("number"), [number(n, arena)]) } } } @@ -996,7 +1000,7 @@ fn generate_instruction_preface() -> TokenStream { IndexingCodePtr, IndexingCodePtr, ), - SwitchOnConstant(IndexMap), + SwitchOnConstant(IndexMap), SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>), } @@ -1016,7 +1020,7 @@ fn generate_instruction_preface() -> TokenStream { IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]), IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]), IndexingCodePtr::Fail => { - vec![atom_as_cell!(atom!("fail"))] + functor!(atom!("fail")) }, } } @@ -1030,80 +1034,43 @@ fn generate_instruction_preface() -> TokenStream { } impl IndexingInstruction { - pub fn to_functor(&self, mut h: usize) -> MachineStub { + pub fn to_functor(&self) -> MachineStub { match self { &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => { functor!( atom!("switch_on_term"), [ fixnum(arg), - indexing_code_ptr(h, vars), - indexing_code_ptr(h, constants), - indexing_code_ptr(h, lists), - indexing_code_ptr(h, structures) + indexing_code_ptr(vars), + indexing_code_ptr(constants), + indexing_code_ptr(lists), + indexing_code_ptr(structures) ] ) } IndexingInstruction::SwitchOnConstant(constants) => { - let mut key_value_list_stub = vec![]; - let orig_h = h; - - h += 2; // skip the 2-cell "switch_on_constant" functor. - - for (c, ptr) in constants.iter() { - let key_value_pair = functor!( - atom!(":"), - [literal(*c), indexing_code_ptr(h + 3, *ptr)] - ); - - key_value_list_stub.push(list_loc_as_cell!(h + 1)); - key_value_list_stub.push(str_loc_as_cell!(h + 3)); - key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); - - h += key_value_pair.len() + 3; - key_value_list_stub.extend(key_value_pair.into_iter()); - } - - key_value_list_stub.push(empty_list_as_cell!()); - - functor!( - atom!("switch_on_constant"), - [str(orig_h, 0)], - [key_value_list_stub] + variadic_functor( + atom!("switch_on_constants"), + 1, + constants.iter().map(|(c, ptr)| { + functor!( + atom!(":"), + [cell((c.clone())), indexing_code_ptr((*ptr))] + ) + }), ) } IndexingInstruction::SwitchOnStructure(structures) => { - let mut key_value_list_stub = vec![]; - let orig_h = h; - - h += 2; // skip the 2-cell "switch_on_constant" functor. - - for ((name, arity), ptr) in structures.iter() { - let predicate_indicator_stub = functor!( - atom!("/"), - [atom(name), fixnum(*arity)] - ); - - let key_value_pair = functor!( - atom!(":"), - [str(h + 3, 0), indexing_code_ptr(h + 3, *ptr)], - [predicate_indicator_stub] - ); - - key_value_list_stub.push(list_loc_as_cell!(h + 1)); - key_value_list_stub.push(str_loc_as_cell!(h + 3)); - key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); - - h += key_value_pair.len() + 3; - key_value_list_stub.extend(key_value_pair.into_iter()); - } - - key_value_list_stub.push(empty_list_as_cell!()); - - functor!( + variadic_functor( atom!("switch_on_structure"), - [str(orig_h, 0)], - [key_value_list_stub] + 1, + structures.iter().map(|((name, arity), ptr)| { + functor!( + atom!(":"), + [functor((atom!("/")), [atom_as_cell(name), fixnum((*arity))]), + indexing_code_ptr((*ptr))] + ) + }), ) } } @@ -1133,18 +1100,16 @@ fn generate_instruction_preface() -> TokenStream { } fn arith_instr_unary_functor( - h: usize, name: Atom, arena: &mut Arena, at: &ArithmeticTerm, t: usize, ) -> MachineStub { let at_stub = at.into_functor(arena); - functor!(name, [str(h, 0), fixnum(t)], [at_stub]) + functor!(name, [functor(at_stub), fixnum(t)]) } fn arith_instr_bin_functor( - h: usize, name: Atom, arena: &mut Arena, at_1: &ArithmeticTerm, @@ -1154,11 +1119,9 @@ fn generate_instruction_preface() -> TokenStream { let at_1_stub = at_1.into_functor(arena); let at_2_stub = at_2.into_functor(arena); - functor!( - name, - [str(h, 0), str(h, 1), fixnum(t)], - [at_1_stub, at_2_stub] - ) + functor!(name, [functor(at_1_stub), + functor(at_2_stub), + fixnum(t)]) } pub type Code = Vec; @@ -1170,7 +1133,7 @@ fn generate_instruction_preface() -> TokenStream { match *self { Instruction::GetConstant(_, _, r) => vec![r], Instruction::GetList(_, r) => vec![r], - Instruction::GetPartialString(_, _, r, _) => vec![r], + Instruction::GetPartialString(_, _, r) => vec![r], Instruction::GetStructure(_, _, _, r) => vec![r], Instruction::GetVariable(r, t) => vec![r, temp_v!(t)], Instruction::GetValue(r, t) => vec![r, temp_v!(t)], @@ -1178,7 +1141,7 @@ fn generate_instruction_preface() -> TokenStream { Instruction::UnifyVariable(r) => vec![r], Instruction::PutConstant(_, _, r) => vec![r], Instruction::PutList(_, r) => vec![r], - Instruction::PutPartialString(_, _, r, _) => vec![r], + Instruction::PutPartialString(_, _, r) => vec![r], Instruction::PutStructure(_, _, r) => vec![r], Instruction::PutValue(r, t) => vec![r, temp_v!(t)], Instruction::PutVariable(r, t) => vec![r, temp_v!(t)], @@ -1242,7 +1205,6 @@ fn generate_instruction_preface() -> TokenStream { pub fn enqueue_functors( &self, - mut h: usize, arena: &mut Arena, functors: &mut Vec, ) { @@ -1251,33 +1213,30 @@ fn generate_instruction_preface() -> TokenStream { for indexing_instr in indexing_instrs { match indexing_instr { IndexingLine::Indexing(indexing_instr) => { - let section = indexing_instr.to_functor(h); - h += section.len(); + let section = indexing_instr.to_functor(); functors.push(section); } IndexingLine::IndexedChoice(indexed_choice_instrs) => { for indexed_choice_instr in indexed_choice_instrs { let section = indexed_choice_instr.to_functor(); - h += section.len(); functors.push(section); } } IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => { for indexed_choice_instr in indexed_choice_instrs { - let section = functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]); - - h += section.len(); + let section = functor!(atom!("dynamic"), + [fixnum((*indexed_choice_instr))]); functors.push(section); } } } } } - instr => functors.push(instr.to_functor(h, arena)), + instr => functors.push(instr.to_functor(arena)), } } - fn to_functor(&self, h: usize, arena: &mut Arena) -> MachineStub { + fn to_functor(&self, arena: &mut Arena) -> MachineStub { match self { &Instruction::InstallVerifyAttr => { functor!(atom!("install_verify_attr")) @@ -1290,25 +1249,23 @@ fn generate_instruction_preface() -> TokenStream { (Death::Infinity, NextOrFail::Next(i)) => { functor!( atom!("dynamic_else"), - [fixnum(birth), atom(atom!("inf")), fixnum(i)] + [fixnum(birth), atom_as_cell((atom!("inf"))), fixnum(i)] ) } (Death::Infinity, NextOrFail::Fail(i)) => { - let next_functor = functor!(atom!("fail"), [fixnum(i)]); - functor!( atom!("dynamic_else"), - [fixnum(birth), atom(atom!("inf")), str(h, 0)], - [next_functor] + [fixnum(birth), + atom_as_cell((atom!("inf"))), + functor((atom!("fail")), [fixnum(i)])] ) } (Death::Finite(d), NextOrFail::Fail(i)) => { - let next_functor = functor!(atom!("fail"), [fixnum(i)]); - functor!( atom!("dynamic_else"), - [fixnum(birth), fixnum(d), str(h, 0)], - [next_functor] + [fixnum(birth), + fixnum(d), + functor((atom!("fail")), [fixnum(i)])] ) } (Death::Finite(d), NextOrFail::Next(i)) => { @@ -1321,25 +1278,23 @@ fn generate_instruction_preface() -> TokenStream { (Death::Infinity, NextOrFail::Next(i)) => { functor!( atom!("dynamic_internal_else"), - [fixnum(birth), atom(atom!("inf")), fixnum(i)] + [fixnum(birth), atom_as_cell((atom!("inf"))), fixnum(i)] ) } (Death::Infinity, NextOrFail::Fail(i)) => { - let next_functor = functor!(atom!("fail"), [fixnum(i)]); - functor!( atom!("dynamic_internal_else"), - [fixnum(birth), atom(atom!("inf")), str(h, 0)], - [next_functor] + [fixnum(birth), + atom_as_cell((atom!("inf"))), + functor((atom!("fail")), [fixnum(i)])] ) } (Death::Finite(d), NextOrFail::Fail(i)) => { - let next_functor = functor!(atom!("fail"), [fixnum(i)]); - functor!( atom!("dynamic_internal_else"), - [fixnum(birth), fixnum(d), str(h, 0)], - [next_functor] + [fixnum(birth), + fixnum(d), + functor((atom!("fail")), [fixnum(i)])] ) } (Death::Finite(d), NextOrFail::Next(i)) => { @@ -1367,157 +1322,154 @@ fn generate_instruction_preface() -> TokenStream { } &Instruction::Cut(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("cut"), [str(h, 0)], [rt_stub]) + functor!(atom!("cut"), [functor(rt_stub)]) } &Instruction::CutPrev(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("cut_prev"), [str(h, 0)], [rt_stub]) + functor!(atom!("cut_prev"), [functor(rt_stub)]) } &Instruction::GetLevel(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("get_level"), [str(h, 0)], [rt_stub]) + functor!(atom!("get_level"), [functor(rt_stub)]) } &Instruction::GetPrevLevel(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("get_prev_level"), [str(h, 0)], [rt_stub]) + functor!(atom!("get_prev_level"), [functor(rt_stub)]) } &Instruction::GetCutPoint(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("get_cut_point"), [str(h, 0)], [rt_stub]) + functor!(atom!("get_cut_point"), [functor(rt_stub)]) } &Instruction::NeckCut => { functor!(atom!("neck_cut")) } &Instruction::Add(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("add"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("add"), arena, at_1, at_2, t) } &Instruction::Sub(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("sub"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("sub"), arena, at_1, at_2, t) } &Instruction::Mul(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("mul"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("mul"), arena, at_1, at_2, t) } &Instruction::IntPow(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("int_pow"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("int_pow"), arena, at_1, at_2, t) } &Instruction::Pow(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("pow"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("pow"), arena, at_1, at_2, t) } &Instruction::IDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("idiv"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("idiv"), arena, at_1, at_2, t) } &Instruction::Max(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("max"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("max"), arena, at_1, at_2, t) } &Instruction::Min(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("min"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("min"), arena, at_1, at_2, t) } &Instruction::IntFloorDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("int_floor_div"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("int_floor_div"), arena, at_1, at_2, t) } &Instruction::RDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("rdiv"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("rdiv"), arena, at_1, at_2, t) } &Instruction::Div(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("div"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("div"), arena, at_1, at_2, t) } &Instruction::Shl(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("shl"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("shl"), arena, at_1, at_2, t) } &Instruction::Shr(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("shr"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("shr"), arena, at_1, at_2, t) } &Instruction::Xor(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("xor"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("xor"), arena, at_1, at_2, t) } &Instruction::And(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("and"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("and"), arena, at_1, at_2, t) } &Instruction::Or(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("or"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("or"), arena, at_1, at_2, t) } &Instruction::Mod(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("mod"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("mod"), arena, at_1, at_2, t) } &Instruction::Rem(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("rem"), arena, at_1, at_2, t) } &Instruction::ATan2(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("rem"), arena, at_1, at_2, t) } &Instruction::Gcd(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t) + arith_instr_bin_functor(atom!("gcd"), arena, at_1, at_2, t) } &Instruction::Sign(ref at, t) => { - arith_instr_unary_functor(h, atom!("sign"), arena, at, t) + arith_instr_unary_functor(atom!("sign"), arena, at, t) } &Instruction::Cos(ref at, t) => { - arith_instr_unary_functor(h, atom!("cos"), arena, at, t) + arith_instr_unary_functor(atom!("cos"), arena, at, t) } &Instruction::Sin(ref at, t) => { - arith_instr_unary_functor(h, atom!("sin"), arena, at, t) + arith_instr_unary_functor(atom!("sin"), arena, at, t) } &Instruction::Tan(ref at, t) => { - arith_instr_unary_functor(h, atom!("tan"), arena, at, t) + arith_instr_unary_functor(atom!("tan"), arena, at, t) } &Instruction::Log(ref at, t) => { - arith_instr_unary_functor(h, atom!("log"), arena, at, t) + arith_instr_unary_functor(atom!("log"), arena, at, t) } &Instruction::Exp(ref at, t) => { - arith_instr_unary_functor(h, atom!("exp"), arena, at, t) + arith_instr_unary_functor(atom!("exp"), arena, at, t) } &Instruction::ACos(ref at, t) => { - arith_instr_unary_functor(h, atom!("acos"), arena, at, t) + arith_instr_unary_functor(atom!("acos"), arena, at, t) } &Instruction::ASin(ref at, t) => { - arith_instr_unary_functor(h, atom!("asin"), arena, at, t) + arith_instr_unary_functor(atom!("asin"), arena, at, t) } &Instruction::ATan(ref at, t) => { - arith_instr_unary_functor(h, atom!("atan"), arena, at, t) + arith_instr_unary_functor(atom!("atan"), arena, at, t) } &Instruction::Sqrt(ref at, t) => { - arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t) + arith_instr_unary_functor(atom!("sqrt"), arena, at, t) } &Instruction::Abs(ref at, t) => { - arith_instr_unary_functor(h, atom!("abs"), arena, at, t) + arith_instr_unary_functor(atom!("abs"), arena, at, t) } &Instruction::Float(ref at, t) => { - arith_instr_unary_functor(h, atom!("float"), arena, at, t) + arith_instr_unary_functor(atom!("float"), arena, at, t) } &Instruction::Truncate(ref at, t) => { - arith_instr_unary_functor(h, atom!("truncate"), arena, at, t) + arith_instr_unary_functor(atom!("truncate"), arena, at, t) } &Instruction::Round(ref at, t) => { - arith_instr_unary_functor(h, atom!("round"), arena, at, t) + arith_instr_unary_functor(atom!("round"), arena, at, t) } &Instruction::Ceiling(ref at, t) => { - arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t) + arith_instr_unary_functor(atom!("ceiling"), arena, at, t) } &Instruction::Floor(ref at, t) => { - arith_instr_unary_functor(h, atom!("floor"), arena, at, t) + arith_instr_unary_functor(atom!("floor"), arena, at, t) } &Instruction::FloatFractionalPart(ref at, t) => { - arith_instr_unary_functor(h, atom!("float_fractional_part"), arena, at, t) + arith_instr_unary_functor(atom!("float_fractional_part"), arena, at, t) } &Instruction::FloatIntegerPart(ref at, t) => { - arith_instr_unary_functor(h, atom!("float_integer_part"), arena, at, t) + arith_instr_unary_functor(atom!("float_integer_part"), arena, at, t) } &Instruction::Neg(ref at, t) => arith_instr_unary_functor( - h, atom!("-"), arena, at, t, ), &Instruction::Plus(ref at, t) => arith_instr_unary_functor( - h, atom!("+"), arena, at, t, ), &Instruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor( - h, atom!("\\"), arena, at, @@ -1533,16 +1485,16 @@ fn generate_instruction_preface() -> TokenStream { functor!(atom!("allocate"), [fixnum(num_frames)]) } &Instruction::CallNamed(arity, name, ..) => { - functor!(atom!("call"), [atom(name), fixnum(arity)]) + functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)]) } &Instruction::ExecuteNamed(arity, name, ..) => { - functor!(atom!("execute"), [atom(name), fixnum(arity)]) + functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)]) } &Instruction::DefaultCallNamed(arity, name, ..) => { - functor!(atom!("call_default"), [atom(name), fixnum(arity)]) + functor!(atom!("call_default"), [atom_as_cell(name), fixnum(arity)]) } &Instruction::DefaultExecuteNamed(arity, name, ..) => { - functor!(atom!("execute_default"), [atom(name), fixnum(arity)]) + functor!(atom!("execute_default"), [atom_as_cell(name), fixnum(arity)]) } &Instruction::CallN(arity) => { functor!(atom!("call_n"), [fixnum(arity)]) @@ -1585,7 +1537,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallSort | &Instruction::CallGetNumber(_) => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("call"), [atom(name), fixnum(arity)]) + functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)]) } // &Instruction::ExecuteTermGreaterThan | @@ -1611,7 +1563,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteSort | &Instruction::ExecuteGetNumber(_) => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("execute"), [atom(name), fixnum(arity)]) + functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)]) } // &Instruction::DefaultCallTermGreaterThan | @@ -1637,7 +1589,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::DefaultCallSort | &Instruction::DefaultCallGetNumber(_) => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("call_default"), [atom(name), fixnum(arity)]) + functor!(atom!("call_default"), [atom_as_cell(name), fixnum(arity)]) } // &Instruction::DefaultExecuteTermGreaterThan | @@ -1663,7 +1615,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::DefaultExecuteSort | &Instruction::DefaultExecuteGetNumber(_) => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("execute_default"), [atom(name), fixnum(arity)]) + functor!(atom!("execute_default"), [atom_as_cell(name), fixnum(arity)]) } &Instruction::CallIsAtom(r) | &Instruction::CallIsAtomic(r) | @@ -1676,7 +1628,8 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallIsVar(r) => { let (name, arity) = self.to_name_and_arity(); let rt_stub = reg_type_into_functor(r); - functor!(atom!("call"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub]) + + functor!(atom!("call"), [atom_as_cell(name), fixnum(arity), functor(rt_stub)]) } &Instruction::ExecuteIsAtom(r) | &Instruction::ExecuteIsAtomic(r) | @@ -1689,7 +1642,8 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteIsVar(r) => { let (name, arity) = self.to_name_and_arity(); let rt_stub = reg_type_into_functor(r); - functor!(atom!("execute"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub]) + + functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity), functor(rt_stub)]) } // &Instruction::CallAtomChars | @@ -1920,14 +1874,14 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallEd25519VerifyRaw | &Instruction::CallEd25519SeedToPublicKey => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("call"), [atom(name), fixnum(arity)]) + functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)]) } // #[cfg(feature = "crypto-full")] &Instruction::CallCryptoDataEncrypt | &Instruction::CallCryptoDataDecrypt => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("call"), [atom(name), fixnum(arity)]) + functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)]) } // &Instruction::ExecuteAtomChars | @@ -2158,14 +2112,14 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteEd25519VerifyRaw | &Instruction::ExecuteEd25519SeedToPublicKey => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("execute"), [atom(name), fixnum(arity)]) + functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)]) } // #[cfg(feature = "crypto-full")] &Instruction::ExecuteCryptoDataEncrypt | &Instruction::ExecuteCryptoDataDecrypt => { let (name, arity) = self.to_name_and_arity(); - functor!(atom!("execute"), [atom(name), fixnum(arity)]) + functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)]) } // &Instruction::Deallocate => { @@ -2180,73 +2134,60 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::Proceed => { functor!(atom!("proceed")) } - &Instruction::GetConstant(lvl, c, r) => { + &Instruction::GetConstant(lvl, lit, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!( - atom!("get_constant"), - [str(h, 0), cell(c), str(h, 1)], - [lvl_stub, rt_stub] - ) + functor!(atom!("get_constant"), [functor(lvl_stub), + cell(lit), + functor(rt_stub)]) } &Instruction::GetList(lvl, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!( - atom!("get_list"), - [str(h, 0), str(h, 1)], - [lvl_stub, rt_stub] - ) + functor!(atom!("get_list"), [functor(lvl_stub), functor(rt_stub)]) } - &Instruction::GetPartialString(lvl, s, r, has_tail) => { + &Instruction::GetPartialString(lvl, ref s, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!( - atom!("get_partial_string"), - [ - str(h, 0), - string(h, s), - str(h, 1), - boolean(has_tail) - ], - [lvl_stub, rt_stub] - ) + functor!(atom!("get_partial_string"), [functor(lvl_stub), + string((s.to_string())), + functor(rt_stub)]) } &Instruction::GetStructure(lvl, name, arity, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!( - atom!("get_structure"), - [str(h, 0), atom(name), fixnum(arity), str(h, 1)], - [lvl_stub, rt_stub] - ) + functor!(atom!("get_structure"), [functor(lvl_stub), + atom_as_cell(name), + fixnum(arity), + functor(rt_stub)]) } &Instruction::GetValue(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub]) + functor!(atom!("get_value"), [functor(rt_stub), + fixnum(arg)]) } &Instruction::GetVariable(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) + functor!(atom!("get_variable"), [functor(rt_stub), fixnum(arg)]) } &Instruction::UnifyConstant(c) => { functor!(atom!("unify_constant"), [cell(c)]) } &Instruction::UnifyLocalValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub]) + functor!(atom!("unify_local_value"), [functor(rt_stub)]) } &Instruction::UnifyVariable(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub]) + functor!(atom!("unify_variable"), [functor(rt_stub)]) } &Instruction::UnifyValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("unify_value"), [str(h, 0)], [rt_stub]) + functor!(atom!("unify_value"), [functor(rt_stub)]) } &Instruction::UnifyVoid(vars) => { functor!(atom!("unify_void"), [fixnum(vars)]) @@ -2258,68 +2199,55 @@ fn generate_instruction_preface() -> TokenStream { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!( - atom!("put_constant"), - [str(h, 0), cell(c), str(h, 1)], - [lvl_stub, rt_stub] - ) + functor!(atom!("put_constant"), [functor(rt_stub), cell(c), functor(lvl_stub)]) } &Instruction::PutList(lvl, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!( - atom!("put_list"), - [str(h, 0), str(h, 1)], - [lvl_stub, rt_stub] - ) + functor!(atom!("put_list"), [functor(lvl_stub), functor(rt_stub)]) } - &Instruction::PutPartialString(lvl, s, r, has_tail) => { + &Instruction::PutPartialString(lvl, ref s, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!( - atom!("put_partial_string"), - [ - str(h, 0), - string(h, s), - str(h, 1), - boolean(has_tail) - ], - [lvl_stub, rt_stub] - ) + functor!(atom!("put_partial_string"), [functor(lvl_stub), + string((s.to_string())), + functor(rt_stub)]) } &Instruction::PutStructure(name, arity, r) => { let rt_stub = reg_type_into_functor(r); - functor!( - atom!("put_structure"), - [atom(name), fixnum(arity), str(h, 0)], - [rt_stub] - ) + functor!(atom!("put_structure"), [atom_as_cell(name), + fixnum(arity), + functor(rt_stub)]) } &Instruction::PutValue(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub]) + + functor!(atom!("put_value"), [functor(rt_stub), + fixnum(arg)]) } &Instruction::PutVariable(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) + + functor!(atom!("put_variable"), [functor(rt_stub), + fixnum(arg)]) } &Instruction::SetConstant(c) => { functor!(atom!("set_constant"), [cell(c)]) } &Instruction::SetLocalValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub]) + functor!(atom!("set_local_value"), [functor(rt_stub)]) } &Instruction::SetVariable(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("set_variable"), [str(h, 0)], [rt_stub]) + functor!(atom!("set_variable"), [functor(rt_stub)]) } &Instruction::SetValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!(atom!("set_value"), [str(h, 0)], [rt_stub]) + functor!(atom!("set_value"), [functor(rt_stub)]) } &Instruction::SetVoid(vars) => { functor!(atom!("set_void"), [fixnum(vars)]) @@ -3204,14 +3132,6 @@ pub fn generate_instructions_rs() -> TokenStream { ) } - pub fn name(&self) -> Atom { - match self { - #( - #clause_type_name_arms, - )* - } - } - pub fn is_inlined(name: Atom, arity: usize) -> bool { matches!((name, arity), #(#is_inlined_arms)|* diff --git a/build/static_string_indexing.rs b/build/static_string_indexing.rs index c3d1701c..62e06f46 100644 --- a/build/static_string_indexing.rs +++ b/build/static_string_indexing.rs @@ -84,6 +84,18 @@ impl<'ast> Visit<'ast> for StaticStrVisitor { } } +const INLINED_ATOM_MAX_LEN: usize = 6; + +fn static_string_index(string: &str, index: usize) -> u64 { + if 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN { + let mut string_buf: [u8; 8] = [0u8; 8]; + string_buf[.. string.len()].copy_from_slice(string.as_bytes()); + (u64::from_le_bytes(string_buf) << 1) | 1 + } else { + (index << 1) as u64 + } +} + pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStream { use quote::*; @@ -149,11 +161,26 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea visitor.visit_file(&syntax) } - let indices = (0..visitor.static_strs.len()).map(|i| (i << 3) as u64); - let indices_iter = indices.clone(); + let mut static_str_keys = vec![]; + let mut static_strs = vec![]; + let mut static_str_indices = vec![]; - let static_strs_len = visitor.static_strs.len(); - let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect(); + let indices: Vec = visitor.static_strs.iter().map(|string| { + let index = static_string_index(string, static_strs.len()); + + static_str_keys.push(string); + + if index & 1 == 1 { + index + } else { + static_str_indices.push(index); + static_strs.push(string); + index + } + }).collect(); + + let static_strs_len = static_strs.len(); // visitor.static_strs.len(); + //let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect(); quote! { static STRINGS: [&str; #static_strs_len] = [ @@ -163,11 +190,11 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea ]; macro_rules! atom { - #((#static_strs) => { Atom { index: #indices_iter } };)* + #((#static_str_keys) => { Atom { index: #indices } };)* } pub static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! { - #(#static_strs => { Atom { index: #indices } },)* + #(#static_strs => { Atom { index: #static_str_indices } },)* }; } } diff --git a/src/allocator.rs b/src/allocator.rs index 27def1d6..735b013f 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -2,6 +2,7 @@ use crate::parser::ast::*; use crate::forms::*; use crate::instructions::*; +use crate::machine::heap::Heap; use crate::targets::*; pub(crate) trait Allocator { @@ -45,7 +46,7 @@ pub(crate) trait Allocator { fn reset(&mut self); fn reset_arg(&mut self, arg_num: usize); - fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize); + fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize); fn reset_contents(&mut self); fn advance_arg(&mut self); diff --git a/src/arena.rs b/src/arena.rs index e080df55..fbb9999f 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -909,7 +909,7 @@ mod tests { use crate::arena::*; use crate::atom_table::*; use crate::machine::mock_wam::*; - use crate::machine::partial_string::*; + use crate::types::*; use crate::parser::dashu::{Integer, Rational}; use ordered_float::OrderedFloat; @@ -992,7 +992,7 @@ mod tests { assert!(!big_int_ptr.as_ptr().is_null()); - let cell = HeapCellValue::from(Literal::Integer(big_int_ptr)); + let cell = HeapCellValue::from(big_int_ptr); assert_eq!(cell.get_tag(), HeapCellValueTag::Cons); let untyped_arena_ptr = match cell.to_untyped_arena_ptr() { @@ -1098,31 +1098,6 @@ mod tests { _ => { unreachable!() } ); - // complete string - - let pstr_var_cell = - put_partial_string(&mut wam.machine_st.heap, "ronan", &wam.machine_st.atom_tbl); - let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; - - assert_eq!(pstr_cell.get_tag(), HeapCellValueTag::PStr); - - match pstr_cell.to_pstr() { - Some(pstr) => { - assert_eq!(&*pstr.as_str_from(0), "ronan"); - } - None => { - unreachable!(); - } - } - - read_heap_cell!(pstr_cell, - (HeapCellValueTag::PStr, pstr_atom) => { - let pstr = PartialString::from(pstr_atom); - assert_eq!(&*pstr.as_str_from(0), "ronan"); - } - _ => { unreachable!() } - ); - // fixnum let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3)); @@ -1200,8 +1175,8 @@ mod tests { let char_cell = char_as_cell!(c); read_heap_cell!(char_cell, - (HeapCellValueTag::Char, c) => { - assert_eq!(c, 'c'); + (HeapCellValueTag::Atom, (c, _arity)) => { + assert_eq!(&*c.as_str(), "c"); } _ => { unreachable!() } ); @@ -1210,8 +1185,8 @@ mod tests { let cyrillic_char_cell = char_as_cell!(c); read_heap_cell!(cyrillic_char_cell, - (HeapCellValueTag::Char, c) => { - assert_eq!(c, 'Ћ'); + (HeapCellValueTag::Atom, (c, _arity)) => { + assert_eq!(&*c.as_str(), "Ћ"); } _ => { unreachable!() } ); diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 9253ee49..f1256b66 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -9,7 +9,6 @@ use crate::instructions::*; use crate::iterators::*; use crate::machine::disjuncts::*; use crate::machine::stack::Stack; -use crate::parser::ast::FocusedHeap; use crate::targets::QueryInstruction; use crate::types::*; @@ -55,103 +54,6 @@ impl Default for ArithmeticTerm { pub(crate) type ArithCont = (CodeDeque, Option); -/* -#[derive(Debug)] -pub(crate) struct ArithInstructionIterator<'a> { - state_stack: Vec>, -} - -impl<'a> ArithInstructionIterator<'a> { - fn push_subterm(&mut self, lvl: Level, term: &'a Term) { - self.state_stack - .push(TermIterState::subterm_to_state(lvl, term)); - } - - fn from(term: &'a Term) -> Result { - let state = match term { - Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), - Term::Clause(cell, name, terms) => { - TermIterState::Clause(Level::Shallow, 0, cell, *name, terms) - } - Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons), - Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => { - return Err(ArithmeticError::NonEvaluableFunctor( - Literal::Atom(atom!(".")), - 2, - )) - } - Term::Var(cell, var_ptr) => TermIterState::Var(Level::Shallow, cell, var_ptr.clone()), - }; - - Ok(ArithInstructionIterator { - state_stack: vec![state], - }) - } -} - -#[derive(Debug)] -pub(crate) enum ArithTermRef<'a> { - Literal(&'a Literal), - Op(Atom, usize), // name, arity. - Var(Level, &'a Cell, VarPtr), -} - -impl<'a> Iterator for ArithInstructionIterator<'a> { - type Item = Result, ArithmeticError>; - - fn next(&mut self) -> Option { - while let Some(iter_state) = self.state_stack.pop() { - match iter_state { - TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)), - TermIterState::Clause(lvl, child_num, cell, name, subterms) => { - let arity = subterms.len(); - - if child_num == arity { - return Some(Ok(ArithTermRef::Op(name, arity))); - } else { - self.state_stack.push(TermIterState::Clause( - lvl, - child_num + 1, - cell, - name, - subterms, - )); - - self.push_subterm(lvl.child_level(), &subterms[child_num]); - } - } - TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))), - TermIterState::Var(lvl, cell, var_ptr) => { - return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr))); - } - _ => { - return Some(Err(ArithmeticError::NonEvaluableFunctor( - Literal::Atom(atom!(".")), - 2, - ))); - } - }; - } - - None - } -} - -pub(crate) trait ArithmeticTermIter<'a> { - type Iter: Iterator, ArithmeticError>>; - - fn iter(self) -> Result; -} - -impl<'a> ArithmeticTermIter<'a> for &'a Term { - type Iter = ArithInstructionIterator<'a>; - - fn iter(self) -> Result { - ArithInstructionIterator::from(self) - } -} -*/ - #[derive(Debug)] pub(crate) struct ArithmeticEvaluator<'a> { marker: &'a mut DebrayAllocator, @@ -159,23 +61,45 @@ pub(crate) struct ArithmeticEvaluator<'a> { interm_c: usize, } -fn push_literal(interm: &mut Vec, c: Literal) -> Result<(), ArithmeticError> { - match c { - Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(n))), - Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(n))), - Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))), - Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(n))), - Literal::Atom(name) if name == atom!("e") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(std::f64::consts::E)), - )), - Literal::Atom(name) if name == atom!("pi") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(std::f64::consts::PI)), - )), - Literal::Atom(name) if name == atom!("epsilon") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(f64::EPSILON)), - )), - _ => return Err(ArithmeticError::NonEvaluableFunctor(HeapCellValue::from(c), 0)), - } +fn push_literal(interm: &mut Vec, c: HeapCellValue) -> Result<(), ArithmeticError> { + read_heap_cell!(c, + (HeapCellValueTag::Fixnum, n) => { + interm.push(ArithmeticTerm::Number(Number::Fixnum(n))) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Integer, n) => { + interm.push(ArithmeticTerm::Number(Number::Integer(n))); + } + (ArenaHeaderTag::Rational, n) => { + interm.push(ArithmeticTerm::Number(Number::Rational(n))); + } + _ => return Err(ArithmeticError::NonEvaluableFunctor(c, 0)), + ); + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + match name { + atom!("pi") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(std::f64::consts::PI)), + )), + atom!("epsilon") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(std::f64::EPSILON)), + )), + atom!("e") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(std::f64::consts::E)), + )), + _ => unreachable!(), + } + } + (HeapCellValueTag::F64, n) => { + interm.push(ArithmeticTerm::Number(Number::Float(*n))); + } + _ => { + return Err(ArithmeticError::NonEvaluableFunctor(c, 0)); + } + ); Ok(()) } @@ -313,7 +237,7 @@ impl<'a> ArithmeticEvaluator<'a> { pub(crate) fn compile_is( &mut self, - src: &mut FocusedHeap, + src: &mut FocusedHeapRefMut, term_loc: usize, context: GenContext, arg: usize, @@ -360,16 +284,13 @@ impl<'a> ArithmeticEvaluator<'a> { } (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { - push_literal(&mut self.interm, Literal::Atom(name))?; + push_literal(&mut self.interm, atom_as_cell!(name))?; } else { code.push_back(self.instr_from_clause(name, arity)?); } } _ => { - match Literal::try_from(term) { - Ok(lit) => push_literal(&mut self.interm, lit)?, - _ => return Err(ArithmeticError::NonEvaluableFunctor(term, 0)), - } + push_literal(&mut self.interm, term)?; } ); } diff --git a/src/atom_table.rs b/src/atom_table.rs index 60b0b3c7..7c23349d 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -23,15 +23,117 @@ use indexmap::IndexSet; use scryer_modular_bitfield::prelude::*; +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug)] +pub struct AtomCell { + name: B48, + arity: B8, + #[allow(unused)] + f: bool, + #[allow(unused)] + m: bool, + #[allow(unused)] + is_inlined: bool, + #[allow(unused)] + tag: B5, +} + +const INLINED_ATOM_MAX_LEN: usize = 6; + +const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::()); +const_assert!(mem::size_of::() == 8); + +const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::()); +const_assert!(mem::size_of::() == 8); + +impl AtomCell { + #[inline] + pub fn new_static(index: u64) -> Self { + // upper 23 bits of index must be 0 + debug_assert!(index & !((1 << 49) - 1) == 0); + AtomCell::new() + .with_name(index) + .with_arity(0u8) + .with_m(false) + .with_f(false) + .with_is_inlined(false) + .with_tag(HeapCellValueTag::Atom as u8) + } + + #[inline] + pub fn new_inlined(string: &str, arity: u8) -> Self { + debug_assert!(string.len() <= INLINED_ATOM_MAX_LEN); + + let mut string_buf: [u8; 8] = [0u8; 8]; + string_buf[.. string.len()].copy_from_slice(string.as_bytes()); + let encoding = u64::from_le_bytes(string_buf); + + AtomCell::new() + .with_name(encoding) + .with_arity(arity) + .with_m(false) + .with_f(false) + .with_is_inlined(true) + .with_tag(HeapCellValueTag::Atom as u8) + } + + #[inline] + pub fn new_char_inlined(c: char) -> Self { + let mut char_buf = [0u8;8]; + c.encode_utf8(&mut char_buf); + + let encoding = u64::from_le_bytes(char_buf); + + AtomCell::new() + .with_name(encoding) + .with_arity(0u8) + .with_m(false) + .with_f(false) + .with_is_inlined(true) + .with_tag(HeapCellValueTag::Atom as u8) + } + + #[inline] + pub fn build_with(atom_index: u64, arity: u8) -> Self { + debug_assert!((arity as usize) <= MAX_ARITY); + + AtomCell::new() + .with_name(atom_index >> 1) + .with_arity(arity) + .with_f(false) + .with_m(false) + .with_is_inlined(atom_index & 1 == 1) + .with_tag(HeapCellValueTag::Atom as u8) + } + + #[inline] + pub fn get_name(self) -> Atom { + Atom { index: (self.name() << 1) | self.is_inlined() as u64 } + } + + #[inline] + pub fn get_arity(self) -> usize { + self.arity() as usize + } + + #[inline] + pub fn get_name_and_arity(self) -> (Atom, usize) { + (self.get_name(), self.get_arity()) + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Atom { pub index: u64, } -const_assert!(mem::size_of::() == 8); - include!(concat!(env!("OUT_DIR"), "/static_atoms.rs")); +// populate these in STRINGS so they can be used from build_functor +const _: Atom = atom!("."); +const _: Atom = atom!("[]"); + impl<'a> From<&'a Atom> for Atom { #[inline] fn from(atom: &'a Atom) -> Self { @@ -39,17 +141,6 @@ impl<'a> From<&'a Atom> for Atom { } } -impl From for Atom { - #[inline] - fn from(value: bool) -> Self { - if value { - atom!("true") - } else { - atom!("false") - } - } -} - impl indexmap::Equivalent for str { fn equivalent(&self, key: &Atom) -> bool { &*key.as_str() == self @@ -120,24 +211,25 @@ impl Hash for Atom { #[inline] fn hash(&self, hasher: &mut H) { self.as_str().hash(hasher) - // hasher.write_usize(self.index) } } pub enum AtomString<'a> { Static(&'a str), + Inlined([u8;8]), Dynamic(AtomTableRef), } -impl AtomString<'_> { - pub fn map(self, f: F) -> Self - where - for<'a> F: FnOnce(&'a str) -> &'a str, - { - match self { - Self::Static(reference) => Self::Static(f(reference)), - Self::Dynamic(guard) => Self::Dynamic(AtomTableRef::map(guard, f)), - } +fn inlined_to_str<'a>(bytes: &'a [u8;8]) -> &'a str { + // allow the '\0\' atom to be represented as the 0-valued inlined atom + let slice_len = if bytes[0] == 0 { + 1 + } else { + bytes.iter().position(|&b| b == 0u8).unwrap_or(INLINED_ATOM_MAX_LEN) + }; + + unsafe { + str::from_utf8_unchecked(&bytes[..slice_len]) } } @@ -158,6 +250,7 @@ impl std::ops::Deref for AtomString<'_> { fn deref(&self) -> &Self::Target { match self { Self::Static(reference) => reference, + Self::Inlined(inlined) => inlined_to_str(&inlined), Self::Dynamic(guard) => guard.deref(), } } @@ -175,13 +268,32 @@ impl rustyline::completion::Candidate for AtomString<'_> { } impl Atom { - #[inline(always)] - pub fn is_static(self) -> bool { - (self.index as usize) < STRINGS.len() << 3 + #[inline] + fn new_inlined(string: &str) -> Self { + AtomCell::new_inlined(string, 0).get_name() } #[inline(always)] - pub fn as_ptr(self) -> Option> { + fn is_static(self) -> bool { + if self.is_inlined() { + true + } else { + (self.flat_index() as usize) < STRINGS.len() + } + } + + #[inline] + pub(crate) fn flat_index(self) -> u64 { + self.index >> 1 + } + + #[inline(always)] + pub(crate) fn is_inlined(self) -> bool { + self.index & 1 == 1 + } + + #[inline(always)] + fn as_ptr(self) -> Option> { if self.is_static() { None } else { @@ -192,7 +304,7 @@ impl Atom { let ptr = buf .block .base - .add((self.index as usize) - (STRINGS.len() << 3)); + .add(self.flat_index() as usize - STRINGS.len()); // TODO use std::ptr::from_raw_parts instead when feature ptr_metadata is stable rust-lang/rust#81513 let atom_data = &*(std::ptr::slice_from_raw_parts(ptr, 0) as *const AtomData); let len = atom_data.header.len(); @@ -208,8 +320,11 @@ impl Atom { #[inline(always)] pub fn len(self) -> usize { - if self.is_static() { - STRINGS[(self.index >> 3) as usize].len() + if let Some(s) = self.inlined_str() { + s.len() + } else if self.is_static() { + let index = self.flat_index(); + STRINGS[index as usize].len() } else { let len: u64 = self.as_ptr().unwrap().header.len(); len as usize @@ -220,11 +335,6 @@ impl Atom { self.len() == 0 } - #[inline(always)] - pub fn flat_index(self) -> u64 { - self.index >> 3 - } - pub fn as_char(self) -> Option { let s = self.as_str(); let mut it = s.chars(); @@ -239,14 +349,26 @@ impl Atom { } } + #[inline] + fn inlined_str<'a>(&self) -> Option> { + if self.is_inlined() { + Some(AtomString::Inlined(self.flat_index().to_le_bytes())) + } else { + None + } + } + #[inline] pub fn as_str(&self) -> AtomString<'static> { - if self.is_static() { - AtomString::Static(STRINGS[(self.index >> 3) as usize]) + if let Some(s) = self.inlined_str() { + s + } else if self.is_static() { + let index = self.flat_index() as usize; + AtomString::Static(STRINGS[index]) } else if let Some(ptr) = self.as_ptr() { AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| &ptr.data)) } else { - AtomString::Static(STRINGS[(self.index >> 3) as usize]) + AtomString::Static(STRINGS[(self.index >> 1) as usize]) } } @@ -342,6 +464,10 @@ impl AtomTable { } pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom { + if 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN { + return Atom::new_inlined(string); + } + loop { let mut block_epoch = atom_table.inner.read(); let mut table_epoch = block_epoch.table.read(); @@ -390,9 +516,14 @@ impl AtomTable { write_to_ptr(string, len_ptr); - let atom = Atom { - index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64, - }; + let atom = AtomCell::new() + .with_name((STRINGS.len() + len_ptr as usize - ptr_base) as u64) + .with_arity(0) + .with_f(false) + .with_m(false) + .with_is_inlined(false) + .with_tag(HeapCellValueTag::Atom as u8) + .get_name(); let mut table = table_epoch.clone(); table.insert(atom); @@ -410,18 +541,21 @@ impl AtomTable { unsafe impl Send for AtomTable {} unsafe impl Sync for AtomTable {} +/* #[bitfield] #[repr(u64)] #[derive(Copy, Clone, Debug)] pub struct AtomCell { - name: B46, + name: B48, arity: B10, #[allow(unused)] f: bool, #[allow(unused)] m: bool, #[allow(unused)] - tag: B6, + inlined: bool, + #[allow(unused)] + tag: B3, } impl AtomCell { @@ -463,3 +597,4 @@ impl AtomCell { (Atom::from((self.get_index() as u64) << 3), self.get_arity()) } } +*/ diff --git a/src/codegen.rs b/src/codegen.rs index 06d8c8e4..4b27e448 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -7,7 +7,7 @@ use crate::forms::*; use crate::indexing::*; use crate::instructions::*; use crate::iterators::*; -use crate::machine::heap::{heap_bound_deref, heap_bound_store}; +use crate::machine::heap::*; use crate::parser::ast::*; use crate::targets::*; use crate::types::*; @@ -16,7 +16,6 @@ use crate::variable_records::*; use crate::machine::disjuncts::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::CodeIndex; -use crate::machine::machine_state::pstr_loc_and_offset; use crate::machine::stack::Stack; use fxhash::FxBuildHasher; @@ -24,6 +23,7 @@ use indexmap::IndexMap; use indexmap::IndexSet; use std::collections::VecDeque; +use std::rc::Rc; #[derive(Debug)] pub struct BranchCodeStack { @@ -274,33 +274,12 @@ impl CodeGenSettings { } #[derive(Debug)] -pub(crate) struct CodeGenerator<'a> { - pub(crate) atom_tbl: &'a AtomTable, +pub(crate) struct CodeGenerator { marker: DebrayAllocator, settings: CodeGenSettings, pub(crate) skeleton: PredicateSkeleton, } -fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) { - let subterm = heap[subterm_loc]; - - if subterm.is_ref() { - let subterm = heap_bound_deref(heap, subterm); - let subterm_loc = subterm.get_value() as usize; - let subterm = heap_bound_store(heap, subterm); - - let subterm_loc = if subterm.is_ref() { - subterm.get_value() as usize - } else { - subterm_loc - }; - - (subterm_loc, subterm) - } else { - (subterm_loc, subterm) - } -} - impl DebrayAllocator { pub(crate) fn mark_non_callable( &mut self, @@ -337,7 +316,7 @@ trait AddToFreeList<'a, Target: CompilationTarget<'a>> { fn add_subterm_to_free_list(&mut self, r: RegType); } -impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> { +impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator { fn add_term_to_free_list(&mut self, r: RegType) { self.marker.add_reg_to_free_list(r); } @@ -345,7 +324,7 @@ impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> { fn add_subterm_to_free_list(&mut self, _r: RegType) {} } -impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> { +impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator { #[inline(always)] fn add_term_to_free_list(&mut self, _r: RegType) {} @@ -357,19 +336,19 @@ impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> { fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>( index_ptrs: &IndexMap, - heap: &[HeapCellValue], + heap: &Heap, arity: usize, heap_loc: usize, ) -> Option { match fetch_index_ptr(heap, arity, heap_loc) { Some(index_ptr) => { - let subterm = Literal::CodeIndex(index_ptr); + let subterm = HeapCellValue::from(index_ptr); return Some(Target::constant_subterm(subterm)); } None => { // if Level::Shallow == lvl { if let Some(index_ptr) = index_ptrs.get(&heap_loc) { - let subterm = Literal::CodeIndex(*index_ptr); + let subterm = HeapCellValue::from(*index_ptr); return Some(Target::constant_subterm(subterm)); } // } @@ -379,10 +358,9 @@ fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>( None } -impl<'b> CodeGenerator<'b> { - pub(crate) fn new(atom_tbl: &'b AtomTable, settings: CodeGenSettings) -> Self { +impl CodeGenerator { + pub(crate) fn new(settings: CodeGenSettings) -> Self { CodeGenerator { - atom_tbl, marker: DebrayAllocator::new(), settings, skeleton: PredicateSkeleton::new(), @@ -445,33 +423,26 @@ impl<'b> CodeGenerator<'b> { None } - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); - + (HeapCellValueTag::Atom, (name, _arity)) => { if index_ptrs.contains_key(&heap_loc) { let r = self.marker.mark_non_var::(Level::Deep, heap_loc, context, target); target.push_back(Target::clause_arg_to_instr(r)); return Some(r); } else { - target.push_back(Target::constant_subterm(Literal::Atom(name))); + target.push_back(Target::constant_subterm(atom_as_cell!(name))); } None } (HeapCellValueTag::Str | HeapCellValueTag::Lis - | HeapCellValueTag::PStrLoc - | HeapCellValueTag::CStr) => { + | HeapCellValueTag::PStrLoc) => { let r = self.marker.mark_non_var::(Level::Deep, heap_loc, context, target); target.push_back(Target::clause_arg_to_instr(r)); return Some(r); } _ => { - match Literal::try_from(subterm) { - Ok(lit) => target.push_back(Target::constant_subterm(lit)), - Err(_) => unreachable!(), - } - + target.push_back(Target::constant_subterm(subterm)); None } ) @@ -486,7 +457,7 @@ impl<'b> CodeGenerator<'b> { where Target: crate::targets::CompilationTarget<'a>, Iter: TermIterator, - CodeGenerator<'b>: AddToFreeList<'a, Target>, + CodeGenerator: AddToFreeList<'a, Target>, { let mut target = CodeDeque::new(); let chunk_num = context.chunk_num(); @@ -530,13 +501,13 @@ impl<'b> CodeGenerator<'b> { target.push_back(instr); } else if lvl == Level::Shallow { let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(Target::to_constant(lvl, Literal::Atom(name), r)); + target.push_back(Target::to_constant(lvl, atom_as_cell!(name), r)); } } else { let r = self.marker.mark_non_var::(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( + >::add_term_to_free_list( self, r, ); @@ -557,7 +528,7 @@ impl<'b> CodeGenerator<'b> { for r_opt in free_list_regs { if let Some(r) = r_opt { - as AddToFreeList<'a, Target>>::add_subterm_to_free_list( + >::add_subterm_to_free_list( self, r, ); } @@ -572,7 +543,7 @@ impl<'b> CodeGenerator<'b> { target.push_back(Target::to_list(lvl, r)); - as AddToFreeList<'a, Target>>::add_term_to_free_list( + >::add_term_to_free_list( self, r, ); @@ -597,62 +568,36 @@ impl<'b> CodeGenerator<'b> { ); if let Some(r) = head_r_opt { - as AddToFreeList<'a, Target>>::add_subterm_to_free_list( + >::add_subterm_to_free_list( self, r, ); } if let Some(r) = tail_r_opt { - as AddToFreeList<'a, Target>>::add_subterm_to_free_list( + >::add_subterm_to_free_list( self, r, ); } } - (HeapCellValueTag::CStr, cstr_atom) => { - let heap_loc = iter.focus().value() as usize; - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - - target.push_back(Target::to_pstr(lvl, cstr_atom, r, false)); - } - (HeapCellValueTag::PStr, pstr_atom) => { + (HeapCellValueTag::PStrLoc, pstr_loc) => { let heap_loc = iter.focus().value() as usize; let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); + let (pstr_str, tail_loc) = iter.scan_slice_to_str(pstr_loc); - target.push_back(Target::to_pstr(lvl, pstr_atom, r, true)); - - let (tail_loc, tail) = subterm_index(iter.deref(), heap_loc + 1); - self.subterm_to_instr::( - tail, tail_loc, context, index_ptrs, &mut target, - ); - } - (HeapCellValueTag::PStrOffset, l) => { - let heap_loc = iter.focus().value() as usize; - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - - let (index, n) = pstr_loc_and_offset(&iter, l); - let n = n.get_num() as usize; - - let pstr_atom = cell_as_atom!(iter[index]); - let pstr_offset_atom = if n == 0 { - pstr_atom - } else { - AtomTable::build_with(self.atom_tbl, &pstr_atom.as_str()[n ..]) - }; - - let (tail_loc, tail) = subterm_index(iter.deref(), l+1); - target.push_back(Target::to_pstr(lvl, pstr_offset_atom, r, true)); + target.push_back(Target::to_pstr(lvl, Rc::new(pstr_str.to_owned()), r)); + let (tail_loc, tail) = subterm_index(iter.deref(), tail_loc); self.subterm_to_instr::( tail, tail_loc, context, index_ptrs, &mut target, ); } _ if lvl == Level::Shallow => { - if let Ok(lit) = Literal::try_from(term) { + if term.is_constant() { let heap_loc = iter.focus().value() as usize; let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(Target::to_constant(lvl, lit, r)); + target.push_back(Target::to_constant(lvl, term, r)); } } _ => {} @@ -688,7 +633,7 @@ impl<'b> CodeGenerator<'b> { fn compile_inlined( &mut self, ct: &InlinedClauseType, - terms: &mut FocusedHeap, + terms: &mut FocusedHeapRefMut, term_loc: usize, context: GenContext, code: &mut CodeDeque, @@ -763,9 +708,6 @@ impl<'b> CodeGenerator<'b> { instr!("$fail") } } - (HeapCellValueTag::Char) => { - instr!("$succeed") - } _ => { instr!("$fail") } @@ -780,7 +722,6 @@ impl<'b> CodeGenerator<'b> { } else { read_heap_cell!(first_arg, (HeapCellValueTag::Fixnum | - HeapCellValueTag::Char | HeapCellValueTag::F64) => { instr!("$succeed") } @@ -803,12 +744,11 @@ impl<'b> CodeGenerator<'b> { } (HeapCellValueTag::Lis | HeapCellValueTag::Str - | HeapCellValueTag::PStrLoc - | HeapCellValueTag::CStr) => { + | HeapCellValueTag::PStrLoc) => { instr!("$fail") } _ => { - if Literal::try_from(first_arg).is_ok() { + if first_arg.is_constant() { instr!("$succeed") } else { instr!("$fail") @@ -833,8 +773,7 @@ impl<'b> CodeGenerator<'b> { } (HeapCellValueTag::Lis | HeapCellValueTag::Str - | HeapCellValueTag::PStrLoc - | HeapCellValueTag::CStr) => { + | HeapCellValueTag::PStrLoc) => { instr!("$succeed") } _ => { @@ -889,12 +828,10 @@ impl<'b> CodeGenerator<'b> { self.marker.reset_arg(1); if let Some(r) = variable_marker(&mut self.marker) { instr!("number", r) + } else if Number::try_from(first_arg).is_ok() { + instr!("$succeed") } else { - if Number::try_from(first_arg).is_ok() { - instr!("$succeed") - } else { - instr!("$fail") - } + instr!("$fail") } } InlinedClauseType::IsNonVar(..) => { @@ -902,12 +839,10 @@ impl<'b> CodeGenerator<'b> { if let Some(r) = variable_marker(&mut self.marker) { instr!("nonvar", r) + } else if first_arg.is_var() { + instr!("$fail") } else { - if first_arg.is_var() { - instr!("$fail") - } else { - instr!("$succeed") - } + instr!("$succeed") } } InlinedClauseType::IsInteger(..) => { @@ -931,12 +866,10 @@ impl<'b> CodeGenerator<'b> { if let Some(r) = variable_marker(&mut self.marker) { instr!("var", r) + } else if first_arg.is_var() { + instr!("$succeed") } else { - if first_arg.is_var() { - instr!("$succeed") - } else { - instr!("$fail") - } + instr!("$fail") } }, }; @@ -948,7 +881,7 @@ impl<'b> CodeGenerator<'b> { fn compile_arith_expr( &mut self, - terms: &mut FocusedHeap, + terms: &mut FocusedHeapRefMut, term_loc: usize, target_int: usize, context: GenContext, @@ -960,7 +893,7 @@ impl<'b> CodeGenerator<'b> { fn compile_is_call( &mut self, - terms: &mut FocusedHeap, + terms: &mut FocusedHeapRefMut, term_loc: usize, code: &mut CodeDeque, context: GenContext, @@ -977,12 +910,10 @@ impl<'b> CodeGenerator<'b> { self.marker.reset_arg(2); - let var = { - let var_cell = terms.heap[term_loc + 1]; - let terms = FocusedHeapRefMut::from_cell(&mut terms.heap, var_cell); - - terms.deref_loc(term_loc + 1) - }; + let var = heap_bound_store( + terms.heap, + heap_bound_deref(terms.heap, heap_loc_as_cell!(term_loc + 1)), + ); let at = read_heap_cell!(var, (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { @@ -1029,7 +960,7 @@ impl<'b> CodeGenerator<'b> { fn compile_seq( &mut self, - focused_heap: &mut FocusedHeap, + mut focused_heap: FocusedHeapRefMut, clauses: &ChunkedTermVec, code: &mut CodeDeque, ) -> Result<(), CompilationError> { @@ -1108,7 +1039,7 @@ impl<'b> CodeGenerator<'b> { .. }, ) => self.compile_is_call( - focused_heap, + &mut focused_heap, clause.term_loc(), branch_code_stack.code(code), context, @@ -1121,7 +1052,7 @@ impl<'b> CodeGenerator<'b> { }, ) => self.compile_inlined( ct, - focused_heap, + &mut focused_heap, clause.term_loc(), context, branch_code_stack.code(code), @@ -1132,15 +1063,13 @@ impl<'b> CodeGenerator<'b> { &QueryTerm::Succeed => { let code = branch_code_stack.code(code); - if self.marker.in_tail_position { - if self.marker.var_data.allocates { - code.push_back(instr!("deallocate")); - } + if self.marker.in_tail_position && self.marker.var_data.allocates { + code.push_back(instr!("deallocate")); } code.push_back( if self.marker.in_tail_position { - instr!("$succeed").to_execute() + instr!("$succeed").into_execute() } else { instr!("$succeed") }, @@ -1148,7 +1077,7 @@ impl<'b> CodeGenerator<'b> { } QueryTerm::Clause(clause) => { self.compile_query_line( - focused_heap, + &mut focused_heap, clause, context, branch_code_stack.code(code), @@ -1208,24 +1137,23 @@ impl<'b> CodeGenerator<'b> { pub(crate) fn compile_rule( &mut self, + heap: &mut Heap, rule: &mut Rule, var_data: VarData, ) -> Result { - let Rule { - ref mut term, - clauses, - } = rule; + let Rule { term_loc, clauses } = rule; + self.marker.var_data = var_data; + let term = FocusedHeapRefMut { heap, focus: *term_loc }; let mut code = VecDeque::new(); + let head_loc = term.nth_arg(term.focus, 1).unwrap(); - self.marker.reset_at_head(term, head_loc); + self.marker.reset_at_head(term.heap, head_loc); let mut stack = Stack::uninitialized(); - let iter = fact_iterator::( - &mut term.heap, &mut stack, head_loc, - ); + let iter = fact_iterator::(term.heap, &mut stack, head_loc); let fact = self.compile_target::( iter, @@ -1247,20 +1175,18 @@ impl<'b> CodeGenerator<'b> { pub(crate) fn compile_fact( &mut self, + heap: &mut Heap, fact: &mut Fact, var_data: VarData, ) -> Result { let mut code = Vec::new(); - let fact_focus = fact.term.focus; let mut stack = Stack::uninitialized(); self.marker.var_data = var_data; - self.marker.reset_at_head(&mut fact.term, fact_focus); + self.marker.reset_at_head(heap, fact.term_loc); - let iter = fact_iterator::( - &mut fact.term.heap, &mut stack, fact_focus, - ); + let iter = fact_iterator::(heap, &mut stack, fact.term_loc); let compiled_fact = self.compile_target::( iter, @@ -1280,7 +1206,7 @@ impl<'b> CodeGenerator<'b> { fn compile_query_line( &mut self, - term: &mut FocusedHeap, + term: &mut FocusedHeapRefMut, clause: &QueryClause, context: GenContext, code: &mut CodeDeque, @@ -1300,15 +1226,16 @@ impl<'b> CodeGenerator<'b> { self.add_call(code, clause.ct.to_instr(), clause.call_policy); } - fn split_predicate(clauses: &[PredicateClause]) -> Vec { + fn split_predicate(heap: &mut Heap, clauses: &[PredicateClause]) -> Vec { let mut subseqs = Vec::new(); let mut left = 0; let mut optimal_index = 0; 'outer: for (right, clause) in clauses.iter().enumerate() { - if let Some(args) = clause.args() { - for (instantiated_arg_index, arg) in args.iter().cloned().enumerate() { - let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg)); + if let Some(args) = clause.args(heap) { + for (instantiated_arg_index, arg_idx) in args.enumerate() { + let arg = heap[arg_idx]; + let arg = heap_bound_store(heap, heap_bound_deref(heap, arg)); if !arg.is_var() { if optimal_index != instantiated_arg_index { @@ -1364,6 +1291,7 @@ impl<'b> CodeGenerator<'b> { fn compile_pred_subseq( &mut self, + heap: &mut Heap, clauses: &mut [PredicateClause], optimal_index: usize, ) -> Result { @@ -1382,11 +1310,11 @@ impl<'b> CodeGenerator<'b> { let clause_code = match clause { PredicateClause::Fact(fact, var_data) => { let var_data = std::mem::take(var_data); - self.compile_fact(fact, var_data)? + self.compile_fact(heap, fact, var_data)? } PredicateClause::Rule(rule, var_data) => { let var_data = std::mem::take(var_data); - self.compile_rule(rule, var_data)? + self.compile_rule(heap, rule, var_data)? } }; @@ -1414,19 +1342,19 @@ impl<'b> CodeGenerator<'b> { skip_stub_try_me_else = !self.settings.is_dynamic(); } - let arg = clause.args().and_then(|args| args.get(optimal_index)); + let arg = clause.args(heap) + .map(|r| heap[r.start() + optimal_index]); - if let Some(arg) = arg.cloned() { + if let Some(arg) = arg { let index = code.len(); if clauses_len > 1 || self.settings.is_extensible { - let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg)); + let arg = heap_bound_store(heap, heap_bound_deref(heap, arg)); code_offsets.index_term( - clause.heap(), + heap, arg, index, &mut clause_index_info, - self.atom_tbl, ); } } @@ -1457,11 +1385,12 @@ impl<'b> CodeGenerator<'b> { pub(crate) fn compile_predicate( &mut self, + heap: &mut Heap, mut clauses: Vec, ) -> Result { let mut code = Code::new(); - let split_pred = Self::split_predicate(&clauses); + let split_pred = Self::split_predicate(heap, &clauses); let multi_seq = split_pred.len() > 1; for ClauseSpan { @@ -1473,11 +1402,13 @@ impl<'b> CodeGenerator<'b> { let skel_lower_bound = self.skeleton.clauses.len(); let code_segment = if self.settings.is_dynamic() { self.compile_pred_subseq::( + heap, &mut clauses[left..right], instantiated_arg_index, )? } else { self.compile_pred_subseq::( + heap, &mut clauses[left..right], instantiated_arg_index, )? diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 4577b1e6..d1d01aa8 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -4,7 +4,7 @@ use crate::codegen::SubsumedBranchHits; use crate::forms::{GenContext, Level}; use crate::instructions::*; use crate::machine::disjuncts::*; -use crate::machine::heap::{heap_bound_deref, heap_bound_store}; +use crate::machine::heap::*; use crate::parser::ast::*; use crate::targets::*; use crate::types::*; @@ -920,19 +920,24 @@ impl Allocator for DebrayAllocator { self.arg_c += 1; } - fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize) { - read_heap_cell!(term.deref_loc(head_loc), + fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize) { + let head_cell = heap_bound_store( + heap, + heap_bound_deref(heap, heap_loc_as_cell!(head_loc)), + ); + + read_heap_cell!(head_cell, (HeapCellValueTag::Str, s) => { - let arity = cell_as_atom_cell!(term.heap[s]).get_arity(); + let arity = cell_as_atom_cell!(heap[s]).get_arity(); self.reset_arg(arity); self.arity = arity; - for (idx, arg) in term.heap[s+1 .. s+arity+1].iter().cloned().enumerate() { + for (idx, arg) in heap.splice(s+1 ..= s+arity).enumerate() { if arg.is_var() { let var = heap_bound_store( - &term.heap, - heap_bound_deref(&term.heap, arg), + heap, + heap_bound_deref(heap, arg), ); if !var.is_var() { diff --git a/src/forms.rs b/src/forms.rs index be96e30c..4053b5a9 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -1,9 +1,10 @@ use crate::arena::*; use crate::atom_table::*; use crate::instructions::*; +use crate::functor_macro::*; use crate::machine::disjuncts::VarData; use crate::machine::heap::*; -use crate::machine::loader::PredicateQueue; +// use crate::machine::loader::PredicateQueue; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::parser::ast::*; @@ -25,18 +26,6 @@ use std::path::PathBuf; pub type PredicateKey = (Atom, usize); // name, arity. -/* -// vars of predicate, toplevel offset. Vec is always a vector -// of vars (we get their adjoining cells this way). -pub type JumpStub = Vec; -*/ - -#[derive(Debug)] -pub enum TopLevel { - Fact(Fact, VarData), // Term, line_num, col_num - Rule(Rule, VarData), // Rule, line_num, col_num -} - #[derive(Debug, Clone, Copy)] pub enum AppendOrPrepend { Append, @@ -171,17 +160,6 @@ impl ChunkedTermVec { .push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity))); } - pub fn push_branch_arm(&mut self, branch: VecDeque) { - match self.chunk_vec.back_mut().unwrap() { - ChunkedTerms::Branch(branches) => { - branches.push(branch); - } - ChunkedTerms::Chunk { .. } => { - self.chunk_vec.push_back(ChunkedTerms::Branch(vec![branch])); - } - } - } - pub fn try_set_chunk_at_inlined_boundary(&mut self) -> bool { if self.current_chunk_type.is_last() { self.current_chunk_type = ChunkType::Mid; @@ -243,7 +221,6 @@ impl ChunkedTermVec { #[derive(Debug)] pub struct QueryClause { pub ct: ClauseType, - pub arity: usize, pub term: HeapCellValue, pub code_indices: IndexMap, pub call_policy: CallPolicy, @@ -266,14 +243,14 @@ pub enum QueryTerm { GetLevel(usize), // var_num } -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] pub struct Fact { - pub(crate) term: FocusedHeap, + pub(crate) term_loc: usize, } #[derive(Debug)] pub struct Rule { - pub(crate) term: FocusedHeap, + pub(crate) term_loc: usize, pub(crate) clauses: ChunkedTermVec, } @@ -290,138 +267,34 @@ impl ListingSource { } } -pub trait ClauseInfo { - fn is_consistent(&self, clauses: &PredicateQueue) -> bool { - match clauses.first() { - Some(cl) => { - self.name() == ClauseInfo::name(cl) && self.arity() == ClauseInfo::arity(cl) +pub fn clause_predicate_key_from_heap( + heap: &impl SizedHeap, + value: HeapCellValue, +) -> Option { + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, _arity)) => { + debug_assert_eq!(_arity, 0); + Some((name, 0)) + } + _ => { + if value.is_ref() { + clause_predicate_key(heap, value.get_value() as usize) + } else { + None } - None => true, } - } - - fn name(&self) -> Option; - fn arity(&self) -> usize; + ) } -impl ClauseInfo for PredicateKey { - #[inline] - fn name(&self) -> Option { - Some(self.0) - } +pub fn clause_predicate_key(heap: &impl SizedHeap, term_loc: usize) -> Option { + let key_opt = term_predicate_key(heap, term_loc); - #[inline] - fn arity(&self) -> usize { - self.1 - } -} - -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)) + if Some((atom!(":-"), 2)) == key_opt { + term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| { + term_predicate_key(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 { - Term::Clause(_, name, terms) => { - match name { - atom!(":-") => { - match terms.len() { - 1 => None, // a declaration. - 2 => terms[0].name(), - _ => Some(*name), - } - } - _ => Some(*name), //str_buf), - } - } - Term::Literal(_, Literal::Atom(name)) => Some(*name), - _ => None, - } - } - - fn arity(&self) -> usize { - match self { - Term::Clause(_, name, terms) => match &*name.as_str() { - ":-" => match terms.len() { - 1 => 0, - 2 => terms[0].arity(), - _ => terms.len(), - }, - _ => terms.len(), - }, - _ => 0, - } - } -} -*/ - -impl ClauseInfo for Rule { - fn name(&self) -> Option { - self.term.name(self.term.focus) - } - - fn arity(&self) -> usize { - self.term.arity(self.term.focus) - } -} - -impl ClauseInfo for PredicateClause { - fn name(&self) -> Option { - match self { - 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 fact, ..) => fact.term.arity(fact.term.focus), - PredicateClause::Rule(ref rule, ..) => rule.term.arity(rule.term.focus), - } + key_opt } } @@ -432,33 +305,27 @@ pub enum PredicateClause { } impl PredicateClause { - pub(crate) fn args(&self) -> Option<&[HeapCellValue]> { - let (term, focus) = match self { - PredicateClause::Fact(Fact { term }, _) => (term, term.focus), - PredicateClause::Rule(Rule { term, .. }, _) => { - let focus = term.nth_arg(term.focus, 1).unwrap(); - (term, focus) + pub(crate) fn args<'a>(&self, heap: &'a Heap) -> Option> { + let focus = match self { + &PredicateClause::Fact(Fact { term_loc }, _) => term_loc, + &PredicateClause::Rule(Rule { term_loc, .. }, _) => { + term_nth_arg(heap, term_loc, 1).unwrap() } }; - let arity = term.arity(focus); + let arity = clause_predicate_key(heap, focus) + .map(|(_name, arity)| arity) + .unwrap_or(0); - read_heap_cell!(term.deref_loc(focus), + read_heap_cell!(heap_bound_store(heap, heap_bound_deref(heap, heap[focus])), (HeapCellValueTag::Str, s) => { - Some(&term.heap[s+1 .. s+arity+1]) + Some(s+1 ..= s+arity) } _ => { None } ) } - - pub(crate) fn heap(&self) -> &[HeapCellValue] { - match self { - PredicateClause::Fact(ref fact, ..) => &fact.term.heap, - PredicateClause::Rule(ref rule, ..) => &rule.term.heap, - } - } } #[derive(Debug)] @@ -477,10 +344,10 @@ pub enum ModuleSource { impl ModuleSource { pub(crate) fn as_functor_stub(&self) -> MachineStub { match self { - ModuleSource::Library(name) => { - functor!(atom!("library"), [atom(name)]) + &ModuleSource::Library(name) => { + functor!(atom!("library"), [atom_as_cell(name)]) } - ModuleSource::File(name) => { + &ModuleSource::File(name) => { functor!(name) } } @@ -813,6 +680,7 @@ impl ArenaFrom for Number { } } +/* impl ArenaFrom for Literal { #[inline] fn arena_from(value: Number, arena: &mut Arena) -> Literal { @@ -824,6 +692,21 @@ impl ArenaFrom for Literal { } } } +*/ + +impl ArenaFrom for HeapCellValue { + #[inline] + fn arena_from(value: u64, arena: &mut Arena) -> HeapCellValue { + fixnum!(value as i64, arena) + } +} + +impl ArenaFrom for HeapCellValue { + #[inline] + fn arena_from(value: usize, arena: &mut Arena) -> HeapCellValue { + HeapCellValue::arena_from(value as u64, arena) + } +} impl ArenaFrom for HeapCellValue { #[inline] @@ -896,8 +779,8 @@ impl Number { #[derive(Debug, Clone)] pub(crate) enum OptArgIndexKey { - Literal(usize, usize, Literal, Vec), // index, IndexingCode location, opt arg, alternatives - List(usize, usize), // index, IndexingCode location + Literal(usize, usize, HeapCellValue, Vec), // index, IndexingCode location, opt arg, alternatives + List(usize, usize), // index, IndexingCode location None, Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity } diff --git a/src/functor_macro.rs b/src/functor_macro.rs new file mode 100644 index 00000000..081a4417 --- /dev/null +++ b/src/functor_macro.rs @@ -0,0 +1,616 @@ +use crate::atom_table::*; +use crate::instructions::IndexingCodePtr; +use crate::machine::heap::Heap; +use crate::parser::ast::Fixnum; +use crate::types::*; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum FunctorElement { + AbsoluteCell(HeapCellValue), + Cell(HeapCellValue), + InnerFunctor(u64, Vec), + String(u64, String), +} + +// helper macros +macro_rules! count { + () => (0); + ( $x:tt $($xs:tt)* ) => (1 + count!($($xs)*)); +} + +// core macros + +/* + * functor! is more declarative now, with fewer effects and more + * work done at compile time using const functions. With these + * advantages come new quirks: expressions must generally be wrapped + * in round parentheses for rustc to parse them. See the tests module + * below for examples, especially those involving atom! + * subexpressions. + */ + +macro_rules! functor { + ($name:expr) => ({ + vec![FunctorElement::Cell(atom_as_cell!($name))] + }); + ($name:expr, [$($dt:ident($($value:tt),*)),+]) => ({ + build_functor!([$($dt($($value),*)),*], + [FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))], + 1, + []) + }); +} + +macro_rules! inner_functor { + ($name:expr, $res_len:expr, [$($dt:ident($($value:tt),*)),+]) => ({ + build_functor!([$($dt($($value),*)),*], + [FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))], + 1 + $res_len, + []) + }); +} + +macro_rules! build_functor { + ([], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({ + vec![$($res,)* $($subfunctor),*] + }); + ([indexing_code_ptr($e:expr) $(, $dt:ident($($value:tt),*))*], + [$($res:expr),*], + $res_len:expr, + [$($subfunctor:expr),*]) => ({ + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(str_loc_as_cell!(1u64 + count!($($dt)*) + $res_len))], + 3 + $res_len, + [$($subfunctor, )* FunctorElement::InnerFunctor(2, indexing_code_ptr($e))]) + }); + ([fixnum($e:expr) $(, $dt:ident($($value:tt),*))*], + [$($res:expr),*], + $res_len:expr, + [$($subfunctor:expr),*]) => ({ + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(fixnum_as_cell!(Fixnum::build_with($e as i64)))], + 1 + $res_len, + [$($subfunctor),*]) + }); + ([cell($e:expr) $(, $dt:ident($($value:tt),*))*], + [$($res:expr),*], + $res_len:expr, + [$($subfunctor:expr),*]) => ({ + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::AbsoluteCell($e)], + 1 + $res_len, + [$($subfunctor),*]) + }); + ([number($n:expr, $arena:expr) $(, $dt:ident($($value:tt),*))*], + [$($res:expr),*], + $res_len:expr, + [$($subfunctor:expr),*]) => ({ + let number_cell = HeapCellValue::arena_from($n, $arena); + + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(number_cell)], + 1 + $res_len, + [$($subfunctor),*]) + }); + ([list([]) $(, $dt:ident($($value:tt),*))*], + [$($res:expr),*], + $res_len:expr, + [$($subfunctor:expr),*]) => ({ + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(empty_list_as_cell!())], + 1 + $res_len, + [$($subfunctor),*]) + }); + ([list([$id:ident($($id_value:tt),*) $(, $in_dt:ident($($in_value:tt),*))*]) $(, $dt:ident($($value:tt),*))*], + [$($res:expr),*], + $res_len:expr, + [$($subfunctor:expr),*]) => ({ + build_functor!([functor((atom!(".")), [$id($($id_value),*), list([$($in_dt($($in_value),*)),*])]) + $(, $dt($($value),*))*], + [$($res),*], + $res_len, + [$($subfunctor),*]) + }); + ([string($s:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({ + let string = $s; + let pstr_len = cell_index!(Heap::compute_pstr_size(&string)) as u64; + let result_len = 1 + count!($($dt)*) + $res_len; + + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(pstr_loc_as_cell!(heap_index!(result_len as usize) as u64))], + 1 + $res_len + pstr_len, + [$($subfunctor, )* FunctorElement::String(pstr_len, string)]) + }); + ([atom_as_cell($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({ + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(atom_as_cell!($n))], + 1 + $res_len, + [$($subfunctor),*]) + }); + ([functor($stub:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({ + let result_len = 1u64 + count!($($dt)*) + $res_len; + let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&$stub)) as u64; + + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))], + 1 + $res_len + inner_functor_size, + [$($subfunctor, )* + FunctorElement::InnerFunctor(inner_functor_size, $stub)]) + }); + ([$id:ident($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({ + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell($id!($n))], + 1 + $res_len, + [$($subfunctor),*]) + }); + ([functor($name:expr, [$($in_dt:ident($($in_value:tt),*)),+]) $(, $dt:ident($($value:tt),*))*], + [$($res:expr),*], + $res_len:expr, + [$($subfunctor:expr),*]) => ({ + let result_len = 1u64 + count!($($dt)*) + $res_len; + let inner_functor = inner_functor!($name, 0, [$($in_dt($($in_value),*)),*]); + let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&inner_functor)) as u64; + + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))], + 1 + $res_len + inner_functor_size, + [$($subfunctor, )* + FunctorElement::InnerFunctor(inner_functor_size, inner_functor)]) + }); +} + +pub(crate) fn indexing_code_ptr(code_ptr: IndexingCodePtr) -> Vec { + match code_ptr { + IndexingCodePtr::DynamicExternal(o) => { + functor!(atom!("dynamic_external"), [fixnum(o)]) + } + IndexingCodePtr::External(o) => { + functor!(atom!("external"), [fixnum(o)]) + } + IndexingCodePtr::Internal(o) => { + functor!(atom!("internal"), [fixnum(o)]) + } + IndexingCodePtr::Fail => { + vec![FunctorElement::Cell(atom_as_cell!(atom!("fail")))] + } + } +} + +pub(crate) fn variadic_functor( + name: Atom, + arity: usize, + iter: impl Iterator>, +) -> Vec { + let mut arg_vec = vec![ + FunctorElement::Cell(atom_as_cell!(name, arity)), + FunctorElement::Cell(list_loc_as_cell!(2)), + ]; + + let key_value_pairs: Vec<_> = iter.collect(); + let num_items = key_value_pairs.len(); + + for (idx, _) in key_value_pairs.iter().enumerate() { + arg_vec.push(FunctorElement::Cell(str_loc_as_cell!(2 + num_items * 2 + idx))); + arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(5 + idx))); + } + + arg_vec.pop(); + arg_vec.push(FunctorElement::Cell(empty_list_as_cell!())); + + arg_vec.extend(key_value_pairs + .into_iter() + .map(|kv_func| { + let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&kv_func)); + FunctorElement::InnerFunctor(inner_functor_size as u64, kv_func) + })); + + arg_vec +} + +#[cfg(test)] +#[allow(unused_parens)] +mod tests { + use super::*; + use FunctorElement::*; + use std::string::String; + + #[test] + fn basic_terms() { + let functor = functor!(atom!("first"), [atom_as_cell((atom!("a"))), + char_as_cell('c')]); + + assert_eq!(functor.len(), 3); + + assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 2))); + assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a")))); + assert_eq!(functor[2], Cell(char_as_cell!('c'))); + + let functor = functor!(atom!("second"), [atom_as_cell((atom!("a"))), + functor((atom!("b")), [fixnum(1), + fixnum(2)]), + char_as_cell('c')]); + + assert_eq!(functor.len(), 5); + + assert_eq!(functor[0], Cell(atom_as_cell!(atom!("second"), 3))); + assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a")))); + assert_eq!(functor[2], Cell(str_loc_as_cell!(4))); + assert_eq!(functor[3], Cell(char_as_cell!('c'))); + assert_eq!(functor[4], InnerFunctor(3, functor!(atom!("b"), [fixnum(1), + fixnum(2)]))); + + let functor = functor!(atom!("third"), [atom_as_cell((atom!("a"))), + functor((atom!("b")), [fixnum(1), fixnum(2)]), + functor((atom!("c")), [fixnum(1), fixnum(2)]), + char_as_cell('c')]); + + assert_eq!(functor.len(), 7); + + assert_eq!(functor[0], Cell(atom_as_cell!(atom!("third"), 4))); + assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a")))); + assert_eq!(functor[2], Cell(str_loc_as_cell!(5))); + assert_eq!(functor[3], Cell(str_loc_as_cell!(8))); + assert_eq!(functor[4], Cell(char_as_cell!('c'))); + assert_eq!(functor[5], InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))); + assert_eq!(functor[6], InnerFunctor(3, functor!(atom!("c"), [fixnum(1), fixnum(2)]))); + + let functor = functor!(atom!("fourth"), [atom_as_cell((atom!("a"))), + functor((atom!("b")), [fixnum(1), fixnum(2)]), + functor((atom!("c")), [fixnum(1)]), + functor((atom!("d")), [fixnum(453), fixnum(2)]), + char_as_cell('c')]); + + assert_eq!(functor.len(), 9); + + assert_eq!(functor[0], Cell(atom_as_cell!(atom!("fourth"), 5))); + assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a")))); + assert_eq!(functor[2], Cell(str_loc_as_cell!(6))); + assert_eq!(functor[3], Cell(str_loc_as_cell!(9))); + assert_eq!(functor[4], Cell(str_loc_as_cell!(11))); + assert_eq!(functor[5], Cell(char_as_cell!('c'))); + assert_eq!(functor[6], InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))); + assert_eq!(functor[7], InnerFunctor(2, functor!(atom!("c"), [fixnum(1)]))); + assert_eq!(functor[8], InnerFunctor(3, functor!(atom!("d"), [fixnum(453), fixnum(2)]))); + } + + #[test] + fn basic_terms_in_heap() { + let functor = functor!(atom!("first"), [atom_as_cell((atom!("a"))), char_as_cell('b')]); + + assert_eq!(functor.len(), 3); + + let mut heap = Heap::new(); + let mut functor_writer = Heap::functor_writer(functor); + let loc = functor_writer(&mut heap).unwrap(); + + assert_eq!(loc, str_loc_as_cell!(0)); + + assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2)); + assert_eq!(heap[1], atom_as_cell!(atom!("a"))); + assert_eq!(heap[2], char_as_cell!('b')); + + heap.truncate(2); + + let functor = functor!(atom!("second"), [atom_as_cell((atom!("a"))), + functor((atom!("b")), [fixnum(1), fixnum(2)]), + functor((atom!("c")), [fixnum(1), fixnum(2)]), + char_as_cell('b')]); + + assert_eq!(functor.len(), 7); + + let mut functor_writer = Heap::functor_writer(functor); + let loc = functor_writer(&mut heap).unwrap(); + + assert_eq!(loc, str_loc_as_cell!(2)); + + assert_eq!(heap[2], atom_as_cell!(atom!("second"), 4)); + assert_eq!(heap[3], atom_as_cell!(atom!("a"))); + assert_eq!(heap[4], str_loc_as_cell!(7)); + assert_eq!(heap[5], str_loc_as_cell!(10)); + assert_eq!(heap[6], char_as_cell!('b')); + assert_eq!(heap[7], atom_as_cell!(atom!("b"), 2)); + assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1))); + assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2))); + assert_eq!(heap[10], atom_as_cell!(atom!("c"), 2)); + assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1))); + assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(2))); + } + + #[test] + fn nested_functors() { + let functor = functor!(atom!("first"), [atom_as_cell((atom!("a"))), + functor((atom!("d")), [fixnum(1), + functor((atom!("b")), + [atom_as_cell((atom!("c"))), + char_as_cell('c')])]), + functor((atom!("e")), [fixnum(453), + fixnum(2)]), + char_as_cell('b')]); + + assert_eq!(functor.len(), 7); + + assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 4))); + assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a")))); + assert_eq!(functor[2], Cell(str_loc_as_cell!(5))); + assert_eq!(functor[3], Cell(str_loc_as_cell!(11))); + assert_eq!(functor[4], Cell(char_as_cell!('b'))); + assert_eq!(functor[5], InnerFunctor(6, vec![Cell(atom_as_cell!(atom!("d"), 2)), + Cell(fixnum_as_cell!(Fixnum::build_with(1))), + Cell(str_loc_as_cell!(3)), + InnerFunctor(3, functor!(atom!("b"), [atom_as_cell((atom!("c"))), + char_as_cell('c')]))])); + assert_eq!(functor[6], InnerFunctor(3, functor!(atom!("e"), [fixnum(453), + fixnum(2)]))); + } + + + #[test] + fn nested_functors_in_heap() { + let functor = functor!(atom!("first"), [atom_as_cell((atom!("a"))), + functor((atom!("second")), [fixnum(1), + functor((atom!("third")), [atom_as_cell((atom!("b"))), + char_as_cell('c')])]), + functor((atom!("fourth")), [fixnum(453), fixnum(2)]), + char_as_cell('b')]); + + let mut heap = Heap::new(); + let mut functor_writer = Heap::functor_writer(functor); + let loc = functor_writer(&mut heap).unwrap(); + + assert_eq!(loc, str_loc_as_cell!(0)); + + assert_eq!(heap.cell_len(), 14); + + assert_eq!(heap[0], atom_as_cell!(atom!("first"), 4)); + assert_eq!(heap[1], atom_as_cell!(atom!("a"))); + assert_eq!(heap[2], str_loc_as_cell!(5)); + assert_eq!(heap[3], str_loc_as_cell!(11)); + assert_eq!(heap[4], char_as_cell!('b')); + assert_eq!(heap[5], atom_as_cell!(atom!("second"), 2)); + assert_eq!(heap[6], fixnum_as_cell!(Fixnum::build_with(1))); + assert_eq!(heap[7], str_loc_as_cell!(8)); + assert_eq!(heap[8], atom_as_cell!(atom!("third"), 2)); + assert_eq!(heap[9], atom_as_cell!(atom!("b"))); + assert_eq!(heap[10], char_as_cell!('c')); + assert_eq!(heap[11], atom_as_cell!(atom!("fourth"), 2)); + assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(453))); + assert_eq!(heap[13], fixnum_as_cell!(Fixnum::build_with(2))); + } + + #[test] + fn functors_with_strings_in_heap() { + let functor = functor!(atom!("first"), [string((String::from("a string")))]); + + assert_eq!(functor.len(), 3); + + let mut heap = Heap::new(); + let mut functor_writer = Heap::functor_writer(functor); + let loc = functor_writer(&mut heap).unwrap(); + + assert_eq!(loc, str_loc_as_cell!(0)); + assert_eq!(heap.cell_len(), 5); + + assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1)); + assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2))); + assert_eq!(heap.slice_to_str(heap_index!(2), "a string".len()), "a string"); + assert_eq!(heap[4], empty_list_as_cell!()); + + heap.truncate(0); + + let functor = functor!(atom!("second"), [string((String::from("a stuttered\0 string")))]); + + let mut functor_writer = Heap::functor_writer(functor); + functor_writer(&mut heap).unwrap(); + + assert_eq!(heap.cell_len(), 7); + + assert_eq!(heap[0], atom_as_cell!(atom!("second"), 1)); + assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2))); + assert_eq!(heap.slice_to_str(heap_index!(2), "a stuttered".len()), "a stuttered"); + assert_eq!(heap[4], pstr_loc_as_cell!(heap_index!(5))); + assert_eq!(heap.slice_to_str(heap_index!(5), " string".len()), " string"); + assert_eq!(heap[6], empty_list_as_cell!()); + } + + #[test] + fn functors_with_lists_in_heap() { + let functor = functor!( + atom!("first"), + [list([fixnum(1), + atom_as_cell((atom!("a"))), + fixnum(2)])] + ); + + assert_eq!(functor.len(), 3); + + let mut heap = Heap::new(); + let mut functor_writer = Heap::functor_writer(functor); + + functor_writer(&mut heap).unwrap(); + + assert_eq!(heap.cell_len(), 11); + + assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1)); + assert_eq!(heap[1], str_loc_as_cell!(2)); + assert_eq!(heap[2], atom_as_cell!(atom!("."), 2)); + assert_eq!(heap[3], fixnum_as_cell!(Fixnum::build_with(1))); + assert_eq!(heap[4], str_loc_as_cell!(5)); + assert_eq!(heap[5], atom_as_cell!(atom!("."), 2)); + assert_eq!(heap[6], atom_as_cell!(atom!("a"))); + assert_eq!(heap[7], str_loc_as_cell!(8)); + assert_eq!(heap[8], atom_as_cell!(atom!("."), 2)); + assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2))); + assert_eq!(heap[10], empty_list_as_cell!()); + } + + #[test] + fn inlined_atoms() { + let atom_table = AtomTable::new(); + let inlined = AtomTable::build_with(&atom_table, "inline"); + + assert!(inlined.is_inlined()); + assert_eq!(&*inlined.as_str(), "inline"); + + let non_inlined = AtomTable::build_with(&atom_table, "longer non-inlined atom"); + + assert!(!non_inlined.is_inlined()); + assert_eq!(&*non_inlined.as_str(), "longer non-inlined atom"); + } + + #[test] + fn functors_with_indexing_code_ptr() { + let code_ptr = IndexingCodePtr::Internal(0); + let functor = functor!( + atom!("first"), + [string((String::from("a string"))), + indexing_code_ptr(code_ptr)] + ); + + let mut heap = Heap::new(); + let mut functor_writer = Heap::functor_writer(functor); + + functor_writer(&mut heap).unwrap(); + + assert_eq!(heap.cell_len(), 8); + + assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2)); + assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3))); + assert_eq!(heap[2], str_loc_as_cell!(6)); + assert_eq!(heap.slice_to_str(heap_index!(3), "a string".len()), "a string"); + assert_eq!(heap[5], empty_list_as_cell!()); + assert_eq!(heap[6], atom_as_cell!(atom!("internal"), 1)); + assert_eq!(heap[7], fixnum_as_cell!(Fixnum::build_with(0))); + + heap.truncate(0); + + let functor = functor!(atom!("second"), + [string((String::from("a string"))), + functor((atom!("third")), [atom_as_cell((atom!("a"))), + string((String::from("another string"))), + indexing_code_ptr(code_ptr)])]); + + let mut functor_writer = Heap::functor_writer(functor); + functor_writer(&mut heap).unwrap(); + + assert_eq!(heap.cell_len(), 15); + + assert_eq!(heap[0], atom_as_cell!(atom!("second"), 2)); + assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3))); + assert_eq!(heap[2], str_loc_as_cell!(6)); + assert_eq!(heap.slice_to_str(heap_index!(3), "a string".len()), "a string"); + assert_eq!(heap[5], empty_list_as_cell!()); + assert_eq!(heap[6], atom_as_cell!(atom!("third"), 3)); + assert_eq!(heap[7], atom_as_cell!(atom!("a"))); + assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(10))); + assert_eq!(heap[9], str_loc_as_cell!(13)); + assert_eq!(heap.slice_to_str(heap_index!(10), "another string".len()), "another string"); + assert_eq!(heap[12], empty_list_as_cell!()); + assert_eq!(heap[13], atom_as_cell!(atom!("internal"), 1)); + assert_eq!(heap[14], fixnum_as_cell!(Fixnum::build_with(0))); + + let functor = functor!(atom!("fourth"), + [string((String::from("a string"))), + functor((atom!("a")), + [functor((atom!("fifth")), [fixnum(5), + string((String::from("another string"))), + indexing_code_ptr(code_ptr)]), + string((String::from("and another")))])]); + + heap.truncate(0); + + let mut functor_writer = Heap::functor_writer(functor); + functor_writer(&mut heap).unwrap(); + + assert_eq!(heap.cell_len(), 21); + + assert_eq!(heap[0], atom_as_cell!(atom!("fourth"), 2)); + assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3))); + assert_eq!(heap[2], str_loc_as_cell!(6)); + assert_eq!(heap.slice_to_str(heap_index!(3), "a string".len()), "a string"); + assert_eq!(heap[5], empty_list_as_cell!()); + assert_eq!(heap[6], atom_as_cell!(atom!("a"), 2)); + assert_eq!(heap[7], str_loc_as_cell!(9)); + assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(18))); // <-- wrong! + assert_eq!(heap[9], atom_as_cell!(atom!("fifth"), 3)); + assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(5))); + assert_eq!(heap[11], pstr_loc_as_cell!(heap_index!(13))); + assert_eq!(heap[12], str_loc_as_cell!(16)); + assert_eq!(heap.slice_to_str(heap_index!(13), "another string".len()), "another string"); + assert_eq!(heap[15], empty_list_as_cell!()); + assert_eq!(heap[16], atom_as_cell!(atom!("internal"), 1)); + assert_eq!(heap[17], fixnum_as_cell!(Fixnum::build_with(0))); + assert_eq!(heap.slice_to_str(heap_index!(18), "and another".len()), "and another"); + assert_eq!(heap[20], empty_list_as_cell!()); + } + + #[test] + fn undefined_procedure_functor() { + // existence_error + let culprit = functor!(atom!("/"), [atom_as_cell((atom!("a"))), fixnum(1)]); + + let stub = functor!( + atom!("existence_error"), + [atom_as_cell((atom!("procedure"))), functor((culprit.clone()))] + ); + + println!("{:?}", stub); + + // now the error form + let lineless_error_form = functor!( + atom!("error"), + [functor(stub), + functor(culprit)] + ); + + println!("{:?}", lineless_error_form); + + let mut heap = Heap::new(); + let mut functor_writer = Heap::functor_writer(lineless_error_form); + + functor_writer(&mut heap).unwrap(); + + assert_eq!(heap[0], atom_as_cell!(atom!("error"), 2)); + assert_eq!(heap[1], str_loc_as_cell!(3)); + assert_eq!(heap[2], str_loc_as_cell!(9)); + assert_eq!(heap[3], atom_as_cell!(atom!("existence_error"), 2)); + assert_eq!(heap[4], atom_as_cell!(atom!("procedure"))); + assert_eq!(heap[5], str_loc_as_cell!(6)); // is str_loc_as_cell!(3) + assert_eq!(heap[6], atom_as_cell!(atom!("/"), 2)); + assert_eq!(heap[7], atom_as_cell!(atom!("a"))); + assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1))); + assert_eq!(heap[9], atom_as_cell!(atom!("/"), 2)); + assert_eq!(heap[10], atom_as_cell!(atom!("a"))); + assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1))); + } + + #[test] + fn argless_functor() { + let name = functor!(atom!("[]")); + + assert_eq!(name.len(), 1); + + let mut heap = Heap::new(); + let mut functor_writer = Heap::functor_writer(name); + let loc = functor_writer(&mut heap).unwrap(); + + assert_eq!(loc, heap_loc_as_cell!(0)); + } + + #[test] + fn predefined_subfunctors() { + let stub = functor!(atom!("sub"), [atom_as_cell((atom!("[]")))]); + let name = functor!(atom!("super"), [functor(stub)]); + + let mut heap = Heap::new(); + let mut functor_writer = Heap::functor_writer(name); + + functor_writer(&mut heap).unwrap(); + + assert_eq!(heap.cell_len(), 4); + + assert_eq!(heap[0], atom_as_cell!(atom!("super"), 1)); + assert_eq!(heap[1], str_loc_as_cell!(2)); + assert_eq!(heap[2], atom_as_cell!(atom!("sub"), 1)); + assert_eq!(heap[3], empty_list_as_cell!()); + } +} diff --git a/src/heap_iter.rs b/src/heap_iter.rs index 5b621836..89f39281 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -116,24 +116,10 @@ impl<'a> EagerStackfulPreOrderHeapIter<'a> { } } (HeapCellValueTag::PStrLoc, h) => { - let h = if self.heap[h].get_tag() == HeapCellValueTag::PStr { - h - } else { - debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::PStrOffset); - self.heap[h].get_value() as usize - }; + let (_, tail_loc) = self.heap.scan_slice_to_str(h); - if self.heap[h].get_mark_bit() == self.mark_phase { - continue; - } - - self.heap[h].set_mark_bit(self.mark_phase); - - if self.heap[h].get_tag() == HeapCellValueTag::PStr { - let value = self.heap[h+1]; - self.heap[h+1].set_mark_bit(self.mark_phase); - self.iter_stack.push(value); - } + self.heap[tail_loc].set_mark_bit(self.mark_phase); + self.iter_stack.push(self.heap[tail_loc]); } _ => { } @@ -249,7 +235,7 @@ impl ListElisionPolicy for NonListElider { #[derive(Debug)] pub struct StackfulPreOrderHeapIter<'a, ElideLists> { - pub heap: &'a mut [HeapCellValue], + pub heap: &'a mut Heap, pub machine_stack: &'a mut Stack, stack: Vec, h: IterStackLoc, @@ -264,14 +250,10 @@ impl<'a, ElideLists> Drop for StackfulPreOrderHeapIter<'a, ElideLists> { cell.set_forwarding_bit(false); cell.set_mark_bit(false); } - - // self.heap.pop(); } } -pub trait FocusedHeapIter: - Deref + Iterator -{ +pub trait FocusedHeapIter: Deref + Iterator { fn focus(&self) -> IterStackLoc; } @@ -285,7 +267,7 @@ impl<'a, ElideLists: ListElisionPolicy> FocusedHeapIter } impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> { - type Target = [HeapCellValue]; + type Target = Heap; fn deref(&self) -> &Self::Target { &self.heap @@ -368,7 +350,7 @@ impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> { impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> { #[inline] - fn new(heap: &'a mut [HeapCellValue], stack: &'a mut Stack, root_loc: usize) -> Self { + fn new(heap: &'a mut Heap, stack: &'a mut Stack, root_loc: usize) -> Self { let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap); // heap.push(cell); @@ -395,8 +377,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> } (HeapCellValueTag::Str | HeapCellValueTag::AttrVar | - HeapCellValueTag::Var | - HeapCellValueTag::PStrLoc, vh) => { + HeapCellValueTag::Var, vh) => { if self.heap[vh].get_mark_bit() { self.read_cell_mut(loc).set_forwarding_bit(true); } @@ -438,7 +419,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> } read_heap_cell!(*cell, - (HeapCellValueTag::Str | HeapCellValueTag::PStrLoc, vh) => { + (HeapCellValueTag::Str, vh) => { let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap); self.push_if_unmarked(loc); @@ -469,20 +450,30 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> self.push_if_unmarked(loc); self.stack.push(IterStackLoc::mark_loc(vs, HeapOrStackTag::Stack)); } - (HeapCellValueTag::PStrOffset, offset) => { - self.push_if_unmarked(IterStackLoc::iterable_loc(offset, HeapOrStackTag::Heap)); - self.stack.push(IterStackLoc::iterable_loc((h.value()+1) as usize, HeapOrStackTag::Heap)); + (HeapCellValueTag::PStrLoc, vh) => { + let cell = *cell; + let (_, tail_loc) = self.heap.scan_slice_to_str(vh); - return Some(self.read_cell(h)); - } - (HeapCellValueTag::PStr) => { - let tail_loc = IterStackLoc::iterable_loc((h.value()+1) as usize, HeapOrStackTag::Heap); + // forward the current PStrLoc cell if the zero + // byte at the end of the string buffer + // is marked + let buf_bytes = self.heap[tail_loc - 1].into_bytes(); - self.push_if_unmarked(IterStackLoc::iterable_loc(h.value() as usize, HeapOrStackTag::Heap)); - self.stack.push(tail_loc); - self.forward_if_referent_marked(tail_loc); + if buf_bytes[7] != 0u8 { + let cell = self.read_cell_mut(h); + cell.set_forwarding_bit(true); + } - return Some(self.read_cell(h)); + // now mark it as if were a HeapCellValue, even + // though it's not! this is fine as long as its tag + // is never inspected, which it isn't. + + self.push_if_unmarked( + IterStackLoc::iterable_loc(tail_loc - 1, HeapOrStackTag::Heap), + ); + self.stack.push(IterStackLoc::mark_loc(tail_loc, HeapOrStackTag::Heap)); + + return Some(cell); } (HeapCellValueTag::Atom, (_name, arity)) => { let l = h.value() as usize; @@ -523,7 +514,7 @@ impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a #[inline(always)] pub(crate) fn cycle_detecting_stackless_preorder_iter( - heap: &'_ mut [HeapCellValue], + heap: &'_ mut Heap, start: usize, ) -> CycleDetectingIter<'_, true> { // const generics argument of true so that cycle discovery stops @@ -533,7 +524,7 @@ pub(crate) fn cycle_detecting_stackless_preorder_iter( #[inline(always)] pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>( - heap: &'a mut Vec, + heap: &'a mut Heap, stack: &'a mut Stack, root_loc: usize, ) -> StackfulPreOrderHeapIter<'a, ElideLists> { @@ -543,13 +534,13 @@ pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>( #[derive(Debug)] pub(crate) struct PostOrderIterator { focus: IterStackLoc, - base_iter: Iter, + pub(crate) base_iter: Iter, base_iter_valid: bool, parent_stack: Vec<(usize, HeapCellValue, IterStackLoc)>, // number of children, parent node, focus. } impl Deref for PostOrderIterator { - type Target = [HeapCellValue]; + type Target = Heap; fn deref(&self) -> &Self::Target { &self.base_iter @@ -592,7 +583,7 @@ impl Iterator for PostOrderIterator { (HeapCellValueTag::Lis) => { self.parent_stack.push((2, item, focus)); } - (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + (HeapCellValueTag::PStrLoc) => { // HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { self.parent_stack.push((1, item, focus)); } _ => { @@ -678,6 +669,8 @@ pub(crate) fn stackful_post_order_iter<'a, ElideLists: ListElisionPolicy>( #[cfg(test)] mod tests { use super::*; + + use crate::functor_macro::*; use crate::machine::gc::IteratorUMP; use crate::machine::mock_wam::*; @@ -686,7 +679,7 @@ mod tests { #[inline(always)] pub(crate) fn stackless_preorder_iter( - heap: &mut [HeapCellValue], + heap: &mut Heap, start: usize, ) -> StacklessPreOrderHeapIter { StacklessPreOrderHeapIter::::new(heap, start) @@ -705,15 +698,21 @@ mod tests { fn heap_stackless_iter_tests() { let mut wam = MockWAM::new(); + // clear the heap of resource error data etc + wam.machine_st.heap.clear(); + let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); - wam.machine_st - .heap - .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [atom_as_cell(a_atom), + atom_as_cell(b_atom)]), + ); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3); @@ -734,21 +733,23 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.extend(functor!( + let mut functor_writer = Heap::functor_writer(functor!( f_atom, [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(0)) + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(0) ] )); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + + wam.machine_st.heap.push_cell(cell).unwrap(); for _ in 0..20 { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5); @@ -757,51 +758,10 @@ mod tests { unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); - assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - atom_as_cell!(a_atom) + str_loc_as_cell!(0) ); - - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - atom_as_cell!(b_atom) - ); - - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - atom_as_cell!(a_atom) - ); - - assert_eq!(iter.next(), None); - } - - all_cells_unmarked(&wam.machine_st.heap); - - wam.machine_st.heap.clear(); - - wam.machine_st.heap.push(str_loc_as_cell!(1)); - - wam.machine_st.heap.extend(functor!( - f_atom, - [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(1)) - ] - )); - - for _ in 0..200000 { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); - - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - atom_as_cell!(f_atom, 4) - ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) @@ -818,12 +778,12 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); { - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -834,16 +794,20 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -873,12 +837,10 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); - - wam.machine_st.heap.pop(); + all_cells_unmarked(wam.machine_st.heap.splice(..)); // now make the list cyclic. - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -909,181 +871,96 @@ mod tests { wam.machine_st.heap.clear(); - // first a 'dangling' partial string, later modified to be a two-part complete string, - // then a three-part cyclic string involving an uncompacted list of chars. - let pstr_var_cell = - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); - let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.allocate_pstr("abc ").unwrap(); + + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) + ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1), ); - assert!(iter.next().is_none()); } - assert_eq!(wam.machine_st.heap[0], pstr_cell); - assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); + wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.heap[1] = pstr_loc_as_cell!(3); + wam.machine_st.allocate_pstr("def").unwrap(); - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); - - let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2); + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3)) + ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(4), ); - assert!(iter.next().is_none()); } - assert_eq!(wam.machine_st.heap[0], pstr_cell); - assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(3)); - assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(0)); - assert_eq!(wam.machine_st.heap[3], pstr_second_cell); - assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(4)); - - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(5)); - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); - - wam.machine_st.heap[2] = heap_loc_as_cell!(4); + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2); { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2); + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5); - let pstr_offset_cell = pstr_offset_as_cell!(0); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - fixnum_as_cell!(Fixnum::build_with(2)) + pstr_loc_as_cell!(0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3) + 2) ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(iter.next(), None); } - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), - pstr_loc_as_cell!(3) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(0) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) - ); - - wam.machine_st.heap.truncate(4); - - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); - - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0i64))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 6); - let pstr_offset_cell = pstr_offset_as_cell!(0); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - pstr_loc_as_cell!(4) - ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - fixnum_as_cell!(Fixnum::build_with(0)) - ); - - assert_eq!(iter.next(), None); - } - - all_cells_unmarked(&wam.machine_st.heap); - - wam.machine_st.heap[5] = fixnum_as_cell!(Fixnum::build_with(1i64)); - - { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 6); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - pstr_loc_as_cell!(4) - ); - - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - pstr_offset_as_cell!(0) - ); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - pstr_offset_as_cell!(0) - ); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - fixnum_as_cell!(Fixnum::build_with(1)) - ); - - assert_eq!(iter.next(), None); - } - - assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0)); - assert_eq!( - wam.machine_st.heap[5], - fixnum_as_cell!(Fixnum::build_with(1i64)) - ); - - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(empty_list_as_cell!()); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(empty_list_as_cell!()); + }); - wam.machine_st.heap.extend(functor); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(b_atom)] + )); + + functor_writer(&mut wam.machine_st.heap).unwrap(); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1126,7 +1003,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1167,7 +1044,7 @@ mod tests { // instance. } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); @@ -1197,7 +1074,7 @@ mod tests { // instance. } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); @@ -1249,15 +1126,19 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 4); @@ -1266,7 +1147,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1288,9 +1169,13 @@ mod tests { wam.machine_st.heap.clear(); // print L = [L|L]. - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(1)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(1)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1308,7 +1193,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1326,21 +1211,25 @@ mod tests { wam.machine_st.heap.clear(); // term is [X,f(Y),Z]. - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2 - wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3 - wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4 - wam.machine_st.heap.push(heap_loc_as_cell!(8)); - wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6 - wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7 - wam.machine_st.heap.push(list_loc_as_cell!(9)); - wam.machine_st.heap.push(heap_loc_as_cell!(9)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. - wam.machine_st.heap.push(heap_loc_as_cell!(12)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(3)); // 2 + section.push_cell(list_loc_as_cell!(4)); // 3 + section.push_cell(str_loc_as_cell!(6)); // 4 + section.push_cell(heap_loc_as_cell!(8)); + section.push_cell(atom_as_cell!(f_atom, 1)); // 6 + section.push_cell(heap_loc_as_cell!(11)); // 7 + section.push_cell(list_loc_as_cell!(9)); + section.push_cell(heap_loc_as_cell!(9)); + section.push_cell(empty_list_as_cell!()); + + section.push_cell(attr_var_as_cell!(11)); // linked from 7. + section.push_cell(heap_loc_as_cell!(12)); + section.push_cell(heap_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 13); @@ -1382,22 +1271,25 @@ mod tests { let clpz_atom = atom!("clpz"); let p_atom = atom!("p"); - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); + wam.machine_st.heap.truncate(12); - wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 - wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13 - wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14 - wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15 - wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16 - wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17 - wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18 - wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19 - wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20 - wam.machine_st.heap.push(empty_list_as_cell!()); // 21 - wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 - wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(13)); // 12 + section.push_cell(list_loc_as_cell!(14)); // 13 + section.push_cell(str_loc_as_cell!(16)); // 14 + section.push_cell(heap_loc_as_cell!(19)); // 15 + section.push_cell(atom_as_cell!(clpz_atom, 2)); // 16 + section.push_cell(atom_as_cell!(a_atom)); // 17 + section.push_cell(atom_as_cell!(b_atom)); // 18 + section.push_cell(list_loc_as_cell!(20)); // 19 + section.push_cell(str_loc_as_cell!(22)); // 20 + section.push_cell(empty_list_as_cell!()); // 21 + section.push_cell(atom_as_cell!(p_atom, 1)); // 22 + section.push_cell(heap_loc_as_cell!(23)); // 23 + section.push_cell(heap_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 24); @@ -1535,9 +1427,7 @@ mod tests { wam.machine_st.heap.clear(); { - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0))); + wam.machine_st.heap.push_cell(fixnum_as_cell!(Fixnum::build_with(0))).unwrap(); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1549,15 +1439,18 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1580,14 +1473,18 @@ mod tests { assert!(iter.next().is_none()); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(str_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(str_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + section.push_cell(str_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3); @@ -1607,20 +1504,24 @@ mod tests { assert!(iter.next().is_none()); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); - wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(list_loc_as_cell!(8)); - wam.machine_st.heap.push(str_loc_as_cell!(4)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(atom!("X"))); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(str_loc_as_cell!(4)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 7); @@ -1663,7 +1564,7 @@ mod tests { assert!(iter.next().is_none()); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], str_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(atom!("g"), 2)); @@ -1678,10 +1579,14 @@ mod tests { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("f"), 2)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(str_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3); @@ -1710,18 +1615,21 @@ mod tests { wam.machine_st.heap.clear(); - // representation of one of the heap terms as in issue #1384. - wam.machine_st.heap.push(list_loc_as_cell!(7)); // 0 - wam.machine_st.heap.push(heap_loc_as_cell!(0)); // 1 - wam.machine_st.heap.push(list_loc_as_cell!(3)); // 2 - wam.machine_st.heap.push(list_loc_as_cell!(5)); // 3 - wam.machine_st.heap.push(empty_list_as_cell!()); // 4 - wam.machine_st.heap.push(heap_loc_as_cell!(2)); // 5 - wam.machine_st.heap.push(heap_loc_as_cell!(2)); // 6 - wam.machine_st.heap.push(empty_list_as_cell!()); // 7 - wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 8 + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + // representation of one of the heap terms as in issue #1384. + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(7)); // 0 + section.push_cell(heap_loc_as_cell!(0)); // 1 + section.push_cell(list_loc_as_cell!(3)); // 2 + section.push_cell(list_loc_as_cell!(5)); // 3 + section.push_cell(empty_list_as_cell!()); // 4 + section.push_cell(heap_loc_as_cell!(2)); // 5 + section.push_cell(heap_loc_as_cell!(2)); // 6 + section.push_cell(empty_list_as_cell!()); // 7 + section.push_cell(heap_loc_as_cell!(3)); // 8 + section.push_cell(heap_loc_as_cell!(0)); // 9 + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 9); @@ -1776,21 +1684,29 @@ mod tests { fn heap_stackful_iter_tests() { let mut wam = MockWAM::new(); + // clear the heap of resource error data etc + wam.machine_st.heap.clear(); + let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); - wam.machine_st - .heap - .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [atom_as_cell(a_atom), + atom_as_cell(b_atom)]), + ); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); + + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 3, + h, ); assert_eq!( @@ -1811,21 +1727,26 @@ mod tests { wam.machine_st.heap.clear(); - wam.machine_st.heap.extend(functor!( + let mut functor_writer = Heap::functor_writer(functor!( f_atom, [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(0)) + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(0) ] )); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); + + wam.machine_st.heap.push_cell(cell).unwrap(); + for _ in 0..20 { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 4, + h, ); assert_eq!( @@ -1852,7 +1773,7 @@ mod tests { wam.machine_st.heap.clear(); { - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, @@ -1878,8 +1799,8 @@ mod tests { { // mutually referencing variables. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, @@ -1898,11 +1819,15 @@ mod tests { wam.machine_st.heap.clear(); // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = StackfulPreOrderHeapIter::::new( @@ -1935,10 +1860,8 @@ mod tests { assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - // now make the list cyclic. - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); { let mut iter = StackfulPreOrderHeapIter::::new( @@ -2001,7 +1924,7 @@ mod tests { ); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -2015,156 +1938,112 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - let pstr_var_cell = - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); - let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + wam.machine_st.allocate_pstr("abc ").unwrap(); + + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 0, + 2, ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(1), + pstr_loc_as_cell!(0) ); - - assert_eq!(iter.next(), None); - } - - // here - - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); - let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; - - { - let mut iter = stackful_preorder_iter::( - &mut wam.machine_st.heap, - &mut wam.machine_st.stack, - 0, - ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3), + heap_loc_as_cell!(1) ); - - assert_eq!(iter.next(), None); + assert!(iter.next().is_none()); } - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); + wam.machine_st.allocate_pstr("def").unwrap(); - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0i64))); - - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 5, ); - let pstr_offset_cell = pstr_offset_as_cell!(0); - - // pstr_offset_cell.set_forwarding_bit(true); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!( - iter.next().unwrap(), - fixnum_as_cell!(Fixnum::build_with(0i64)) + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(4), ); - assert_eq!(iter.next(), None); } - /* - { - let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); - let string: String = iter.chars().collect(); - assert_eq!(string, "abc def"); - } - */ - - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1i64))); - - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2); { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 5, ); - let pstr_offset_cell = pstr_offset_as_cell!(0); - - // pstr_offset_cell.set_forwarding_bit(true); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!( - iter.next().unwrap(), - fixnum_as_cell!(Fixnum::build_with(1i64)) + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) ); - - let h = iter.focus(); - - assert_eq!(h.value(), 5); - assert_eq!(unmark_cell_bits!(iter.heap[4]), pstr_offset_as_cell!(0)); assert_eq!( - unmark_cell_bits!(iter.heap[5]), - fixnum_as_cell!(Fixnum::build_with(1i64)) + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3) + 2) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3) + 2) ); - assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); - let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + let functor = functor!( + f_atom, + [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)] + ); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.extend(functor); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(empty_list_as_cell!()); + }); - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut functor_writer = Heap::functor_writer(functor); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 0, ); assert_eq!( @@ -2219,7 +2098,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -2227,7 +2106,7 @@ mod tests { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 0, ); assert_eq!( @@ -2284,13 +2163,17 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(1)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(1)); + }); { let mut iter = StackfulPreOrderHeapIter::::new( @@ -2319,13 +2202,17 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(pstr_as_cell!(atom!("a string"))); - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_pstr("a string"); + section.push_cell(empty_list_as_cell!()); + section.push_cell(pstr_loc_as_cell!(0)); + }); { let mut iter = stackful_preorder_iter::( @@ -2335,38 +2222,41 @@ mod tests { ); assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - pstr_as_cell!(atom!("a string")) + iter.heap.slice_to_str(0, "a string".len()), + "a string" + ); + assert_eq!( + iter.next().unwrap(), + empty_list_as_cell!() ); - - assert_eq!(iter.next().unwrap(), empty_list_as_cell!()); - assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); - wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(list_loc_as_cell!(8)); - wam.machine_st.heap.push(str_loc_as_cell!(4)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(atom!("X"))); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(str_loc_as_cell!(4)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(heap_loc_as_cell!(0)); + }); { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 10, ); assert_eq!( @@ -2392,21 +2282,29 @@ mod tests { fn heap_stackful_post_order_iter() { let mut wam = MockWAM::new(); + // clear the heap of resource error data etc + wam.machine_st.heap.clear(); + let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); - wam.machine_st.heap.push(str_loc_as_cell!(1)); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [atom_as_cell(a_atom), + atom_as_cell(b_atom)]), + ); - wam.machine_st - .heap - .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); + + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 0, + h, ); assert_eq!( @@ -2427,23 +2325,28 @@ mod tests { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - wam.machine_st.heap.extend(functor!( + + let mut functor_writer = Heap::functor_writer(functor!( f_atom, [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(1)) + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(0) ] )); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); + + wam.machine_st.heap.push_cell(cell).unwrap(); + for _ in 0..20 { // 0000 { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 0, + h, ); assert_eq!( @@ -2458,9 +2361,10 @@ mod tests { unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1)); - + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + str_loc_as_cell!(0) + ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) @@ -2472,7 +2376,7 @@ mod tests { wam.machine_st.heap.clear(); { - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, @@ -2498,8 +2402,8 @@ mod tests { { // mutually referencing variables. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, @@ -2518,20 +2422,21 @@ mod tests { wam.machine_st.heap.clear(); // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 0, ); assert_eq!( @@ -2558,18 +2463,14 @@ mod tests { assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - // now make the list cyclic. - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 4, ); // the cycle will be iterated twice before being detected. @@ -2618,7 +2519,7 @@ mod tests { ); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -2632,140 +2533,106 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - let pstr_var_cell = - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); - let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + wam.machine_st.allocate_pstr("abc ").unwrap(); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - let h = wam.machine_st.heap.len() - 1; + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 2, ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1), ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) + ); assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); + wam.machine_st.allocate_pstr("def").unwrap(); - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); - let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - let h = wam.machine_st.heap.len() - 1; + wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 5, ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3), + heap_loc_as_cell!(4), + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); - - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0i64))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - let h = wam.machine_st.heap.len() - 1; + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 5, ); assert_eq!( - iter.next().unwrap(), - fixnum_as_cell!(Fixnum::build_with(0i64)) + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3) + 2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - pstr_offset_as_cell!(0) - ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - - assert_eq!(iter.next(), None); - } - - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1i64))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - let h = wam.machine_st.heap.len() - 1; - - { - let mut iter = stackful_post_order_iter::( - &mut wam.machine_st.heap, - &mut wam.machine_st.stack, - h, - ); - - assert_eq!( - iter.next().unwrap(), - fixnum_as_cell!(Fixnum::build_with(1i64)) + pstr_loc_as_cell!(heap_index!(3) + 2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - pstr_offset_as_cell!(0) + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); - let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + let functor = functor!( + f_atom, + [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)] + ); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.extend(functor); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(empty_list_as_cell!()); + }); + + let mut functor_writer = Heap::functor_writer(functor); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = stackful_post_order_iter::( @@ -2827,7 +2694,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -2894,7 +2761,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); } @@ -2902,15 +2769,21 @@ mod tests { fn heap_stackless_post_order_iter() { let mut wam = MockWAM::new(); + // clear the heap of resource error data etc + wam.machine_st.heap.clear(); + let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); - wam.machine_st - .heap - .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [atom_as_cell(a_atom), + atom_as_cell(b_atom)]), + ); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 3); @@ -2933,17 +2806,18 @@ mod tests { wam.machine_st.heap.clear(); - wam.machine_st.heap.extend(functor!( + let mut functor_writer = Heap::functor_writer(functor!( f_atom, [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(0)) + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(0) ] )); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + wam.machine_st.heap.push_cell(cell).unwrap(); for _ in 0..20 { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 5); @@ -2974,7 +2848,7 @@ mod tests { wam.machine_st.heap.clear(); { - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); @@ -2989,8 +2863,8 @@ mod tests { { // mutually referencing variables. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); @@ -3010,11 +2884,15 @@ mod tests { wam.machine_st.heap.clear(); // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); @@ -3043,10 +2921,8 @@ mod tests { assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - // now make the list cyclic. - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); @@ -3093,7 +2969,7 @@ mod tests { ); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -3107,11 +2983,10 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - let pstr_var_cell = - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); - let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + wam.machine_st.allocate_pstr("abc ").unwrap(); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 2); @@ -3120,108 +2995,68 @@ mod tests { unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1), ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) + ); assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + wam.machine_st.heap[2] = heap_loc_as_cell!(2); + wam.machine_st.allocate_pstr("def").unwrap(); - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); - - let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3), + heap_loc_as_cell!(1), ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - - assert_eq!(iter.next(), None); - } - - all_cells_unmarked(&wam.machine_st.heap); - - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); - - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - { - let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7); - let mut pstr_loc_cell = pstr_loc_as_cell!(0); - - pstr_loc_cell.set_forwarding_bit(true); - - // assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3) + pstr_loc_as_cell!(0) ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2); { - let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7); + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4); - //assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1))); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3) + pstr_loc_as_cell!(heap_index!(3) + 2) ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } + all_cells_unmarked(wam.machine_st.heap.splice(..)); + wam.machine_st.heap.clear(); - let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + let functor = functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)]); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.extend(functor); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(empty_list_as_cell!()); + }); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut functor_writer = Heap::functor_writer(functor); + functor_writer(&mut wam.machine_st.heap).unwrap(); { - let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 9); + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), @@ -3264,7 +3099,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -3312,6 +3147,6 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 8d434b15..2bc1706b 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -9,7 +9,6 @@ use crate::forms::*; use crate::heap_iter::*; use crate::machine::heap::*; use crate::machine::machine_indices::*; -use crate::machine::machine_state::pstr_loc_and_offset; use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::streams::*; @@ -25,7 +24,6 @@ use std::convert::TryFrom; use std::iter::once; use std::net::{IpAddr, TcpListener}; use std::rc::Rc; -use std::sync::Arc; /* contains the location, name, precision and Specifier of the parent op. */ #[derive(Debug, Copy, Clone)] @@ -206,11 +204,12 @@ impl NumberFocus { #[derive(Debug, Clone, Copy)] struct CommaSeparatedCharList { - pstr: PartialString, - offset: usize, + // pstr: PartialString, + // offset: usize, + pstr_loc: usize, max_depth: usize, - end_cell: HeapCellValue, - end_h: Option, + // end_cell: HeapCellValue, + // end_h: Option, } #[derive(Debug, Clone)] @@ -473,7 +472,6 @@ pub fn fmt_float(mut fl: f64) -> String { pub struct HCPrinter<'a, Outputter> { outputter: Outputter, iter: StackfulPreOrderHeapIter<'a, ListElider>, - atom_tbl: Arc, op_dir: &'a OpDir, state_stack: Vec, toplevel_spec: Option, @@ -488,9 +486,19 @@ pub struct HCPrinter<'a, Outputter> { pub double_quotes: bool, } +fn ambiguity_check(outputter: &impl HCValueOutputter, quoted: bool, last_item_idx: usize, atom: &str) -> bool { + let tail = &outputter.as_str()[last_item_idx..]; + + if atom == "," || !quoted || non_quoted_token(atom.chars()) { + requires_space(tail, atom) + } else { + requires_space(tail, "'") + } +} + macro_rules! push_space_if_amb { ($self:expr, $atom:expr, $action:block) => { - if $self.ambiguity_check($atom) { + if ambiguity_check(&$self.outputter, $self.quoted, $self.last_item_idx, $atom) { $self.outputter.push_char(' '); $action; } else { @@ -528,7 +536,6 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { pub fn new( heap: &'a mut Heap, - atom_tbl: Arc, stack: &'a mut Stack, op_dir: &'a OpDir, output: Outputter, @@ -537,7 +544,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { HCPrinter { outputter: output, iter: stackful_preorder_iter(heap, stack, root_loc), - atom_tbl, op_dir, state_stack: vec![], toplevel_spec: None, @@ -553,17 +559,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - #[inline] - fn ambiguity_check(&self, atom: &str) -> bool { - let tail = &self.outputter.as_str()[self.last_item_idx..]; - - if atom == "," || !self.quoted || non_quoted_token(atom.chars()) { - requires_space(tail, atom) - } else { - requires_space(tail, "'") - } - } - fn set_parent_of_first_op(&mut self, parent_op: Option) { if let Some(op) = parent_op { if op.is_left() && op.is_prefix() { @@ -1123,9 +1118,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { // returns true if max_depth limit is reached and ellipsis is printed. fn print_string_as_functor(&mut self, focus: usize, max_depth: &mut usize) -> bool { - let iter = HeapPStrIter::new(self.iter.heap, focus); + let mut iter = HeapPStrIter::new(self.iter.heap, focus); + let mut char_count = 0; - for (char_count, c) in iter.chars().enumerate() { + while let Some(iteratee) = iter.next() { if self.check_max_depth(max_depth) { if char_count > 0 { self.state_stack.push(TokenOrRedirect::Close); @@ -1135,13 +1131,31 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { return true; } - append_str!(self, "'.'"); - push_char!(self, '('); + macro_rules! emit_char { + ($c:expr) => ({ + append_str!(self, "'.'"); + push_char!(self, '('); - print_char!(self, self.quoted, c); - push_char!(self, ','); + print_char!(self, self.quoted, $c); + push_char!(self, ','); - self.state_stack.push(TokenOrRedirect::Close); + self.state_stack.push(TokenOrRedirect::Close); + char_count += 1; + }); + } + + match iteratee { + PStrIteratee::Char { value, .. } => { + emit_char!(value); + } + PStrIteratee::PStrSlice { slice_loc, slice_len } => { + let s = iter.heap.slice_to_str(slice_loc, slice_len); + + for c in s.chars() { + emit_char!(c); + } + } + } } false @@ -1152,7 +1166,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { fn print_proper_string(&mut self, focus: usize, max_depth: usize) { push_char!(self, '"'); - let iter = HeapPStrIter::new(self.iter.heap, focus); + let mut iter = HeapPStrIter::new(self.iter.heap, focus); + let char_to_string = |c: char| { // refrain from quoting characters other than '"' and '\' // unless self.quoted is true. @@ -1164,19 +1179,43 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }; if max_depth == 0 { - for c in iter.chars() { - for c in char_to_string(c).chars() { - push_char!(self, c); + while let Some(iteratee) = iter.next() { + let iter: Box> = match iteratee { + PStrIteratee::Char { value: c, .. } => { + Box::new(std::iter::once(c)) + } + PStrIteratee::PStrSlice { slice_loc, slice_len } => { + let s = iter.heap.slice_to_str(slice_loc, slice_len); + Box::new(s.chars()) + } + }; + + for c in iter { + for c in char_to_string(c).chars() { + push_char!(self, c); + } } } } else { let mut char_count = 0; - for c in iter.chars().take(max_depth) { - char_count += 1; + while let Some(iteratee) = iter.next() { + let iter: Box> = match iteratee { + PStrIteratee::Char { value: c, .. } => { + Box::new(std::iter::once(c)) + } + PStrIteratee::PStrSlice { slice_loc, slice_len } => { + let s = iter.heap.slice_to_str(slice_loc, slice_len); + Box::new(s.chars()) + } + }; - for c in char_to_string(c).chars() { - push_char!(self, c); + for c in iter.take(max_depth - char_count) { + char_count += 1; + + for c in char_to_string(c).chars() { + push_char!(self, c); + } } } @@ -1194,10 +1233,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.iter.pop_stack(); self.iter.pop_stack(); } - HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset => { + HeapCellValueTag::PStrLoc => { self.iter.pop_stack(); } - HeapCellValueTag::CStr => {} + // HeapCellValueTag::CStr => {} _ => { unreachable!(); } @@ -1208,19 +1247,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let focus = self.iter.focus(); let mut heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus.value() as usize); - let next_h; - let next_hare; - - if heap_pstr_iter.next().is_some() { - next_h = heap_pstr_iter.focus; - next_hare = heap_pstr_iter.focus(); + let is_cyclic = if heap_pstr_iter.next().is_some() { for _ in heap_pstr_iter.by_ref() {} + heap_pstr_iter.is_cyclic() } else { return self.push_list(max_depth); - } + }; let end_h = heap_pstr_iter.focus(); - let end_cell = heap_pstr_iter.focus; + let end_cell = heap_pstr_iter.heap[end_h]; // heap_pstr_iter.focus; if self.check_max_depth(&mut max_depth) { self.remove_list_children(focus.value() as usize); @@ -1230,9 +1265,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let at_cdr = self.outputter.ends_with("|"); - if self.double_quotes && !self.ignore_ops && end_cell.is_string_terminator(self.iter.heap) { - self.remove_list_children(focus.value() as usize); - return self.print_proper_string(focus.value() as usize, max_depth); + if self.double_quotes && !self.ignore_ops && !is_cyclic { + if end_cell.is_string_terminator(self.iter.heap) { + self.remove_list_children(focus.value() as usize); + return self.print_proper_string(focus.value() as usize, max_depth); + } } if self.ignore_ops { @@ -1261,37 +1298,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { (HeapCellValueTag::Lis) => { self.push_list(max_depth) } - _ => { + (HeapCellValueTag::PStrLoc, h) => { let switch = Rc::new(Cell::new((!at_cdr, 0))); let switch = self.close_list(switch); - let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus.value() as usize); - - let offset = offset.get_num() as usize; - let tag = value.get_tag(); - - let end_h = if tag == HeapCellValueTag::PStrOffset { - // remove the fixnum offset from the iterator stack so we don't - // print an extraneous number. pstr offset value cells are never - // used by the iterator to mark cyclic terms so the removal is safe. - self.iter.pop_stack(); - Some(next_hare) - // Some(end_h) - } else { - None - }; - if !self.max_depth_exhausted(max_depth) { - let pstr = cell_as_string!(self.iter.heap[h]); - self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList(CommaSeparatedCharList { - pstr, offset, max_depth, end_cell: next_h, end_h, - })); + self.state_stack.push( + TokenOrRedirect::CommaSeparatedCharList( + CommaSeparatedCharList { + pstr_loc: h, max_depth, + } + ), + ); } else { self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); } self.open_list(switch); } + _ => { + unreachable!() + } ); } } @@ -1521,32 +1548,29 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { fn print_comma_separated_char_list(&mut self, char_list: CommaSeparatedCharList) { let CommaSeparatedCharList { - pstr, - offset, + pstr_loc, max_depth, - end_cell, - end_h, } = char_list; - let pstr_str = pstr.as_str_from(offset); - if let Some(c) = pstr_str.chars().next() { - let offset = offset + c.len_utf8(); + let c = self.iter.heap.char_at(pstr_loc); + + if c != '\u{0}' || pstr_loc % std::mem::size_of::() == 0 { + // if a null character in a pstr has location aligned + // to a cell boundary, the string is ['\\x0\\']. if !self.max_depth_exhausted(max_depth) { self.state_stack .push(TokenOrRedirect::CommaSeparatedCharList( CommaSeparatedCharList { - pstr, - offset, + pstr_loc: pstr_loc + c.len_utf8(), max_depth: max_depth.saturating_sub(1), - end_cell, - end_h, }, )); let max_depth_allows = self.max_depth == 0 || max_depth > 1; + let next_c = self.iter.heap.char_at(pstr_loc + c.len_utf8()); - if max_depth_allows && pstr_str.chars().nth(1).is_some() { + if max_depth_allows && next_c != '\u{0}' { self.state_stack.push(TokenOrRedirect::Comma); } @@ -1558,14 +1582,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } else if self.max_depth_exhausted(max_depth) { self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); - } else if end_cell != empty_list_as_cell!() { - if let Some(end_h) = end_h { - self.iter - .push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap)); - } + } else { + /* + let end_cell_h = Heap::neighboring_cell_offset(pstr_loc); + let end_cell = self.iter.heap[end_cell_h]; + let end_cell = heap_bound_store( + self.iter.heap, + heap_bound_deref(self.iter.heap, end_cell), + ); - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); + if end_cell != empty_list_as_cell!() { + self.iter.push_stack( + IterStackLoc::iterable_loc(end_cell_h, HeapOrStackTag::Heap), + ); + } + */ + + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } } @@ -1658,10 +1691,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { (HeapCellValueTag::Atom, (name, arity)) => { print_struct(self, name, arity); } - (HeapCellValueTag::Char, c) => { - let name = AtomTable::build_with(&self.atom_tbl, &String::from(c)); - print_struct(self, name, 0); - } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.iter.heap[s]) .get_name_and_arity(); @@ -1688,7 +1717,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { (HeapCellValueTag::F64, f) => { self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(*f)), &op); } - (HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + (HeapCellValueTag::PStrLoc) => { // HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { self.print_list_like(max_depth); } (HeapCellValueTag::Lis) => { @@ -1825,6 +1854,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { mod tests { use super::*; + use crate::functor_macro::*; use crate::machine::mock_wam::*; #[test] @@ -1832,25 +1862,30 @@ mod tests { fn term_printing_tests() { let mut wam = MockWAM::new(); + // clear the heap of resource error data etc + wam.machine_st.heap.clear(); + let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); let c_atom = atom!("c"); - wam.machine_st - .heap - .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [atom_as_cell(a_atom), + atom_as_cell(b_atom)]), + ); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + wam.machine_st.heap.push_cell(cell).unwrap(); { let printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - 0, + 3, ); let output = printer.print(); @@ -1858,31 +1893,31 @@ mod tests { assert_eq!(output.result(), "f(a,b)"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.extend(functor!( + let mut functor_writer = Heap::functor_writer(functor!( f_atom, [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(0)) + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(0) ] )); - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + + wam.machine_st.heap.push_cell(cell).unwrap(); { let printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - h, + 5, ); let output = printer.print(); @@ -1890,19 +1925,22 @@ mod tests { assert_eq!(output.result(), "f(a,b,a,...)"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + // print L = [L|L]. - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(1)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(1)); + }); { let printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), @@ -1915,7 +1953,6 @@ mod tests { let mut printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), @@ -1931,24 +1968,32 @@ mod tests { assert_eq!(output.result(), "[L|L]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(str_loc_as_cell!(5)); - wam.machine_st.heap.push(empty_list_as_cell!()); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(str_loc_as_cell!(5)); + section.push_cell(empty_list_as_cell!()); + }); - wam.machine_st.heap.extend(functor); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(b_atom)] + )); + + functor_writer(&mut wam.machine_st.heap).unwrap(); { let printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), @@ -1960,14 +2005,13 @@ mod tests { assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap[4] = list_loc_as_cell!(1); { let printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), @@ -1979,12 +2023,11 @@ mod tests { assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|...]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); { let mut printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), @@ -2000,23 +2043,27 @@ mod tests { assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|L]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); // issue #382 wam.machine_st.heap.clear(); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - for idx in 0..3000 { - wam.machine_st.heap.push(heap_loc_as_cell!(2 * idx + 1)); - wam.machine_st.heap.push(list_loc_as_cell!(2 * idx + 2 + 1)); - } + let mut writer = wam.machine_st.heap.reserve(6002).unwrap(); - wam.machine_st.heap.push(empty_list_as_cell!()); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + + for idx in 0..3000 { + section.push_cell(heap_loc_as_cell!(2 * idx + 1)); + section.push_cell(list_loc_as_cell!(2 * idx + 2 + 1)); + } + + section.push_cell(empty_list_as_cell!()); + }); { let mut printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), @@ -2030,24 +2077,22 @@ mod tests { assert_eq!(output.result(), "[_1,_3,_5,_7,_9|...]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - put_partial_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl); + wam.machine_st.allocate_pstr("abc").unwrap(); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - let h = wam.machine_st.heap.len() - 1; + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - h, + 2, ); let output = printer.print(); @@ -2055,28 +2100,28 @@ mod tests { assert_eq!(output.result(), "[a,b,c|_1]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(2)); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(5)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(list_loc_as_cell!(7)); + section.push_cell(atom_as_cell!(c_atom)); + section.push_cell(empty_list_as_cell!()); + }); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(4)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(6)); - wam.machine_st.heap.push(atom_as_cell!(c_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.heap[1] = list_loc_as_cell!(3); { let mut printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), - 0, + 2, ); printer.double_quotes = true; @@ -2086,7 +2131,7 @@ mod tests { assert_eq!(output.result(), "\"abcabc\""); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); @@ -2095,14 +2140,14 @@ mod tests { "=(X,[a,b,c|X])" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( &wam.parse_and_print_term("[a,b,\"a\",[a,b,c]].").unwrap(), "[a,b,[a],[a,b,c]]" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( &wam.parse_and_print_term("[\"abc\",e,f,[g,e,h,Y,v|[X,Y]]].") @@ -2110,11 +2155,11 @@ mod tests { "[[a,b,c],e,f,[g,e,h,Y,v,X,Y]]" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(&wam.parse_and_print_term("f((a,b)).").unwrap(), "f((a,b))"); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.op_dir .insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX)); @@ -2126,14 +2171,14 @@ mod tests { "[a|[]+b]" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( &wam.parse_and_print_term("[a|[b|c]*d].").unwrap(), "[a|[b|c]*d]" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.op_dir .insert((atom!("fy"), Fixity::Pre), OpDesc::build_with(9, FY)); diff --git a/src/indexing.rs b/src/indexing.rs index a199e625..d9a4f036 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1,7 +1,8 @@ use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; -use crate::parser::ast::*; +use crate::machine::heap::*; +use crate::parser::ast::Fixnum; use crate::types::*; use fxhash::FxBuildHasher; @@ -144,7 +145,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn add_static_indexed_choice_for_constant( &mut self, external: usize, - constant: Literal, + constant: HeapCellValue, index: usize, ) { let third_level_index = if self.append_or_prepend.is_append() { @@ -181,7 +182,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn add_dynamic_indexed_choice_for_constant( &mut self, external: usize, - constant: Literal, + constant: HeapCellValue, index: usize, ) { let third_level_index = if self.append_or_prepend.is_append() { @@ -235,8 +236,8 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn index_overlapping_constant( &mut self, - orig_constant: Literal, - overlapping_constant: Literal, + orig_constant: HeapCellValue, + overlapping_constant: HeapCellValue, index: usize, ) { loop { @@ -316,7 +317,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { } } - fn index_constant(&mut self, constant: Literal, index: usize) { + fn index_constant(&mut self, constant: HeapCellValue, index: usize) { loop { let indexing_code_len = self.indexing_code.len(); @@ -663,8 +664,8 @@ pub(crate) fn merge_clause_index( } pub(crate) fn remove_constant_indices( - constant: Literal, - overlapping_constants: &[Literal], + constant: HeapCellValue, + overlapping_constants: &[HeapCellValue], indexing_code: &mut [IndexingLine], offset: usize, ) { @@ -1096,12 +1097,28 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) { } pub(crate) fn constant_key_alternatives( - constant: Literal, - atom_tbl: &AtomTable, + constant: HeapCellValue, + // atom_tbl: &AtomTable, // arena: &mut Arena, -) -> Vec { +) -> Vec { let mut constants = vec![]; + match Number::try_from(constant) { + Ok(Number::Integer(n)) => { + let result = (&*n).try_into(); + if let Ok(value) = result { + constants.push( + Fixnum::build_with_checked(value) + .map(|n| fixnum_as_cell!(n)) + .unwrap() + ); + } + } + _ => { + } + } + + /* match constant { Literal::Atom(ref name) => { if let Some(c) = name.as_char() { @@ -1131,20 +1148,21 @@ pub(crate) fn constant_key_alternatives( } _ => {} } + */ constants } #[derive(Debug)] pub(crate) struct StaticCodeIndices { - constants: IndexMap, FxBuildHasher>, + constants: IndexMap, FxBuildHasher>, lists: VecDeque, structures: IndexMap<(Atom, usize), VecDeque, FxBuildHasher>, } #[derive(Debug)] pub(crate) struct DynamicCodeIndices { - constants: IndexMap, FxBuildHasher>, + constants: IndexMap, FxBuildHasher>, lists: VecDeque, structures: IndexMap<(Atom, usize), VecDeque, FxBuildHasher>, } @@ -1156,7 +1174,7 @@ pub(crate) trait Indexer { fn constants( &mut self, - ) -> &mut IndexMap, FxBuildHasher>; + ) -> &mut IndexMap, FxBuildHasher>; fn lists(&mut self) -> &mut VecDeque; fn structures( &mut self, @@ -1204,7 +1222,7 @@ impl Indexer for StaticCodeIndices { #[inline] fn constants( &mut self, - ) -> &mut IndexMap, FxBuildHasher> { + ) -> &mut IndexMap, FxBuildHasher> { &mut self.constants } @@ -1328,7 +1346,7 @@ impl Indexer for DynamicCodeIndices { } #[inline] - fn constants(&mut self) -> &mut IndexMap, FxBuildHasher> { + fn constants(&mut self) -> &mut IndexMap, FxBuildHasher> { &mut self.constants } @@ -1449,11 +1467,10 @@ impl CodeOffsets { fn index_constant( &mut self, - atom_tbl: &AtomTable, - constant: Literal, + constant: HeapCellValue, index: usize, - ) -> Vec { - let overlapping_constants = constant_key_alternatives(constant, atom_tbl); + ) -> Vec { + let overlapping_constants = constant_key_alternatives(constant); let code = self.indices.constants().entry(constant).or_default(); let is_initial_index = code.is_empty(); @@ -1491,11 +1508,10 @@ impl CodeOffsets { pub(crate) fn index_term( &mut self, - heap: &[HeapCellValue], + heap: &Heap, optimal_arg: HeapCellValue, index: usize, clause_index_info: &mut ClauseIndexInfo, - atom_tbl: &AtomTable, ) { read_heap_cell!(optimal_arg, (HeapCellValueTag::Str, s) => { @@ -1514,36 +1530,32 @@ impl CodeOffsets { (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); - let overlapping_constants = self.index_constant(atom_tbl, Literal::Atom(name), index); + let overlapping_constants = self.index_constant(atom_as_cell!(name), index); clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( self.optimal_index, 0, - Literal::Atom(name), + atom_as_cell!(name), overlapping_constants, ); } (HeapCellValueTag::Lis - | HeapCellValueTag::CStr + // | HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); self.index_list(index); } - _ => { - match Literal::try_from(optimal_arg) { - Ok(lit) => { - let overlapping_constants = self.index_constant(atom_tbl, lit, index); + _ if optimal_arg.is_constant() => { + let overlapping_constants = self.index_constant(optimal_arg, index); - clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( - self.optimal_index, - 0, - lit, - overlapping_constants, - ); - } - _ => {} - } + clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( + self.optimal_index, + 0, + optimal_arg, + overlapping_constants, + ); } + _ => {} ); } diff --git a/src/iterators.rs b/src/iterators.rs index c139f006..b641c756 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -14,9 +14,7 @@ use std::iter::*; use std::ops::Deref; use std::vec::Vec; -pub(crate) trait TermIterator: - Deref + Iterator -{ +pub(crate) trait TermIterator: Deref + Iterator { fn focus(&self) -> IterStackLoc; fn level(&mut self) -> Level; } @@ -30,7 +28,7 @@ pub(crate) struct TargetIterator { } fn record_path( - heap: &[HeapCellValue], + heap: &impl SizedHeap, root_terms: &mut BitSet, mut root_loc: usize, ) -> usize { @@ -47,9 +45,9 @@ fn record_path( } } (HeapCellValueTag::Lis) => { - root_terms.insert(root_loc); - break; - } + root_terms.insert(root_loc); + break; + } _ => { if cell.is_ref() { root_terms.insert(cell.get_value() as usize); @@ -63,14 +61,14 @@ fn record_path( root_loc } -fn find_root_terms(heap: &[HeapCellValue], root_loc: usize) -> (usize, BitSet) { +fn find_root_terms(heap: &impl SizedHeap, 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) } fn find_shallow_terms( - heap: &[HeapCellValue], + heap: &impl SizedHeap, root_loc: usize, ) -> IndexMap, FxBuildHasher> { let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default()); @@ -101,8 +99,8 @@ fn find_shallow_terms( 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); + let (derefed_root_loc, root_terms) = find_root_terms(iter.deref(), root_loc); + let shallow_terms = find_shallow_terms(iter.deref(), derefed_root_loc); Self { shallow_terms, @@ -184,7 +182,7 @@ impl Iterator for TargetIterator Deref for TargetIterator { - type Target = [HeapCellValue]; + type Target = Heap; fn deref(&self) -> &Self::Target { self.iter.deref() @@ -205,7 +203,6 @@ pub(crate) fn fact_iterator<'a, const SKIP_ROOT: bool>( stack: &'a mut Stack, root_loc: usize, ) -> FactIterator<'a, SKIP_ROOT> { - // let cell = heap[root_loc]; TargetIterator::new(stackful_preorder_iter(heap, stack, root_loc), root_loc, 0) } @@ -217,7 +214,6 @@ pub(crate) fn query_iterator<'a, const SKIP_ROOT: bool>( stack: &'a mut Stack, root_loc: usize, ) -> QueryIterator<'a, SKIP_ROOT> { - // let cell = heap[root_loc]; TargetIterator::new(stackful_post_order_iter(heap, stack, root_loc), root_loc, 1) } diff --git a/src/lib.rs b/src/lib.rs index fcb65ff0..ffd532f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![recursion_limit = "4112"] #![deny(missing_docs)] + #[macro_use] extern crate static_assertions; @@ -13,6 +14,8 @@ pub(crate) mod atom_table; pub(crate) mod arena; #[macro_use] pub(crate) mod parser; +#[macro_use] +pub(crate) mod functor_macro; mod allocator; mod arithmetic; pub(crate) mod codegen; diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index e7aebf3f..bc78b711 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -125,7 +125,7 @@ call(_, _, _, _, _, _, _, _, _). % % The flags that Scryer Prolog support are: % -% * `max_arity`: The max arity a predicate can have in Prolog. On Scryer is set to 1023. Read only. +% * `max_arity`: The max arity a predicate can have in Prolog. On Scryer is set to 255. Read only. % * `bounded`: `true` if integer arithmethic is bounded between some min/max values. On Scryer is always set % to `false` since it supports unbounded integer arithmethic. Read only. % * `integer_rounding_function`: Describes the rounding donde by `//` and `rem` functions. On Scryer is @@ -145,8 +145,8 @@ call(_, _, _, _, _, _, _, _, _). % `fail` (the call silently fails) and `warn` (the call fails and a warning about the undefined predicate is printed). % * `answer_write_options`: Additional write options used by the top level for writing answers. % -current_prolog_flag(Flag, Value) :- Flag == max_arity, !, Value = 1023. -current_prolog_flag(max_arity, 1023). +current_prolog_flag(Flag, Value) :- Flag == max_arity, !, Value = 255. +current_prolog_flag(max_arity, 255). current_prolog_flag(Flag, Value) :- Flag == bounded, !, Value = false. current_prolog_flag(bounded, false). current_prolog_flag(Flag, Value) :- Flag == integer_rounding_function, !, Value == toward_zero. diff --git a/src/loader.pl b/src/loader.pl index 26b6afc8..f2d77009 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -205,7 +205,6 @@ load_loop(Stream, Evacuable) :- read_term(Stream, Term, [singletons(Singletons)]) ; Term = end_of_file ), - % write('Term: '), writeq(Term), nl, ( Term == end_of_file -> close(Stream), '$conclude_load'(Evacuable) @@ -220,7 +219,6 @@ load_loop(Stream, Evacuable) :- compile_term(Term, Evacuable) :- expand_terms_and_goals(Term, Terms), - % write('Terms: '), writeq(Terms),nl, !, ( var(Terms) -> instantiation_error(load/1) @@ -301,7 +299,7 @@ expand_term_goals(Terms0, Terms) :- ( atom(Module) -> prolog_load_context(module, Target), module_expanded_head_variables(Head2, HeadVars), - catch(expand_goal(Body0, Target, Body1, HeadVars, []), + catch('$call'(loader:expand_goal(Body0, Target, Body1, HeadVars, [])), error(type_error(callable, Pred), _), ( loader:print_goal_expansion_warning(Pred), builtins:(Body1 = Body0) @@ -311,7 +309,7 @@ expand_term_goals(Terms0, Terms) :- ) ; module_expanded_head_variables(Head1, HeadVars), prolog_load_context(module, Target), - catch(expand_goal(Body0, Target, Body1, HeadVars, []), + catch('$call'(loader:expand_goal(Body0, Target, Body1, HeadVars, [])), error(type_error(callable, Pred), _), ( loader:print_goal_expansion_warning(Pred), builtins:(Body1 = Body0) diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 496007bd..a779411d 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -48,7 +48,7 @@ macro_rules! drop_iter_on_err { }; } -fn zero_divisor_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> MachineStubGen { +fn zero_divisor_eval_error(stub_gen: impl Fn() -> MachineStub + 'static) -> MachineStubGen { Box::new(move |machine_st| { let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor); let stub = stub_gen(); @@ -57,7 +57,7 @@ fn zero_divisor_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> Mach }) } -fn undefined_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> MachineStubGen { +fn undefined_eval_error(stub_gen: impl Fn() -> MachineStub + 'static) -> MachineStubGen { Box::new(move |machine_st| { let eval_error = machine_st.evaluation_error(EvalError::Undefined); let stub = stub_gen(); @@ -69,7 +69,7 @@ fn undefined_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> Machine fn numerical_type_error( valid_type: ValidType, n: Number, - stub_gen: impl Fn() -> FunctorStub + 'static, + stub_gen: impl Fn() -> MachineStub + 'static, ) -> MachineStubGen { Box::new(move |machine_st| { let type_error = machine_st.type_error(valid_type, n); @@ -528,7 +528,7 @@ pub(crate) fn min(n1: Number, n2: Number) -> Result { pub fn rational_from_number( n: Number, - stub_gen: impl Fn() -> FunctorStub + 'static, + stub_gen: impl Fn() -> MachineStub + 'static, arena: &mut Arena, ) -> Result, MachineStubGen> { match n { @@ -1140,7 +1140,7 @@ impl MachineState { pub fn get_rational( &mut self, at: &ArithmeticTerm, - caller: impl Fn() -> FunctorStub + 'static, + caller: impl Fn() -> MachineStub + 'static, ) -> Result, MachineStub> { let n = self.get_number(at)?; @@ -1154,6 +1154,8 @@ impl MachineState { &mut self, value: HeapCellValue, ) -> Result { + debug_assert!(value.is_ref()); + let stub_gen = || functor_stub(atom!("is"), 2); let root_loc = if value.is_ref() && !value.is_stack_var() { @@ -1178,7 +1180,7 @@ impl MachineState { (HeapCellValueTag::Str, s) => { cell_as_atom_cell!(self.heap[s]).get_name_and_arity() } - (HeapCellValueTag::Lis | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset | + (HeapCellValueTag::Lis | // HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset | HeapCellValueTag::PStrLoc) => { (atom!("."), 2) } @@ -1458,7 +1460,7 @@ mod tests { parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap(); assert_eq!( - wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)), + wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)), Ok(Number::Fixnum(Fixnum::build_with(8))), ); @@ -1468,7 +1470,7 @@ mod tests { parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap(); assert_eq!( - wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)), + wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)), Ok(Number::Fixnum(Fixnum::build_with(19))), ); @@ -1478,7 +1480,7 @@ mod tests { parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap(); assert_eq!( - wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)), + wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)), Ok(Number::Fixnum(Fixnum::build_with(-1))) ); } diff --git a/src/machine/attributed_variables.pl b/src/machine/attributed_variables.pl index c288511b..584abc80 100644 --- a/src/machine/attributed_variables.pl +++ b/src/machine/attributed_variables.pl @@ -38,6 +38,7 @@ verify_attrs([], _, _, []). call_goals([ListOfGoalLists | ListsCubed]) :- + '$debug_hook', call_goals_0(ListOfGoalLists), call_goals(ListsCubed). call_goals([]). diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 794c0e76..6b5ae9b3 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -6,7 +6,6 @@ use crate::types::*; use indexmap::IndexSet; use std::cmp::Ordering; -use std::vec::IntoIter; pub(super) type Bindings = Vec<(usize, HeapCellValue)>; @@ -55,32 +54,36 @@ impl MachineState { self.attr_var_init.bindings.push((h, addr)); } - fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) { + fn populate_var_and_value_lists(&mut self) -> Result<(HeapCellValue, HeapCellValue), usize> { + let size = self.attr_var_init.bindings.len(); + let iter = self .attr_var_init .bindings .iter() .map(|(ref h, _)| attr_var_as_cell!(*h)); - let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter)); + let var_list_addr = sized_iter_to_heap_list(&mut self.heap, size, iter)?; let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v); - let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter)); + let value_list_addr = sized_iter_to_heap_list(&mut self.heap, size, iter)?; - (var_list_addr, value_list_addr) + Ok((var_list_addr, value_list_addr)) } - fn verify_attributes(&mut self) { + fn verify_attributes(&mut self) -> Result<(), usize> { for (h, _) in &self.attr_var_init.bindings { self.heap[*h] = attr_var_as_cell!(*h); } - let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists(); + let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists()?; self[temp_v!(1)] = var_list_addr; self[temp_v!(2)] = value_list_addr; + + Ok(()) } - pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter { + pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> Vec { let mut attr_vars: Vec<_> = if b >= self.attr_var_init.attr_var_queue.len() { vec![] } else { @@ -104,10 +107,10 @@ impl MachineState { }); attr_vars.dedup(); - attr_vars.into_iter() + attr_vars } - pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) { + pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) -> Result<(), usize> { self.allocate(arity + 3); let e = self.e; @@ -121,14 +124,18 @@ impl MachineState { and_frame[arity + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64)); and_frame[arity + 3] = fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64)); - self.verify_attributes(); + self.verify_attributes()?; self.num_of_args = 3; self.b0 = self.b; self.p = p; + + Ok(()) } pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec { + debug_assert!(cell.is_ref()); + let mut seen_set = IndexSet::new(); let mut seen_vars = vec![]; let root_loc = if cell.is_ref() { diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 983f5961..71beaa47 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1232,15 +1232,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { fn compile_standalone_clause( &mut self, - term: FocusedHeap, + term: TermWriteResult, settings: CodeGenSettings, ) -> Result { let mut preprocessor = Preprocessor::new(settings); - let clause = self.try_term_to_tl(term, &mut preprocessor)?; - let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings); + let clause = preprocessor.try_term_to_tl(self, term)?; + let machine_st = LS::machine_st(&mut self.payload); + let mut cg = CodeGenerator::new(settings); - let clause_code = cg.compile_predicate(vec![clause])?; + let clause_code = cg.compile_predicate(&mut machine_st.heap, vec![clause])?; Ok(StandaloneCompileResult { clause_code, @@ -1265,11 +1266,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let mut preprocessor = Preprocessor::new(settings); for term in predicates.predicates.drain(0..) { - clauses.push(self.try_term_to_tl(term, &mut preprocessor)?); + clauses.push(preprocessor.try_term_to_tl(self, term)?); } - let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings); - let mut code = cg.compile_predicate(clauses)?; + let machine_st = LS::machine_st(&mut self.payload); + + let mut cg = CodeGenerator::new(settings); + let mut code = cg.compile_predicate(&mut machine_st.heap, clauses)?; if settings.is_extensible { let mut clause_clause_locs = VecDeque::new(); @@ -1466,7 +1469,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { pub(super) fn incremental_compile_clause( &mut self, key: PredicateKey, - clause: FocusedHeap, + clause: TermWriteResult, compilation_target: CompilationTarget, non_counted_bt: bool, append_or_prepend: AppendOrPrepend, @@ -2005,7 +2008,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { &mut self, key: PredicateKey, compilation_target: CompilationTarget, - clause_clauses: Vec, + clause_clauses: Vec, append_or_prepend: AppendOrPrepend, ) -> Result<(), SessionError> { let clause_clause_compilation_target = match compilation_target { @@ -2099,15 +2102,19 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> { - let key = self + let key = match self .payload .predicates .first() - .and_then(|cl| { - let arity = ClauseInfo::arity(cl); - ClauseInfo::name(cl).map(|name| (name, arity)) - }) - .ok_or(SessionError::NamelessEntry)?; + .map(|term| term.focus) { + Some(focus) => { + clause_predicate_key(self.machine_heap(), focus) + .ok_or(SessionError::NamelessEntry)? + } + None => { + return Err(SessionError::NamelessEntry); + } + }; let listing_src_file_name = self.listing_src_file_name(); @@ -2285,34 +2292,40 @@ impl Machine { ) -> Result<(), SessionError> { let body_cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg])); - let new_header_loc = self.machine_st.heap.len(); + let new_header_loc = self.machine_st.heap.cell_len(); let arity = vars.len(); + let term_loc = self.machine_st.heap.cell_len() + 1 + arity; - self.machine_st.heap.push(atom_as_cell!(atom!(""), arity)); + let mut writer = self.machine_st.heap.reserve(4 + arity) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - for var in vars { - self.machine_st.heap.push(var); - } + writer.write_with(move |section| { + section.push_cell(atom_as_cell!(atom!(""), arity)); - let head_loc = if arity > 0 { - str_loc_as_cell!(new_header_loc) - } else { - heap_loc_as_cell!(new_header_loc) - }; + for var in vars { + section.push_cell(var); + } - let term_loc = self.machine_st.heap.len(); + let head_loc = if arity > 0 { + str_loc_as_cell!(new_header_loc) + } else { + heap_loc_as_cell!(new_header_loc) + }; - self.machine_st.heap.push(atom_as_cell!(atom!(":-"), 2)); - self.machine_st.heap.push(head_loc); - self.machine_st.heap.push(body_cell); + section.push_cell(atom_as_cell!(atom!(":-"), 2)); + section.push_cell(head_loc); + section.push_cell(body_cell); + }); let mut compile = || { - use crate::heap_iter::eager_stackful_preorder_iter; - let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(self, InlineTermStream {}); - let mut term = loader.copy_term_from_heap(str_loc_as_cell!(term_loc)); + let machine_st = InlineLoadState::machine_st(&mut loader.payload); + + let term_loc = str_loc_as_cell!(term_loc); + let term = TermWriteResult::from(&mut machine_st.heap, term_loc) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; let settings = CodeGenSettings { global_clock_tick: None, @@ -2320,12 +2333,6 @@ impl Machine { non_counted_bt: true, }; - let value = term.heap[term.focus]; - - term.inverse_var_locs = inverse_var_locs_from_iter( - eager_stackful_preorder_iter(&mut term.heap, value), - ); - loader.compile_standalone_clause(term, settings) }; diff --git a/src/machine/copier.rs b/src/machine/copier.rs index c02854ff..5bb2fe90 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -1,10 +1,11 @@ use crate::atom_table::*; use crate::machine::get_structure_index; +use crate::machine::heap::*; use crate::machine::stack::*; use crate::types::*; use std::mem; -use std::ops::IndexMut; +use std::ops::{IndexMut, Range}; type Trail = Vec<(Ref, HeapCellValue)>; @@ -17,22 +18,31 @@ pub enum AttrVarPolicy { pub trait CopierTarget: IndexMut { fn store(&self, value: HeapCellValue) -> HeapCellValue; fn deref(&self, value: HeapCellValue) -> HeapCellValue; - fn push(&mut self, value: HeapCellValue); + // fn push_cell(&mut self, value: HeapCellValue) -> Result<(), usize>; fn push_attr_var_queue(&mut self, attr_var_loc: usize); fn stack(&mut self) -> &mut Stack; fn threshold(&self) -> usize; + // returns the tail location of the pstr on success + fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result; + fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize; + fn pstr_at(&self, loc: usize) -> bool; + fn next_non_pstr_cell_index(&self, loc: usize) -> usize; + fn reserve(&mut self, num_cells: usize) -> Result; + fn copy_slice_to_end(&mut self, bounds: Range) -> Result<(), usize>; } pub(crate) fn copy_term( target: T, addr: HeapCellValue, attr_var_policy: AttrVarPolicy, -) { +) -> Result<(), usize> { let mut copy_term_state = CopyTermState::new(target, attr_var_policy); - copy_term_state.copy_term_impl(addr); - copy_term_state.copy_attr_var_lists(); + copy_term_state.copy_term_impl(addr)?; + copy_term_state.copy_attr_var_lists()?; copy_term_state.unwind_trail(); + + Ok(()) } #[derive(Debug)] @@ -67,14 +77,14 @@ impl CopyTermState { self.trail.push((Ref::heap_cell(addr), trail_item)); } - fn copy_list(&mut self, addr: usize) { + fn copy_list(&mut self, addr: usize) -> Result<(), usize> { for offset in 0..2 { read_heap_cell!(self.target[addr + offset], (HeapCellValueTag::Lis, h) => { if h >= self.old_h { *self.value_at_scan() = list_loc_as_cell!(h); self.scan += 1; - return; + return Ok(()); } } _ => { @@ -83,14 +93,10 @@ impl CopyTermState { } let threshold = self.target.threshold(); + self.target.copy_slice_to_end(addr .. addr + 2)?; *self.value_at_scan() = list_loc_as_cell!(threshold); - for i in 0..2 { - let hcv = self.target[addr + i]; - self.target.push(hcv); - } - let cdr = self .target .store(self.target.deref(heap_loc_as_cell!(addr + 1))); @@ -113,80 +119,72 @@ impl CopyTermState { } self.scan += 1; + Ok(()) } - fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) { - read_heap_cell!(self.target[pstr_loc], - (HeapCellValueTag::PStrLoc, h) => { - debug_assert!(h >= self.old_h); + /* + * write a null byte to the first word of a partial string to + * flag that it has been copied followed by the copied + * string's index in the next 7 bytes. write the bytes in big + * endian order so that the null byte is at index 0. + */ + fn write_pstr_index(&mut self, head_cell_idx: usize, threshold: usize) { + let bytes = u64::to_be_bytes(threshold as u64); + debug_assert_eq!(bytes[0], 0); + self.target[head_cell_idx] = HeapCellValue::from_bytes(bytes); + } - *self.value_at_scan() = match scan_tag { - HeapCellValueTag::PStrLoc => { - pstr_loc_as_cell!(h) - } - tag => { - debug_assert_eq!(tag, HeapCellValueTag::PStrOffset); - pstr_offset_as_cell!(h) - } - }; + fn copy_partial_string(&mut self, pstr_loc: usize) -> Result<(), usize> { + let head_cell_idx = self.target.pstr_head_cell_index(pstr_loc); + let head_byte_idx = heap_index!(head_cell_idx); + let pstr_offset = pstr_loc - head_byte_idx; - self.scan += 1; - return; - } - (HeapCellValueTag::Var, h) => { - debug_assert!(h >= self.old_h); - debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); + // if a partial string has been copied previously, we + // track it by writing a null byte to its first word, which is trailed, + // and then the new pstr_loc in the word's remaining 7 bytes. see write_pstr_index + // comment. - *self.value_at_scan() = pstr_offset_as_cell!(h); - self.scan += 1; + if self.target[head_cell_idx].into_bytes()[0] == 0u8 { + let head_bytes = self.target[head_cell_idx].into_bytes(); + let new_pstr_loc = u64::from_be_bytes(head_bytes) as usize; - return; - } - _ => {} - ); + *self.value_at_scan() = pstr_loc_as_cell!(heap_index!(new_pstr_loc) + pstr_offset); + self.scan += 1; + return Ok(()); + } let threshold = self.target.threshold(); + let tail_loc = self.target.copy_pstr_to_threshold(head_byte_idx)?; - let replacement = read_heap_cell!(self.target[pstr_loc], - (HeapCellValueTag::CStr) => { - debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); + *self.value_at_scan() = pstr_loc_as_cell!(heap_index!(threshold) + pstr_offset); - *self.value_at_scan() = pstr_offset_as_cell!(threshold); - self.target.push(self.target[pstr_loc]); + self.trail.push((Ref::heap_cell(head_cell_idx), self.target[head_cell_idx])); + self.write_pstr_index(head_cell_idx, threshold); - heap_loc_as_cell!(threshold) - } - _ => { - *self.value_at_scan() = if scan_tag == HeapCellValueTag::PStrLoc { - pstr_loc_as_cell!(threshold) - } else { - debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); - pstr_offset_as_cell!(threshold) - }; + let tail_cell = self.target[tail_loc]; + let mut writer = self.target.reserve(1)?; - self.target.push(self.target[pstr_loc]); - self.target.push(self.target[pstr_loc + 1]); - - pstr_loc_as_cell!(threshold) - } - ); + writer.write_with(|section| { + section.push_cell(tail_cell); + }); self.scan += 1; - let trail_item = mem::replace(&mut self.target[pstr_loc], replacement); - self.trail.push((Ref::heap_cell(pstr_loc), trail_item)); + Ok(()) } - fn copy_attr_var_lists(&mut self) { + fn copy_attr_var_lists(&mut self) -> Result<(), usize> { while !self.attr_var_list_locs.is_empty() { - let iter = std::mem::take(&mut self.attr_var_list_locs); + let mut list_loc_vec = std::mem::take(&mut self.attr_var_list_locs); - for (threshold, list_loc) in iter { + while let Some((threshold, list_loc)) = list_loc_vec.pop() { self.target[threshold] = list_loc_as_cell!(self.target.threshold()); self.target.push_attr_var_queue(threshold - 1); - self.copy_attr_var_list(list_loc); + self.copy_attr_var_list(list_loc)?; } } + + Ok(()) } /* @@ -194,36 +192,36 @@ impl CopyTermState { * structure which is ensured by this function and not at all by * the vanilla copier. */ - fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) { + fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) -> Result<(), usize> { while let HeapCellValueTag::Lis = list_addr.get_tag() { let threshold = self.target.threshold(); let heap_loc = list_addr.get_value() as usize; let str_loc = self.target[heap_loc].get_value() as usize; + let str_cell = self.target[str_loc]; + let mut writer = self.target.reserve(3).unwrap(); - self.target.push(heap_loc_as_cell!(threshold + 2)); - self.target.push(heap_loc_as_cell!(threshold + 1)); + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(threshold + 2)); + section.push_cell(heap_loc_as_cell!(threshold + 1)); - read_heap_cell!(self.target[str_loc], - (HeapCellValueTag::Atom) => { - self.target.push(self.target[str_loc]); + if str_cell.to_atom().is_some() { + section.push_cell(str_cell); } - (HeapCellValueTag::Str) => { - self.copy_term_impl(self.target[str_loc]); - } - _ => { - unreachable!(); - } - ); + }); + debug_assert_eq!(str_cell.get_tag(), HeapCellValueTag::Str); + self.copy_term_impl(str_cell)?; list_addr = self.target[heap_loc + 1]; if HeapCellValueTag::Lis == list_addr.get_tag() { self.target[threshold + 1] = list_loc_as_cell!(self.target.threshold()); } } + + Ok(()) } - fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) { + fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) -> Result<(), usize> { read_heap_cell!(addr, (HeapCellValueTag::Var, h) => { self.target[frontier] = heap_loc_as_cell!(frontier); @@ -250,8 +248,12 @@ impl CopyTermState { self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h))); if let AttrVarPolicy::DeepCopy = self.attr_var_policy { - self.target.push(attr_var_as_cell!(threshold)); - self.target.push(heap_loc_as_cell!(threshold + 1)); + let mut writer = self.target.reserve(2).unwrap(); + + writer.write_with(|section| { + section.push_cell(attr_var_as_cell!(threshold)); + section.push_cell(heap_loc_as_cell!(threshold + 1)); + }); let old_list_link = self.target[h + 1]; self.trail.push((Ref::heap_cell(h + 1), old_list_link)); @@ -266,9 +268,11 @@ impl CopyTermState { unreachable!() } ); + + Ok(()) } - fn copy_var(&mut self, addr: HeapCellValue) { + fn copy_var(&mut self, addr: HeapCellValue) -> Result<(), usize> { let index = addr.get_value() as usize; let rd = self.target.deref(addr); let ra = self.target.store(rd); @@ -278,7 +282,7 @@ impl CopyTermState { if h >= self.old_h { *self.value_at_scan() = ra; self.scan += 1; - return; + return Ok(()); } } (HeapCellValueTag::Lis, h) => { @@ -292,46 +296,57 @@ impl CopyTermState { ); self.scan += 1; - return; + return Ok(()); } } _ => {} ); if rd == ra { - self.reinstantiate_var(ra, self.scan); + self.reinstantiate_var(ra, self.scan)?; self.scan += 1; } else { *self.value_at_scan() = ra; } + + Ok(()) } - fn copy_structure(&mut self, addr: usize) { + fn copy_structure(&mut self, addr: usize) -> Result<(), usize> { read_heap_cell!(self.target[addr], - (HeapCellValueTag::Atom, (name, arity)) => { + (HeapCellValueTag::Atom, (_name, arity)) => { let threshold = self.target.threshold(); *self.value_at_scan() = str_loc_as_cell!(threshold); + self.target.copy_slice_to_end(addr .. addr + 1 + arity)?; + let trail_item = mem::replace( &mut self.target[addr], str_loc_as_cell!(threshold), ); self.trail.push((Ref::heap_cell(addr), trail_item)); +/* self.target.push(atom_as_cell!(name, arity)); for i in 0..arity { let hcv = self.target[addr + 1 + i]; self.target.push(hcv); } +*/ + if !self.target.pstr_at(addr + 1 + arity) { + let index_cell = self.target[addr + 1 + arity]; - let index_cell = self.target[addr + 1 + arity]; + if get_structure_index(index_cell).is_some() { + // copy the index pointer trailing this + // inlined or expanded goal. + let mut writer = self.target.reserve(1).unwrap(); - if get_structure_index(index_cell).is_some() { - // copy the index pointer trailing this - // inlined or expanded goal. - self.target.push(index_cell); + writer.write_with(|section| { + section.push_cell(index_cell); + }); + } } } (HeapCellValueTag::Str, h) => { @@ -343,37 +358,51 @@ impl CopyTermState { ); self.scan += 1; + Ok(()) } - fn copy_term_impl(&mut self, addr: HeapCellValue) { + fn copy_term_impl(&mut self, addr: HeapCellValue) -> Result<(), usize> { self.scan = self.target.threshold(); - self.target.push(addr); + let mut writer = self.target.reserve(1)?; + + writer.write_with(|section| { + section.push_cell(addr); + }); while self.scan < self.target.threshold() { + if self.target.pstr_at(self.scan) { + self.scan = self.target.next_non_pstr_cell_index(self.scan); + continue; + } + let addr = *self.value_at_scan(); read_heap_cell!(addr, (HeapCellValueTag::Lis, h) => { if h >= self.old_h { self.scan += 1; + continue; } else { - self.copy_list(h); + self.copy_list(h) } } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => { - self.copy_var(addr); + self.copy_var(addr) } (HeapCellValueTag::Str, h) => { - self.copy_structure(h); + self.copy_structure(h) } - (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => { - self.copy_partial_string(addr.get_tag(), pstr_loc); + (HeapCellValueTag::PStrLoc, pstr_loc) => { + self.copy_partial_string(pstr_loc) } _ => { self.scan += 1; + continue; } - ); + )?; } + + Ok(()) } fn unwind_trail(mut self) { @@ -395,19 +424,25 @@ impl CopyTermState { #[cfg(test)] mod tests { use super::*; + use crate::functor_macro::*; use crate::machine::mock_wam::*; #[test] fn copier_tests() { let mut wam = MockWAM::new(); + // clear the heap of resource error data etc + wam.machine_st.heap.clear(); + let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); - wam.machine_st - .heap - .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + let mut functor_writer = Heap::functor_writer( + functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom)]), + ); + + functor_writer(&mut wam.machine_st.heap).unwrap(); assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -415,7 +450,7 @@ mod tests { { let wam = TermCopyingMockWAM { wam: &mut wam }; - copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy); + copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap(); } // check that the original heap state is still intact. @@ -430,69 +465,62 @@ mod tests { wam.machine_st.heap.clear(); - let pstr_var_cell = - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); - let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + let mut writer = wam.machine_st.heap.reserve(4).unwrap(); - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + writer.write_with(|section| { + section.push_pstr("abc "); + section.push_cell(pstr_loc_as_cell!(heap_index!(2))); - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); - let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; - - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); - - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0i64))); + section.push_pstr("def"); + section.push_cell(pstr_loc_as_cell!(0)); + }); { let wam = TermCopyingMockWAM { wam: &mut wam }; - copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy); + copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap(); } - print_heap_terms(wam.machine_st.heap[6..].iter(), 6); - - assert_eq!(wam.machine_st.heap[0], pstr_cell); - assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2)); - assert_eq!(wam.machine_st.heap[2], pstr_second_cell); - assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4)); - assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0)); assert_eq!( - wam.machine_st.heap[5], - fixnum_as_cell!(Fixnum::build_with(0i64)) + wam.machine_st.heap.slice_to_str(0, "abc ".len()), + "abc " ); - - assert_eq!(wam.machine_st.heap[7], pstr_cell); - assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9)); - assert_eq!(wam.machine_st.heap[9], pstr_second_cell); - assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11)); - assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7)); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(2))); assert_eq!( - wam.machine_st.heap[12], - fixnum_as_cell!(Fixnum::build_with(0i64)) + wam.machine_st.heap.slice_to_str(heap_index!(2), "def".len()), + "def" ); + assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(5))); + + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(5), "abc ".len()), + "abc " + ); + assert_eq!(wam.machine_st.heap[6], pstr_loc_as_cell!(heap_index!(7))); + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(7), "def".len()), + "def" + ); + assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(heap_index!(5))); wam.machine_st.heap.clear(); - wam.machine_st.heap.extend(functor!( + let mut functor_writer = Heap::functor_writer(functor!( f_atom, [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(0)) + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(0) ] )); + functor_writer(&mut wam.machine_st.heap).unwrap(); + { let wam = TermCopyingMockWAM { wam: &mut wam }; - copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy); + copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap(); } assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4)); diff --git a/src/machine/cycle_detection.rs b/src/machine/cycle_detection.rs index 6df242ac..99ae40b4 100644 --- a/src/machine/cycle_detection.rs +++ b/src/machine/cycle_detection.rs @@ -1,4 +1,5 @@ use crate::atom_table::*; +use crate::machine::heap::*; use crate::types::*; /* Use the pointer reversal technique of the Deutsch-Schorr-Waite @@ -11,7 +12,7 @@ use crate::types::*; * - Cells are only marked during the backward phase * - Visiting subterms of a visited compound does not immediately shift to the backward phase * - The heads of LIS structures are both marked and forwarded rather - * than just forwarded to distinguish them from tails; + * than just forwarded to distinguish them from tails * continue_forwarding() checks for this before entering the forward * phase * @@ -22,7 +23,7 @@ use crate::types::*; #[derive(Debug)] pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> { - pub(crate) heap: &'a mut [HeapCellValue], + pub(crate) heap: &'a mut Heap, start: usize, current: usize, next: u64, @@ -31,7 +32,7 @@ pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> { } impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { - pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self { + pub(crate) fn new(heap: &'a mut Heap, start: usize) -> Self { heap[start].set_forwarding_bit(true); let next = heap[start].get_value(); @@ -127,7 +128,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { self.current = next; self.next = temp; - if self.next < self.heap.len() as u64 { + if self.next < self.heap.cell_len() as u64 { return Some(HeapCellValue::build_with(tag, next as u64)); } } @@ -205,8 +206,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { } HeapCellValueTag::PStrLoc => { let h = self.next as usize; - let cell = self.heap[h]; - let last_cell_loc = h + 1; + let (_, last_cell_loc) = self.heap.scan_slice_to_str(h); if self.heap[last_cell_loc].get_forwarding_bit() { if self.cycle_detection_active() { @@ -225,39 +225,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { self.heap[last_cell_loc].set_value(self.current as u64); self.current = last_cell_loc; - return Some(cell); - } - HeapCellValueTag::PStrOffset => { - let h = self.next as usize; - let cell = self.heap[h]; - let last_cell_loc = h + 1; - - if self.heap[h].get_tag() == HeapCellValueTag::PStr { - if self.heap[last_cell_loc].get_forwarding_bit() { - if self.cycle_detection_active() { - self.cycle_found = true; - return None; - } else if self.backward() { - return None; - } - - continue; - } - - self.heap[last_cell_loc].set_forwarding_bit(true); - - self.next = self.heap[last_cell_loc].get_value(); - self.heap[last_cell_loc].set_value(self.current as u64); - self.current = last_cell_loc; - } else { - debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr); - - self.next = self.heap[h].get_value(); - self.heap[h].set_value(self.current as u64); - self.current = h; - } - - return Some(cell); + return Some(pstr_loc_as_cell!(h)); } tag @ HeapCellValueTag::Atom => { let cell = HeapCellValue::build_with(tag, self.next); @@ -269,11 +237,6 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { return None; } } - HeapCellValueTag::PStr => { - if self.backward() { - return None; - } - } _ => { return Some(self.backward_and_return()); } diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index d7f35155..a7b2a128 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -3,6 +3,7 @@ use crate::forms::*; use crate::instructions::*; use crate::iterators::fact_iterator; use crate::machine::Stack; +use crate::machine::heap::*; use crate::machine::loader::*; use crate::machine::machine_errors::CompilationError; use crate::machine::preprocessor::*; @@ -320,13 +321,12 @@ impl VariableClassifier { } } - pub fn classify_fact( + pub fn classify_fact<'a, LS: LoadState<'a>>( mut self, - term: &mut FocusedHeap, + loader: &mut Loader<'a, LS>, + term: &TermWriteResult, ) -> Result { - let focus = term.focus; - self.classify_head_variables(term, focus)?; - + self.classify_head_variables(loader, &term, term.focus)?; Ok(self.branch_map.separate_and_classify_variables( self.var_num, self.global_cut_var_num, @@ -337,12 +337,14 @@ impl VariableClassifier { pub fn classify_rule<'a, LS: LoadState<'a>>( mut self, loader: &mut Loader<'a, LS>, - term: &mut FocusedHeap, + term: &TermWriteResult, ) -> Result { - let head_loc = term.nth_arg(term.focus, 1).unwrap(); - let body_loc = term.nth_arg(term.focus, 2).unwrap(); + let heap = &mut LS::machine_st(&mut loader.payload).heap; - self.classify_head_variables(term, head_loc)?; + let head_loc = term_nth_arg(heap, term.focus, 1).unwrap(); + let body_loc = term_nth_arg(heap, term.focus, 2).unwrap(); + + self.classify_head_variables(loader, &term, head_loc)?; self.root_set.insert(self.current_branch_num.clone()); let mut query_terms = self.classify_body_variables(loader, term, body_loc)?; @@ -385,8 +387,8 @@ impl VariableClassifier { &mut self, arg_c: usize, arity: usize, - term: &mut FocusedHeap, - term_loc: usize, + term: &mut FocusedHeapRefMut, + inverse_var_locs: &InverseVarLocs, context: GenContext, ) { let classify_info = ClassifyInfo { arg_c, arity }; @@ -394,9 +396,9 @@ impl VariableClassifier { let mut lvl = Level::Shallow; let mut stack = Stack::uninitialized(); let mut iter = fact_iterator::( - &mut term.heap, + term.heap, &mut stack, - term_loc, + term.focus, ); // second arg is true to iterate the root, which may be a variable @@ -407,7 +409,7 @@ impl VariableClassifier { } let var_loc = subterm.get_value() as usize; - let var = to_classified_var(&term.inverse_var_locs, var_loc); + let var = to_classified_var(inverse_var_locs, var_loc); self.probe_body_var( context, @@ -468,27 +470,21 @@ impl VariableClassifier { self.probe_body_var(context, var_info); } - fn classify_head_variables( + fn classify_head_variables<'a, LS: LoadState<'a>>( &mut self, - term: &mut FocusedHeap, + loader: &mut Loader<'a, LS>, + term: &TermWriteResult, head_loc: usize, ) -> Result<(), CompilationError> { - let arity = read_heap_cell!(term.deref_loc(head_loc), - (HeapCellValueTag::Str, s) => { - cell_as_atom_cell!(term.heap[s]).get_arity() - } - (HeapCellValueTag::Atom) => { - return Ok(()); - } - _ => { - return Err(CompilationError::InvalidRuleHead); - } - ); + let heap = &mut LS::machine_st(&mut loader.payload).heap; + let arity = term_predicate_key(heap, head_loc) + .and_then(|(_, arity)| Some(arity)) + .ok_or(CompilationError::InvalidRuleHead)?; let mut classify_info = ClassifyInfo { arg_c: 1, arity }; if arity > 0 { - let (_term_loc, value) = subterm_index(&term.heap, head_loc); + let (_term_loc, value) = subterm_index(heap, head_loc); let str_offset = value.get_value() as usize; debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str); @@ -497,7 +493,7 @@ impl VariableClassifier { let mut lvl = Level::Shallow; let mut stack = Stack::uninitialized(); let mut iter = fact_iterator::( - &mut term.heap, + heap, &mut stack, idx, ); @@ -571,11 +567,11 @@ impl VariableClassifier { fn classify_body_variables<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - terms: &mut FocusedHeap, + terms: &TermWriteResult, term_loc: usize, ) -> Result { let mut state_stack = vec![TraversalState::Term { - subterm: terms.heap[term_loc], + subterm: loader.machine_heap()[term_loc], term_loc, }]; let mut build_stack = ChunkedTermVec::new(); @@ -684,13 +680,21 @@ impl VariableClassifier { for (arg_c, term_loc) in ($term_loc + 1 ..= $term_loc + $key.1).enumerate() { - self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context); + let mut term = FocusedHeapRefMut::from(loader.machine_heap(), term_loc); + + self.probe_body_term( + arg_c + 1, + $key.1, + &mut term, + &terms.inverse_var_locs, + context, + ); } build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( loader, $key, - terms.as_ref_mut($term_loc), + &terms, HeapCellValue::build_with($tag, $term_loc as u64), self.call_policy, ))); @@ -706,9 +710,17 @@ impl VariableClassifier { let context = build_stack.current_gen_context(); for (arg_c, term_loc) in - ($term_loc + 1..$term_loc + $key.1 + 1).enumerate() + ($term_loc + 1 ..= $term_loc + $key.1).enumerate() { - self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context); + let mut term = FocusedHeapRefMut::from(loader.machine_heap(), term_loc); + + self.probe_body_term( + arg_c + 1, + $key.1, + &mut term, + &terms.inverse_var_locs, + context, + ); } build_stack.push_chunk_term(QueryTerm::Clause( @@ -716,7 +728,7 @@ impl VariableClassifier { loader, $key, $module_name, - terms.as_ref_mut($term_loc), + &terms, HeapCellValue::build_with($tag, $term_loc as u64), self.call_policy, ), @@ -725,26 +737,28 @@ impl VariableClassifier { } loop { + let heap = loader.machine_heap(); + read_heap_cell!(subterm, (HeapCellValueTag::Str, subterm_loc) => { - let (name, arity) = cell_as_atom_cell!(terms.heap[subterm_loc]) + let (name, arity) = cell_as_atom_cell!(heap[subterm_loc]) .get_name_and_arity(); match (name, arity) { (atom!("->") | atom!(";") | atom!(","), 3) => { - if blunt_index_ptr(&mut terms.heap, (name, 2), subterm_loc) { - subterm = terms.heap[subterm_loc]; + if blunt_index_ptr(heap, (name, 2), subterm_loc) { + subterm = heap[subterm_loc]; continue; } add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc); } (atom!(","), 2) => { - let head_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap(); - let head = terms.heap[head_loc]; + let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); + let head = heap[head_loc]; - let iter = unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(",")) + let iter = unfold_by_str_locs(heap, tail_loc, atom!(",")) .into_iter() .rev() .chain(std::iter::once((head, head_loc))) @@ -754,15 +768,15 @@ impl VariableClassifier { state_stack.extend(iter); } (atom!(";"), 2) => { - let head_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - let head = terms.heap[head_loc]; + let head = heap[head_loc]; let first_branch_num = self.current_branch_num.split(); let branches: Vec<_> = std::iter::once((head, head_loc)) .chain( - unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(";")) + unfold_by_str_locs(heap, tail_loc, atom!(";")) .into_iter(), ) .collect(); @@ -807,11 +821,11 @@ impl VariableClassifier { build_stack.current_chunk_num += 1; } (atom!("->"), 2) => { - let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let then_term_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + let if_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let then_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - let if_term = terms.heap[if_term_loc]; - let then_term = terms.heap[then_term_loc]; + let if_term = heap[if_term_loc]; + let then_term = heap[then_term_loc]; let prev_b = if matches!( state_stack.last(), @@ -851,8 +865,8 @@ impl VariableClassifier { self.var_num += 1; } (atom!("\\+"), 1) => { - let not_term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let not_term = terms.heap[not_term_loc]; + let not_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let not_term = heap[not_term_loc]; let build_stack_len = build_stack.len(); build_stack.reserve_branch(2); @@ -886,18 +900,19 @@ impl VariableClassifier { self.var_num += 1; } (atom!(":"), 2) => { - let module_name_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let predicate_term_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + let module_name_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let predicate_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); + let mut focused = FocusedHeapRefMut::from(heap, module_name_loc); - let module_name = terms.deref_loc(module_name_loc); - let predicate_term = terms.deref_loc(predicate_term_loc); + let module_name = focused.deref_loc(module_name_loc); + let predicate_term = focused.deref_loc(predicate_term_loc); read_heap_cell!(module_name, (HeapCellValueTag::Atom, (module_name, arity)) => { if arity == 0 { read_heap_cell!(predicate_term, (HeapCellValueTag::Str, s) => { - let key = cell_as_atom_cell!(terms.heap[s]) + let key = cell_as_atom_cell!(heap[s]) .get_name_and_arity(); add_qualified_chunk!( @@ -933,25 +948,40 @@ impl VariableClassifier { let context = build_stack.current_gen_context(); - self.probe_body_term(1, 0, terms, module_name_loc, context); - self.probe_body_term(2, 0, terms, predicate_term_loc, context); + focused.focus = module_name_loc; - let h = terms.heap.len(); + self.probe_body_term( + 1, 0, &mut focused, &terms.inverse_var_locs, context, + ); - terms.heap.push(atom_as_cell!(atom!("call"), 1)); - terms.heap.push(str_loc_as_cell!(subterm_loc)); + focused.focus = predicate_term_loc; + + self.probe_body_term( + 2, 0, &mut focused, &terms.inverse_var_locs, context, + ); + + let h = heap.cell_len(); + + heap.push_cell(atom_as_cell!(atom!("call"), 1)) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + heap.push_cell(str_loc_as_cell!(subterm_loc)) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( loader, (atom!("call"), 1), - terms.as_ref_mut(h), + terms, str_loc_as_cell!(h), self.call_policy, ))); } (atom!("$call_with_inference_counting"), 1) => { - let term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let subterm = terms.deref_loc(term_loc); + let term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let heap = loader.machine_heap(); + let subterm = heap_bound_store( + heap, + heap_bound_deref(heap, heap[term_loc]), + ); state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); state_stack.push(TraversalState::Term { subterm, term_loc }); @@ -973,17 +1003,9 @@ impl VariableClassifier { add_chunk!((name, 0), HeapCellValueTag::Var, term_loc); } } - (HeapCellValueTag::Char, c) => { - if c == '!' { - let context = build_stack.current_gen_context(); - state_stack.push(self.new_cut_state(context)); - } else { - return Err(CompilationError::InadmissibleQueryTerm); - } - } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if h != term_loc { - subterm = terms.heap[h]; + subterm = heap[h]; term_loc = h; continue; } diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 729c6974..ad0ebc7d 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -1,5 +1,6 @@ use crate::arena::*; use crate::atom_table::*; +use crate::functor_macro::*; use crate::instructions::*; use crate::machine::arithmetic_ops::*; use crate::machine::machine_errors::*; @@ -24,7 +25,10 @@ macro_rules! try_or_throw { match $e { Ok(val) => val, Err(msg) => { - $s.throw_exception(msg); + if !msg.is_empty() { + $s.throw_exception(msg); + } + $s.backtrack(); continue; } @@ -32,6 +36,15 @@ macro_rules! try_or_throw { }}; } +macro_rules! backtrack_on_resource_error { + ($machine_st:expr, $val:expr) => { + step_or_resource_error!($machine_st, $val, { + $machine_st.backtrack(); + continue; + }) + }; +} + macro_rules! increment_call_count { ($s:expr) => {{ if !$s.increment_call_count() { @@ -55,6 +68,15 @@ macro_rules! try_or_throw_gen { }}; } +macro_rules! push_cell { + ($machine_st:expr, $cell:expr) => {{ + step_or_resource_error!($machine_st, $machine_st.heap.push_cell($cell), { + $machine_st.backtrack(); + continue; + }) + }}; +} + static INSTRUCTIONS_PER_INTERRUPT_POLL: usize = 256; impl MachineState { @@ -113,12 +135,15 @@ impl MachineState { } pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { - let old_h = self.heap.len(); + let old_h = self.heap.cell_len(); let a1 = self.registers[1]; let a2 = self.registers[2]; - copy_term(CopyTerm::new(self), a1, attr_var_policy); + step_or_resource_error!( + self, + copy_term(CopyTerm::new(self), a1, attr_var_policy) + ); unify_fn!(*self, heap_loc_as_cell!(old_h), a2); } @@ -135,10 +160,16 @@ impl MachineState { list.dedup_by(|v1, v2| compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal)); - let heap_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, list.into_iter())); + let heap_addr = resource_error_call_result!( + self, + sized_iter_to_heap_list( + &mut self.heap, + list.len(), + list.into_iter(), + ) + ); let target_addr = self.registers[2]; - unify_fn!(*self, target_addr, heap_addr); Ok(()) } @@ -160,8 +191,14 @@ impl MachineState { compare_term_test!(self, a1.0, a2.0, var_comparison).unwrap_or(Ordering::Less) }); - let key_pairs = key_pairs.into_iter().map(|kp| kp.1); - let heap_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, key_pairs)); + let heap_addr = resource_error_call_result!( + self, + sized_iter_to_heap_list( + &mut self.heap, + key_pairs.len(), + key_pairs.into_iter().map(|kp| kp.1), + ) + ); let target_addr = self.registers[2]; @@ -201,13 +238,13 @@ impl MachineState { v } (HeapCellValueTag::PStrLoc | - HeapCellValueTag::Lis | - HeapCellValueTag::CStr) => { + HeapCellValueTag::Lis) => { + // HeapCellValueTag::CStr) => { l } (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint | - HeapCellValueTag::Char | + // HeapCellValueTag::Char | HeapCellValueTag::F64) => { c } @@ -242,6 +279,7 @@ impl MachineState { ) } + /* #[inline(always)] pub(crate) fn constant_to_literal(&self, addr: HeapCellValue) -> Literal { read_heap_cell!(addr, @@ -288,6 +326,7 @@ impl MachineState { } ) } + */ #[inline(always)] pub(crate) fn select_switch_on_structure_index( @@ -464,9 +503,9 @@ impl Machine { } } IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => { - let lit = self.machine_st.constant_to_literal(addr); + // let lit = self.machine_st.constant_to_literal(addr); - let offset = match hm.get(&lit) { + let offset = match hm.get(&addr) { Some(offset) => *offset, _ => IndexingCodePtr::Fail, }; @@ -1245,22 +1284,32 @@ impl Machine { self.machine_st.allocate(num_cells); } &Instruction::DefaultCallAcyclicTerm => { - let addr = self.machine_st.registers[1]; + let addr = self.deref_register(1); - if self.machine_st.is_cyclic_term(addr) { - self.machine_st.backtrack(); - } else { - self.machine_st.p += 1; + if addr.is_ref() { + self.machine_st.heap[0] = addr; + + if self.machine_st.is_cyclic_term(0) { + self.machine_st.backtrack(); + continue; + } } + + self.machine_st.p += 1; } &Instruction::DefaultExecuteAcyclicTerm => { - let addr = self.machine_st.registers[1]; + let addr = self.deref_register(1); - if self.machine_st.is_cyclic_term(addr) { - self.machine_st.backtrack(); - } else { - self.machine_st.p = self.machine_st.cp; + if addr.is_ref() { + self.machine_st.heap[0] = addr; + + if self.machine_st.is_cyclic_term(0) { + self.machine_st.backtrack(); + continue; + } } + + self.machine_st.p = self.machine_st.cp; } &Instruction::DefaultCallArg => { try_or_throw!(self.machine_st, self.machine_st.try_arg()); @@ -1497,24 +1546,34 @@ impl Machine { step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallAcyclicTerm => { - let addr = self.machine_st.registers[1]; + let addr = self.deref_register(1); - if self.machine_st.is_cyclic_term(addr) { - self.machine_st.backtrack(); - } else { - increment_call_count!(self.machine_st); - self.machine_st.p += 1; + if addr.is_ref() { + self.machine_st.heap[0] = addr; + + if self.machine_st.is_cyclic_term(0) { + self.machine_st.backtrack(); + continue; + } } + + increment_call_count!(self.machine_st); + self.machine_st.p += 1; } &Instruction::ExecuteAcyclicTerm => { - let addr = self.machine_st.registers[1]; + let addr = self.deref_register(1); - if self.machine_st.is_cyclic_term(addr) { - self.machine_st.backtrack(); - } else { - increment_call_count!(self.machine_st); - self.machine_st.p = self.machine_st.cp; + if addr.is_ref() { + self.machine_st.heap[0] = addr; + + if self.machine_st.is_cyclic_term(0) { + self.machine_st.backtrack(); + continue; + } } + + increment_call_count!(self.machine_st); + self.machine_st.p = self.machine_st.cp; } &Instruction::CallArg => { try_or_throw!(self.machine_st, self.machine_st.try_arg()); @@ -2282,9 +2341,6 @@ impl Machine { self.machine_st.backtrack(); } } - (HeapCellValueTag::Char) => { - self.machine_st.p += 1; - } _ => { self.machine_st.backtrack(); } @@ -2313,9 +2369,6 @@ impl Machine { self.machine_st.backtrack(); } } - (HeapCellValueTag::Char) => { - self.machine_st.p = self.machine_st.cp; - } _ => { self.machine_st.backtrack(); } @@ -2327,7 +2380,7 @@ impl Machine { .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, - (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + (HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | HeapCellValueTag::Cons) => { self.machine_st.p += 1; } @@ -2359,7 +2412,7 @@ impl Machine { .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, - (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + (HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | HeapCellValueTag::Cons) => { self.machine_st.p = self.machine_st.cp; } @@ -2392,8 +2445,8 @@ impl Machine { read_heap_cell!(d, (HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | - HeapCellValueTag::CStr) => { + HeapCellValueTag::PStrLoc) => { + // HeapCellValueTag::CStr) => { self.machine_st.p += 1; } (HeapCellValueTag::Str, s) => { @@ -2425,8 +2478,8 @@ impl Machine { read_heap_cell!(d, (HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | - HeapCellValueTag::CStr) => { + HeapCellValueTag::PStrLoc) => { + // HeapCellValueTag::CStr) => { self.machine_st.p = self.machine_st.cp; } (HeapCellValueTag::Str, s) => { @@ -2664,8 +2717,6 @@ impl Machine { &Instruction::CallNamed(arity, name, ref idx) => { let idx = idx.get(); - // println!("calling {}/{}", name.as_str(), arity); - try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); if self.machine_st.fail { @@ -2677,8 +2728,6 @@ impl Machine { &Instruction::ExecuteNamed(arity, name, ref idx) => { let idx = idx.get(); - // println!("executing {}/{}", name.as_str(), arity); - try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); if self.machine_st.fail { @@ -2690,8 +2739,6 @@ impl Machine { &Instruction::DefaultCallNamed(arity, name, ref idx) => { let idx = idx.get(); - // println!("calling {}/{}", name.as_str(), arity); - try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); if self.machine_st.fail { @@ -2701,8 +2748,6 @@ impl Machine { &Instruction::DefaultExecuteNamed(arity, name, ref idx) => { let idx = idx.get(); - // println!("executing {}/{}", name.as_str(), arity); - try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); if self.machine_st.fail { @@ -2720,8 +2765,7 @@ impl Machine { self.machine_st.p = self.machine_st.cp; } &Instruction::GetConstant(_, c, reg) => { - let value = self.machine_st.deref(self.machine_st[reg]); - self.machine_st.write_literal_to_var(value, c); + unify!(self.machine_st, self.machine_st[reg], c); step_or_fail!(self, self.machine_st.p += 1); } &Instruction::GetList(_, reg) => { @@ -2730,17 +2774,7 @@ impl Machine { read_heap_cell!(store_v, (HeapCellValueTag::PStrLoc, h) => { - let (h, n) = pstr_loc_and_offset(&self.machine_st.heap, h); - - self.machine_st.s = HeapPtr::PStrChar(h, n.get_num() as usize); - self.machine_st.s_offset = 0; - self.machine_st.mode = MachineMode::Read; - } - (HeapCellValueTag::CStr) => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(store_v); - - self.machine_st.s = HeapPtr::PStrChar(h, 0); + self.machine_st.s = HeapPtr::PStr(h); self.machine_st.s_offset = 0; self.machine_st.mode = MachineMode::Read; } @@ -2763,9 +2797,9 @@ impl Machine { self.machine_st.mode = MachineMode::Read; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(list_loc_as_cell!(h+1)); + push_cell!(self.machine_st, list_loc_as_cell!(h+1)); self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); self.machine_st.mode = MachineMode::Write; @@ -2778,29 +2812,61 @@ impl Machine { self.machine_st.p += 1; } - &Instruction::GetPartialString(_, string, reg, has_tail) => { + &Instruction::GetPartialString(_, ref string, reg) => { + use crate::machine::partial_string::{HeapPStrIter, PStrCmpResult}; + let deref_v = self.machine_st.deref(self.machine_st[reg]); let store_v = self.machine_st.store(deref_v); read_heap_cell!(store_v, (HeapCellValueTag::Str | HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | - HeapCellValueTag::CStr) => { - self.machine_st.match_partial_string(store_v, string, has_tail); + HeapCellValueTag::PStrLoc) => { + debug_assert!(store_v.is_ref()); + + self.machine_st.heap[0] = store_v; + let heap_pstr_iter = HeapPStrIter::new(&self.machine_st.heap, 0); + + match heap_pstr_iter.compare_pstr_to_string(string) { + Some(PStrCmpResult::CompletePStrMatch { chars_matched, pstr_loc }) => { + self.machine_st.s_offset = chars_matched; + self.machine_st.s = HeapPtr::PStr(pstr_loc); + self.machine_st.mode = MachineMode::Read; + } + Some(PStrCmpResult::PartialPStrMatch { string, var_loc }) => { + let cell = backtrack_on_resource_error!( + self.machine_st, + self.machine_st.allocate_pstr(string) + ); + + self.machine_st.mode = MachineMode::Write; + unify!(self.machine_st, cell, heap_loc_as_cell!(var_loc)); + } + Some(PStrCmpResult::ListMatch { list_loc }) => { + self.machine_st.s_offset = 0; + self.machine_st.s = HeapPtr::HeapCell(list_loc); + self.machine_st.mode = MachineMode::Read; + } + None => { + self.machine_st.backtrack(); + continue; + } + } } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { - let target_cell = self.machine_st.push_str_to_heap( - &string.as_str(), - has_tail, + let target_cell = backtrack_on_resource_error!( + self.machine_st, + self.machine_st.allocate_pstr(string) ); self.machine_st.bind( store_v.as_var().unwrap(), target_cell, ); + + self.machine_st.mode = MachineMode::Write; } _ => { self.machine_st.backtrack(); @@ -2833,10 +2899,10 @@ impl Machine { ); } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(str_loc_as_cell!(h+1)); - self.machine_st.heap.push(atom_as_cell!(name, arity)); + push_cell!(self.machine_st, str_loc_as_cell!(h+1)); + push_cell!(self.machine_st, atom_as_cell!(name, arity)); self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); self.machine_st.mode = MachineMode::Write; @@ -2870,8 +2936,7 @@ impl Machine { match self.machine_st.mode { MachineMode::Read => { let addr = self.machine_st.read_s(); - - self.machine_st.write_literal_to_var(addr, v); + unify!(&mut self.machine_st, addr, v); if self.machine_st.fail { self.machine_st.backtrack(); @@ -2881,7 +2946,7 @@ impl Machine { } } MachineMode::Write => { - self.machine_st.heap.push(v); + push_cell!(self.machine_st, v); } } @@ -2906,17 +2971,17 @@ impl Machine { let value = self .machine_st .store(self.machine_st.deref(self.machine_st[reg])); - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); read_heap_cell!(value, (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => { let value = self.machine_st.heap[hc]; - self.machine_st.heap.push(value); + push_cell!(self.machine_st, value); self.machine_st.s_offset += 1; } _ => { - self.machine_st.heap.push(heap_loc_as_cell!(h)); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); (self.machine_st.bind_fn)( &mut self.machine_st, Ref::heap_cell(h), @@ -2932,13 +2997,14 @@ impl Machine { &Instruction::UnifyVariable(reg) => { match self.machine_st.mode { MachineMode::Read => { - self.machine_st[reg] = self.machine_st.read_s(); + let value = self.machine_st.read_s(); + self.machine_st[reg] = value; self.machine_st.s_offset += 1; } MachineMode::Write => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); self.machine_st[reg] = heap_loc_as_cell!(h); } } @@ -2961,8 +3027,8 @@ impl Machine { } } MachineMode::Write => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + let h = self.machine_st.heap.cell_len(); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); let addr = self.machine_st.store(self.machine_st[reg]); (self.machine_st.bind_fn)( @@ -2974,7 +3040,7 @@ impl Machine { // the former code of this match arm was: // let addr = self.machine_st.store(self.machine_st[reg]); - // self.machine_st.heap.push(HeapCellValue::Addr(addr)); + // push_cell!(self.machine_st, HeapCellValue::Addr(addr)); // the old code didn't perform the occurs // check when enabled and so it was changed to @@ -2991,10 +3057,10 @@ impl Machine { self.machine_st.s_offset += n; } MachineMode::Write => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); for i in h..h + n { - self.machine_st.heap.push(heap_loc_as_cell!(i)); + push_cell!(self.machine_st, heap_loc_as_cell!(i)); } } } @@ -3126,38 +3192,26 @@ impl Machine { } } } - &Instruction::PutConstant(_, c, reg) => { - self.machine_st[reg] = c; + &Instruction::PutConstant(_, cell, reg) => { + self.machine_st[reg] = cell; self.machine_st.p += 1; } &Instruction::PutList(_, reg) => { - self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.len()); + self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.cell_len()); self.machine_st.p += 1; } - &Instruction::PutPartialString(_, string, reg, has_tail) => { - let pstr_addr = if has_tail { - if string != atom!("") { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(string_as_pstr_cell!(string)); + &Instruction::PutPartialString(_, ref string, reg) => { + self.machine_st[reg] = backtrack_on_resource_error!( + self.machine_st, + self.machine_st.allocate_pstr(&string) + ); - // the tail will be pushed by the next - // instruction, so don't push one here. - - pstr_loc_as_cell!(h) - } else { - empty_list_as_cell!() - } - } else { - string_as_cstr_cell!(string) - }; - - self.machine_st[reg] = pstr_addr; self.machine_st.p += 1; } &Instruction::PutStructure(name, arity, reg) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(atom_as_cell!(name, arity)); + push_cell!(self.machine_st, atom_as_cell!(name, arity)); self.machine_st[reg] = str_loc_as_cell!(h); self.machine_st.p += 1; @@ -3171,9 +3225,9 @@ impl Machine { if addr.is_protected(self.machine_st.e) { self.machine_st.registers[arg] = addr; } else { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); (self.machine_st.bind_fn)( &mut self.machine_st, Ref::heap_cell(h), @@ -3197,8 +3251,8 @@ impl Machine { self.machine_st.registers[arg] = self.machine_st[norm]; } RegType::Temp(_) => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + let h = self.machine_st.heap.cell_len(); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); self.machine_st[norm] = heap_loc_as_cell!(h); self.machine_st.registers[arg] = heap_loc_as_cell!(h); @@ -3208,7 +3262,7 @@ impl Machine { self.machine_st.p += 1; } &Instruction::SetConstant(c) => { - self.machine_st.heap.push(c); + push_cell!(self.machine_st, c); self.machine_st.p += 1; } &Instruction::SetLocalValue(reg) => { @@ -3216,37 +3270,37 @@ impl Machine { let stored_v = self.machine_st.store(addr); if stored_v.is_stack_var() { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + let h = self.machine_st.heap.cell_len(); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); (self.machine_st.bind_fn)( &mut self.machine_st, Ref::heap_cell(h), stored_v, ); } else { - self.machine_st.heap.push(stored_v); + push_cell!(self.machine_st, stored_v); } self.machine_st.p += 1; } &Instruction::SetVariable(reg) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); self.machine_st[reg] = heap_loc_as_cell!(h); self.machine_st.p += 1; } &Instruction::SetValue(reg) => { let heap_val = self.machine_st.store(self.machine_st[reg]); - self.machine_st.heap.push(heap_val); + push_cell!(self.machine_st, heap_val); self.machine_st.p += 1; } &Instruction::SetVoid(n) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); for i in h..h + n { - self.machine_st.heap.push(heap_loc_as_cell!(i)); + push_cell!(self.machine_st, heap_loc_as_cell!(i)); } self.machine_st.p += 1; @@ -3363,11 +3417,11 @@ impl Machine { } &Instruction::CallCopyToLiftedHeap => { self.copy_to_lifted_heap(); - self.machine_st.p += 1; + step_or_fail!(self, self.machine_st.p += 1); } &Instruction::ExecuteCopyToLiftedHeap => { self.copy_to_lifted_heap(); - self.machine_st.p = self.machine_st.cp; + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCreatePartialString => { self.create_partial_string(); @@ -3519,15 +3573,6 @@ impl Machine { self.dynamic_module_resolution(arity - 2) ); - /* - println!( - "(slow) calling {}:{}/{}", - module_name.as_str(), - key.0.as_str(), - key.1, - ); - */ - try_or_throw!(self.machine_st, self.call_clause(module_name, key)); if self.machine_st.fail { @@ -3540,15 +3585,6 @@ impl Machine { self.dynamic_module_resolution(arity - 2) ); - /* - println!( - "(slow) executing {}:{}/{}", - module_name.as_str(), - key.0.as_str(), - key.1, - ); - */ - try_or_throw!(self.machine_st, self.execute_clause(module_name, key)); if self.machine_st.fail { @@ -4291,11 +4327,11 @@ impl Machine { } &Instruction::CallSetBall => { self.set_ball(); - self.machine_st.p += 1; + step_or_fail!(self, self.machine_st.p += 1); } &Instruction::ExecuteSetBall => { self.set_ball(); - self.machine_st.p = self.machine_st.cp; + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPushBallStack => { self.push_ball_stack(); @@ -4630,19 +4666,19 @@ impl Machine { step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadHTML => { - self.load_html(); + backtrack_on_resource_error!(self.machine_st, self.load_html()); step_or_fail!(self, self.machine_st.p += 1); } &Instruction::ExecuteLoadHTML => { - self.load_html(); + backtrack_on_resource_error!(self.machine_st, self.load_html()); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadXML => { - self.load_xml(); + backtrack_on_resource_error!(self.machine_st, self.load_xml()); step_or_fail!(self, self.machine_st.p += 1); } &Instruction::ExecuteLoadXML => { - self.load_xml(); + backtrack_on_resource_error!(self.machine_st, self.load_xml()); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetEnv => { @@ -5119,13 +5155,18 @@ impl Machine { let r = self.machine_st.registers[2]; let r = self.machine_st.store(self.machine_st.deref(r)); - let h = self.machine_st.heap.len(); - self.machine_st - .heap - .extend(functor!(atom!("-"), [fixnum(n), fixnum(p)])); + let mut writer = Heap::functor_writer( + functor!(atom!("-"), [fixnum(n), fixnum(p)]), + ); + + let str_cell = backtrack_on_resource_error!( + &mut self.machine_st, + writer(&mut self.machine_st.heap) + ); let r = r.as_var().unwrap(); - self.machine_st.bind(r, str_loc_as_cell!(h)); + + self.machine_st.bind(r, str_cell); step_or_fail!(self, self.machine_st.p += 1); } @@ -5137,13 +5178,18 @@ impl Machine { let r = self.machine_st.registers[2]; let r = self.machine_st.store(self.machine_st.deref(r)); - let h = self.machine_st.heap.len(); - self.machine_st - .heap - .extend(functor!(atom!("-"), [fixnum(n), fixnum(p)])); + let mut writer = Heap::functor_writer( + functor!(atom!("-"), [fixnum(n), fixnum(p)]), + ); + + let str_cell = backtrack_on_resource_error!( + &mut self.machine_st, + writer(&mut self.machine_st.heap) + ); let r = r.as_var().unwrap(); - self.machine_st.bind(r, str_loc_as_cell!(h)); + + self.machine_st.bind(r, str_cell); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } diff --git a/src/machine/gc.rs b/src/machine/gc.rs index 456f075f..f0f480f3 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -1,15 +1,22 @@ -#![allow(dead_code)] - +#[cfg(test)] use crate::atom_table::*; +#[cfg(test)] use crate::machine::heap::*; +#[cfg(test)] use crate::types::*; +#[cfg(test)] +use fxhash::FxBuildHasher; +#[cfg(test)] +use indexmap::IndexMap; + #[cfg(test)] use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc}; #[cfg(test)] use std::ops::Deref; +#[cfg(test)] pub(crate) trait UnmarkPolicy { fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option where @@ -29,8 +36,7 @@ pub(crate) trait UnmarkPolicy { fn record_focus(_iter: &mut StacklessPreOrderHeapIter) where Self: Sized, - { - } + {} } #[cfg(test)] @@ -71,8 +77,10 @@ impl UnmarkPolicy for IteratorUMP { } } +#[cfg(test)] struct MarkerUMP {} +#[cfg(test)] impl UnmarkPolicy for MarkerUMP { #[inline(always)] fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option { @@ -100,18 +108,23 @@ impl UnmarkPolicy for MarkerUMP { } } +#[cfg(test)] +type PStrLocValuesMap = IndexMap; + +#[cfg(test)] #[derive(Debug)] pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> { - pub(crate) heap: &'a mut [HeapCellValue], + pub(crate) heap: &'a mut Heap, start: usize, current: usize, next: u64, iter_state: UMP, + pstr_loc_values: PStrLocValuesMap, } #[cfg(test)] impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> { - type Target = [HeapCellValue]; + type Target = Heap; fn deref(&self) -> &Self::Target { self.heap @@ -126,6 +139,7 @@ impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> { } } +#[cfg(test)] impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> { fn drop(&mut self) { UMP::invert_marker(self); @@ -138,8 +152,9 @@ impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> { } } +#[cfg(test)] impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> { - pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self { + pub(crate) fn new(heap: &'a mut Heap, start: usize) -> Self { heap[start].set_forwarding_bit(true); let next = heap[start].get_value(); @@ -149,13 +164,15 @@ impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> { current: start, next, iter_state: MarkerUMP {}, + pstr_loc_values: PStrLocValuesMap::with_hasher(FxBuildHasher::default()), } } } #[cfg(test)] impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> { - pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self { + #[cfg(test)] + pub(crate) fn new(heap: &'a mut Heap, start: usize) -> Self { heap[start].set_forwarding_bit(true); let next = heap[start].get_value(); @@ -165,10 +182,12 @@ impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> { current: start, next, iter_state: IteratorUMP { mark_phase: true }, + pstr_loc_values: PStrLocValuesMap::with_hasher(FxBuildHasher::default()), } } } +#[cfg(test)] impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { fn backward_and_return(&mut self) -> HeapCellValue { let mut current = self.heap[self.current]; @@ -214,7 +233,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { return Some(cell); } - if self.next < self.heap.len() as u64 && UMP::report_var_link(self) { + if self.next < self.heap.cell_len() as u64 && UMP::report_var_link(self) { let tag = HeapCellValueTag::AttrVar; return Some(HeapCellValue::build_with(tag, next as u64)); } @@ -226,7 +245,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { return Some(cell); } - if self.next < self.heap.len() as u64 && UMP::report_var_link(self) { + if self.next < self.heap.cell_len() as u64 && UMP::report_var_link(self) { let tag = HeapCellValueTag::Var; return Some(HeapCellValue::build_with(tag, next as u64)); } @@ -241,7 +260,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { let arity = cell_as_atom_cell!(self.heap[h]).get_arity(); - for cell in &mut self.heap[h + 1..h + arity + 1] { + for cell in &mut self.heap.splice_mut(h + 1..h + arity + 1) { cell.set_forwarding_bit(true); } @@ -270,48 +289,21 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { } HeapCellValueTag::PStrLoc => { let h = self.next as usize; + let (_, last_cell_loc) = self.heap.scan_slice_to_str(h); - if self.heap[h + 1].get_forwarding_bit() { + self.pstr_loc_values.insert(self.current, h); + + if self.heap[last_cell_loc].get_forwarding_bit() { return Some(self.backward_and_return()); } - let cell = self.heap[h]; - - let last_cell_loc = h + 1; - self.next = self.heap[last_cell_loc].get_value(); self.heap[last_cell_loc].set_value(self.current as u64); self.current = last_cell_loc; self.heap[last_cell_loc].set_forwarding_bit(true); - return Some(cell); - } - HeapCellValueTag::PStrOffset => { - let h = self.next as usize; - let cell = self.heap[h]; - - let last_cell_loc = h + 1; - - if self.heap[last_cell_loc].get_forwarding_bit() { - return Some(self.backward_and_return()); - } - - if self.heap[h].get_tag() == HeapCellValueTag::PStr { - self.heap[last_cell_loc].set_forwarding_bit(true); - - self.next = self.heap[last_cell_loc].get_value(); - self.heap[last_cell_loc].set_value(self.current as u64); - self.current = last_cell_loc; - } else { - debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr); - - self.next = self.heap[h].get_value(); - self.heap[h].set_value(self.current as u64); - self.current = h; - } - - return Some(cell); + return Some(pstr_loc_as_cell!(h)); } tag @ HeapCellValueTag::Atom => { let cell = HeapCellValue::build_with(tag, self.next); @@ -323,7 +315,15 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { return None; } } - HeapCellValueTag::PStr => { + HeapCellValueTag::Cons if self.heap.pstr_at(self.current) => { + let pstr_loc_loc = self.heap[self.current].get_value() as usize; + let pstr_loc_val = self.pstr_loc_values.get(&pstr_loc_loc).unwrap(); + + self.heap[self.current].set_value(self.next); + + self.next = *pstr_loc_val as u64; + self.current = pstr_loc_loc; + if self.backward() { return None; } @@ -366,6 +366,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { } } +#[cfg(test)] impl<'a, UMP: UnmarkPolicy> Iterator for StacklessPreOrderHeapIter<'a, UMP> { type Item = HeapCellValue; @@ -375,157 +376,167 @@ impl<'a, UMP: UnmarkPolicy> Iterator for StacklessPreOrderHeapIter<'a, UMP> { } } -pub fn mark_cells(heap: &mut Heap, start: usize) { - let mut iter = StacklessPreOrderHeapIter::::new(heap, start); - while iter.forward().is_some() {} -} - #[cfg(test)] mod tests { use super::*; + use crate::functor_macro::*; use crate::machine::mock_wam::*; + fn mark_cells(heap: &mut Heap, start: usize) { + let mut iter = StacklessPreOrderHeapIter::::new(heap, start); + while iter.forward().is_some() {} + } + #[test] fn heap_marking_tests() { let mut wam = MockWAM::new(); + // clear the heap of resource error data etc + wam.machine_st.heap.clear(); + let f_atom = atom!("f"); let a_atom = atom!("a"); let b_atom = atom!("b"); - wam.machine_st.heap.push(str_loc_as_cell!(1)); + let mut functor_writer = Heap::functor_writer( + functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom)]), + ); - wam.machine_st - .heap - .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); - mark_cells(&mut wam.machine_st.heap, 0); + wam.machine_st.heap.push_cell(cell).unwrap(); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + mark_cells(&mut wam.machine_st.heap, h); + + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - str_loc_as_cell!(1) + unmark_cell_bits!(wam.machine_st.heap[3]), + str_loc_as_cell!(0) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), + unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 2) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), + unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), + unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom) ); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); + let mut functor_writer = Heap::functor_writer( + functor!( + f_atom, + [ + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(1) + ] + ), + ); - wam.machine_st.heap.extend(functor!( - f_atom, - [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(1)) - ] - )); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); - mark_cells(&mut wam.machine_st.heap, 0); + wam.machine_st.heap.push_cell(cell).unwrap(); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + mark_cells(&mut wam.machine_st.heap, h); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + + assert_eq!( + unmark_cell_bits!(wam.machine_st.heap[5]), + str_loc_as_cell!(0) + ); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), - str_loc_as_cell!(1) - ); - - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(f_atom, 4) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), + unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), + unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), + unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(a_atom) ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - str_loc_as_cell!(1) - ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); // make the structure doubly cyclic. - wam.machine_st.heap[2] = str_loc_as_cell!(1); + wam.machine_st.heap[1] = str_loc_as_cell!(0); - mark_cells(&mut wam.machine_st.heap, 0); + mark_cells(&mut wam.machine_st.heap, h); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); + let mut functor_writer = Heap::functor_writer( + functor!( + f_atom, + [ + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(0) + ] + ), + ); - wam.machine_st.heap.extend(functor!( - f_atom, - [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(1)) - ] - )); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); - mark_cells(&mut wam.machine_st.heap, 0); + wam.machine_st.heap.push_cell(cell).unwrap(); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + mark_cells(&mut wam.machine_st.heap, h); + + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - str_loc_as_cell!(1) + unmark_cell_bits!(wam.machine_st.heap[5]), + str_loc_as_cell!(0) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), + unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 4) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), + unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), + unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), + unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(a_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - str_loc_as_cell!(1) + unmark_cell_bits!(wam.machine_st.heap[4]), + str_loc_as_cell!(0) ); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -534,16 +545,20 @@ mod tests { wam.machine_st.heap.clear(); - // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + // term is: [a, b] + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -566,18 +581,14 @@ mod tests { empty_list_as_cell!() ); - wam.machine_st.heap.pop(); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); // now make the list cyclic. - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -600,7 +611,7 @@ mod tests { heap_loc_as_cell!(0) ); - for cell in &mut wam.machine_st.heap { + for cell in &mut wam.machine_st.heap.splice_mut(..) { cell.set_mark_bit(false); } @@ -609,24 +620,29 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); // term is: [a, ] let stream = Stream::from_static_string("test", &mut wam.machine_st.arena); - let stream_cell = - HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons)); + let stream_cell = HeapCellValue::from( + ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons), + ); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(stream_cell); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(stream_cell); + section.push_cell(empty_list_as_cell!()); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -650,14 +666,18 @@ mod tests { // now a cycle of variables. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(0)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -682,264 +702,282 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - wam.machine_st.heap.push(pstr_loc_as_cell!(1)); + let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap(); - let pstr_var_cell = - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); - let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); - mark_cells(&mut wam.machine_st.heap, 0); + let pstr_cell_loc = wam.machine_st.heap.cell_len(); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(heap_index!(0))).unwrap(); + + mark_cells(&mut wam.machine_st.heap, pstr_cell_loc); + + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - pstr_loc_as_cell!(1) + wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()), + "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[pstr_cell_loc]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - heap_loc_as_cell!(2) + unmark_cell_bits!(wam.machine_st.heap[1]), + heap_loc_as_cell!(1) ); - wam.machine_st.heap.pop(); + wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + wam.machine_st.allocate_pstr("abc ").unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); - wam.machine_st.heap.push(pstr_loc_as_cell!(3)); + mark_cells(&mut wam.machine_st.heap, 2); - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); - let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); - mark_cells(&mut wam.machine_st.heap, 0); + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); - - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) + wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()), + "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) + ); + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " + ); + assert_eq!( + wam.machine_st.heap[4], heap_loc_as_cell!(4) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + // create a cycle offset two characters into the partial string at 0 + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(0) + 2); - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(5)); - wam.machine_st.heap.push(pstr_offset_as_cell!(1)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); - wam.machine_st.heap.push(pstr_loc_as_cell!(5)); + mark_cells(&mut wam.machine_st.heap, 2); - mark_cells(&mut wam.machine_st.heap, 7); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]); + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) + wam.machine_st.heap.slice_to_str(0, "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_loc_as_cell!(5) + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " + ); + assert_eq!( + wam.machine_st.heap[4], + pstr_loc_as_cell!(heap_index!(0) + 2) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + wam.machine_st.heap[4] = heap_loc_as_cell!(2); - wam.machine_st.heap[7] = heap_loc_as_cell!(2); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(2)).unwrap(); - mark_cells(&mut wam.machine_st.heap, 7); + mark_cells(&mut wam.machine_st.heap, 5); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) + wam.machine_st.heap.slice_to_str(0, "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " + ); + assert_eq!( + wam.machine_st.heap[4], + heap_loc_as_cell!(2) + ); + assert_eq!( + wam.machine_st.heap[5], heap_loc_as_cell!(2) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + wam.machine_st.heap[4] = pstr_loc_as_cell!(0); - wam.machine_st.heap[7] = pstr_loc_as_cell!(1); + mark_cells(&mut wam.machine_st.heap, 2); - mark_cells(&mut wam.machine_st.heap, 7); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(.. 5)); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]); + unmark_all_cells(wam.machine_st.heap.splice_mut(.. 5)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) + wam.machine_st.heap.slice_to_str(0, "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_loc_as_cell!(1) - ); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - - wam.machine_st.heap[7] = heap_loc_as_cell!(0); - - mark_cells(&mut wam.machine_st.heap, 7); - - all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]); - - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[4], + pstr_loc_as_cell!(heap_index!(0)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - heap_loc_as_cell!(0) + wam.machine_st.heap[5], + heap_loc_as_cell!(2) ); wam.machine_st.heap.truncate(4); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + let mut writer = wam.machine_st.heap.reserve(2).unwrap(); - wam.machine_st - .heap - .push(atom_as_cell!(atom!("irrelevant stuff"))); - wam.machine_st.heap.push(pstr_offset_as_cell!(1)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("irrelevant stuff"))); + section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 2)); // offset two chars into pstr at 0 + }); - // this is at index 7 - wam.machine_st.heap.push(pstr_loc_as_cell!(5)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap(); - mark_cells(&mut wam.machine_st.heap, 7); + mark_cells(&mut wam.machine_st.heap, 6); - assert!(!wam.machine_st.heap[0].get_mark_bit()); + // indices 0 and 3 are the beginning of one-cell partial + // strings, and they should be marked! despite the HeapCellValue casts + // otherwise not being sensible. + assert!(wam.machine_st.heap[0].get_mark_bit()); assert!(wam.machine_st.heap[1].get_mark_bit()); - assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[2].get_mark_bit()); assert!(wam.machine_st.heap[3].get_mark_bit()); assert!(wam.machine_st.heap[4].get_mark_bit()); assert!(wam.machine_st.heap[5].get_mark_bit()); assert!(wam.machine_st.heap[6].get_mark_bit()); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) + wam.machine_st.heap.slice_to_str(0, "abc ".len()), + "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) + ); + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " + ); + assert_eq!( + wam.machine_st.heap[4], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(0) + 2) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_loc_as_cell!(5) + wam.machine_st.heap[6], + heap_loc_as_cell!(5) ); wam.machine_st.heap.clear(); - wam.machine_st - .heap - .push(atom_as_cell!(atom!("irrelevant stuff"))); - wam.machine_st.heap.push(pstr_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(4)); - wam.machine_st - .heap - .push(atom_as_cell!(atom!("irrelevant stuff"))); - wam.machine_st.heap.push(pstr_second_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(7)); - wam.machine_st - .heap - .push(atom_as_cell!(atom!("irrelevant stuff"))); - wam.machine_st.heap.push(pstr_offset_as_cell!(1)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(pstr_loc_as_cell!(7)); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("irrelevant stuff"))); + section.push_pstr("abc "); + section.push_cell(pstr_loc_as_cell!(heap_index!(4))); + section.push_cell(atom_as_cell!(atom!("irrelevant stuff"))); + section.push_pstr("def"); + section.push_cell(pstr_loc_as_cell!(heap_index!(1) + 2)); + section.push_cell(atom_as_cell!(atom!("irrelevant stuff"))); + section.push_cell(pstr_loc_as_cell!(heap_index!(1) + 2)); + }); - mark_cells(&mut wam.machine_st.heap, 9); + mark_cells(&mut wam.machine_st.heap, 7); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); + assert!(!wam.machine_st.heap[3].get_forwarding_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + assert!(!wam.machine_st.heap[6].get_forwarding_bit()); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + + assert_eq!( + wam.machine_st.heap[0], + atom_as_cell!(atom!("irrelevant stuff")) + ); + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()), + "abc " + ); + assert_eq!( + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(4)) + ); + assert_eq!( + wam.machine_st.heap[3], + atom_as_cell!(atom!("irrelevant stuff")) + ); + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()), + "def" + ); + assert_eq!( + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(1) + 2) + ); + assert_eq!( + wam.machine_st.heap[6], + atom_as_cell!(atom!("irrelevant stuff")) + ); + + wam.machine_st.heap[7] = heap_loc_as_cell!(2); + + mark_cells(&mut wam.machine_st.heap, 7); assert!(!wam.machine_st.heap[0].get_mark_bit()); assert!(wam.machine_st.heap[1].get_mark_bit()); @@ -949,46 +987,49 @@ mod tests { assert!(wam.machine_st.heap[5].get_mark_bit()); assert!(!wam.machine_st.heap[6].get_mark_bit()); assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); + assert!(!wam.machine_st.heap[3].get_forwarding_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + assert!(!wam.machine_st.heap[6].get_forwarding_bit()); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), + wam.machine_st.heap[0], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) + wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(4)) + ); + assert_eq!( + wam.machine_st.heap[3], + atom_as_cell!(atom!("irrelevant stuff")) + ); + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()), + "def" + ); + assert_eq!( + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(1) + 2) + ); + assert_eq!( + wam.machine_st.heap[6], + atom_as_cell!(atom!("irrelevant stuff")) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + wam.machine_st.heap[7] = pstr_loc_as_cell!(heap_index!(4)); - wam.machine_st.heap[9] = heap_loc_as_cell!(5); - - mark_cells(&mut wam.machine_st.heap, 9); + mark_cells(&mut wam.machine_st.heap, 7); assert!(!wam.machine_st.heap[0].get_mark_bit()); assert!(wam.machine_st.heap[1].get_mark_bit()); @@ -998,340 +1039,143 @@ mod tests { assert!(wam.machine_st.heap[5].get_mark_bit()); assert!(!wam.machine_st.heap[6].get_mark_bit()); assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); - for cell in &wam.machine_st.heap { - assert!(!cell.get_forwarding_bit()); - } + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); + assert!(!wam.machine_st.heap[3].get_forwarding_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + assert!(!wam.machine_st.heap[6].get_forwarding_bit()); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), + wam.machine_st.heap[0], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) + wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) - ); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - - wam.machine_st.heap[9] = pstr_loc_as_cell!(4); - - mark_cells(&mut wam.machine_st.heap, 9); - - assert!(!wam.machine_st.heap[0].get_mark_bit()); - assert!(wam.machine_st.heap[1].get_mark_bit()); - assert!(wam.machine_st.heap[2].get_mark_bit()); - assert!(!wam.machine_st.heap[3].get_mark_bit()); - assert!(wam.machine_st.heap[4].get_mark_bit()); - assert!(wam.machine_st.heap[5].get_mark_bit()); - assert!(!wam.machine_st.heap[6].get_mark_bit()); - assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); - - for cell in &wam.machine_st.heap { - assert!(!cell.get_forwarding_bit()); - } - - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(4)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), + wam.machine_st.heap[3], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) + wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()), + "def" ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(1) + 2) ); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - - mark_cells(&mut wam.machine_st.heap, 9); - - wam.machine_st.heap[9] = heap_loc_as_cell!(2); - - assert!(!wam.machine_st.heap[0].get_mark_bit()); - assert!(wam.machine_st.heap[1].get_mark_bit()); - assert!(wam.machine_st.heap[2].get_mark_bit()); - assert!(!wam.machine_st.heap[3].get_mark_bit()); - assert!(wam.machine_st.heap[4].get_mark_bit()); - assert!(wam.machine_st.heap[5].get_mark_bit()); - assert!(!wam.machine_st.heap[6].get_mark_bit()); - assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); - - for cell in &wam.machine_st.heap { - assert!(!cell.get_forwarding_bit()); - } - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), + wam.machine_st.heap[6], atom_as_cell!(atom!("irrelevant stuff")) ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) - ); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - - wam.machine_st.heap[9] = pstr_loc_as_cell!(1); - - mark_cells(&mut wam.machine_st.heap, 9); - - assert!(!wam.machine_st.heap[0].get_mark_bit()); - assert!(wam.machine_st.heap[1].get_mark_bit()); - assert!(wam.machine_st.heap[2].get_mark_bit()); - assert!(!wam.machine_st.heap[3].get_mark_bit()); - assert!(wam.machine_st.heap[4].get_mark_bit()); - assert!(wam.machine_st.heap[5].get_mark_bit()); - assert!(!wam.machine_st.heap[6].get_mark_bit()); - assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); - - for cell in &wam.machine_st.heap { - assert!(!cell.get_forwarding_bit()); - } - - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) - ); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } wam.machine_st.heap.clear(); - // embedded cyclic partial string. + // embedded cyclic partial string - wam.machine_st.heap.push(pstr_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(3))); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(8).unwrap(); - mark_cells(&mut wam.machine_st.heap, 4); + writer.write_with(|section| { + section.push_pstr("abc "); + section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 3)); // 3 character offset into pstr_cell + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(pstr_loc_as_cell!(0)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(heap_loc_as_cell!(2)); + }); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + mark_cells(&mut wam.machine_st.heap, 5); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), - pstr_loc_as_cell!(2) + wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_offset_as_cell!(0) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(0) + 3) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - fixnum_as_cell!(Fixnum::build_with(3)) + wam.machine_st.heap[2], + list_loc_as_cell!(3) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - list_loc_as_cell!(5) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), + wam.machine_st.heap[3], pstr_loc_as_cell!(0) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), + wam.machine_st.heap[4], empty_list_as_cell!() ); - - wam.machine_st.heap.clear(); - - wam.machine_st.heap.push(pstr_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(3))); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - wam.machine_st.heap.push(heap_loc_as_cell!(4)); - - mark_cells(&mut wam.machine_st.heap, 4); - - all_cells_marked_and_unforwarded(&wam.machine_st.heap); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), - pstr_loc_as_cell!(2) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_offset_as_cell!(0) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - fixnum_as_cell!(Fixnum::build_with(3)) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - list_loc_as_cell!(5) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(0) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - heap_loc_as_cell!(4) + wam.machine_st.heap[5], + heap_loc_as_cell!(2) ); wam.machine_st.heap.clear(); // a chain of variables, ending in a self-referential variable. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(3)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), + wam.machine_st.heap[0], heap_loc_as_cell!(1) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), + wam.machine_st.heap[1], heap_loc_as_cell!(2) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), + wam.machine_st.heap[2], heap_loc_as_cell!(3) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), + wam.machine_st.heap[3], heap_loc_as_cell!(3) ); wam.machine_st.heap.clear(); // print L = [L|L]. - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(1)); + + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(1)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1350,23 +1194,28 @@ mod tests { // term is [X,f(Y),Z]. // Z is an attributed variable, but has a variable attributes list. - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2 - wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3 - wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4 - wam.machine_st.heap.push(heap_loc_as_cell!(8)); - wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6 - wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7 - wam.machine_st.heap.push(list_loc_as_cell!(9)); - wam.machine_st.heap.push(heap_loc_as_cell!(9)); - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. - wam.machine_st.heap.push(heap_loc_as_cell!(12)); + + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(3)); // 2 + section.push_cell(list_loc_as_cell!(4)); // 3 + section.push_cell(str_loc_as_cell!(6)); // 4 + section.push_cell(heap_loc_as_cell!(8)); + section.push_cell(atom_as_cell!(f_atom, 1)); // 6 + section.push_cell(heap_loc_as_cell!(11)); // 7 + section.push_cell(list_loc_as_cell!(9)); + section.push_cell(heap_loc_as_cell!(9)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(attr_var_as_cell!(11)); // linked from 7. + section.push_cell(heap_loc_as_cell!(12)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1425,29 +1274,32 @@ mod tests { let clpz_atom = atom!("clpz"); let p_atom = atom!("p"); - for cell in &mut wam.machine_st.heap { + for cell in &mut wam.machine_st.heap.splice_mut(..) { cell.set_mark_bit(false); cell.set_forwarding_bit(false); } - wam.machine_st.heap.pop(); + wam.machine_st.heap[12] = heap_loc_as_cell!(13); - wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 - wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13 - wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14 - wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15 - wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16 - wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17 - wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18 - wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19 - wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20 - wam.machine_st.heap.push(empty_list_as_cell!()); // 21 - wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 - wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(14)); // 13 + section.push_cell(str_loc_as_cell!(16)); // 14 + section.push_cell(heap_loc_as_cell!(19)); // 15 + section.push_cell(atom_as_cell!(clpz_atom, 2)); // 16 + section.push_cell(atom_as_cell!(a_atom)); // 17 + section.push_cell(atom_as_cell!(b_atom)); // 18 + section.push_cell(list_loc_as_cell!(20)); // 19 + section.push_cell(str_loc_as_cell!(22)); // 20 + section.push_cell(empty_list_as_cell!()); // 21 + section.push_cell(atom_as_cell!(p_atom, 1)); // 22 + section.push_cell(heap_loc_as_cell!(23)); // 23 + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1546,22 +1398,26 @@ mod tests { heap_loc_as_cell!(23) ); - for cell in &mut wam.machine_st.heap { + for cell in &mut wam.machine_st.heap.splice_mut(..) { cell.set_mark_bit(false); cell.set_forwarding_bit(false); } // push some unrelated nonsense cells to the heap and check that they // are unmarked after the marker has finished at 0. - wam.machine_st.heap.push(heap_loc_as_cell!(5)); - wam.machine_st.heap.push(heap_loc_as_cell!(5)); - wam.machine_st.heap.push(list_loc_as_cell!(5)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(5)); + section.push_cell(heap_loc_as_cell!(5)); + section.push_cell(list_loc_as_cell!(5)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[0..24]); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(0..24)); - for cell in &wam.machine_st.heap[24..] { + for cell in wam.machine_st.heap.splice(24..) { assert!(!cell.get_mark_bit()); } @@ -1677,32 +1533,37 @@ mod tests { wam.machine_st.heap.clear(); wam.machine_st .heap - .push(fixnum_as_cell!(Fixnum::build_with(0))); + .push_cell(fixnum_as_cell!(Fixnum::build_with(0))) + .unwrap(); mark_cells(&mut wam.machine_st.heap, 0); - assert_eq!(wam.machine_st.heap.len(), 1); + assert_eq!(wam.machine_st.heap.cell_len(), 1); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); - wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(list_loc_as_cell!(8)); - wam.machine_st.heap.push(str_loc_as_cell!(4)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(atom!("X"))); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(str_loc_as_cell!(4)); + section.push_cell(empty_list_as_cell!()); + }); mark_cells(&mut wam.machine_st.heap, 7); - assert_eq!(wam.machine_st.heap.len(), 10); + assert_eq!(wam.machine_st.heap.cell_len(), 10); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1747,14 +1608,18 @@ mod tests { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("f"), 2)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(str_loc_as_cell!(0)); + }); mark_cells(&mut wam.machine_st.heap, 3); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1773,19 +1638,22 @@ mod tests { // representation of one of the heap terms as in issue #1384. - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(5)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(list_loc_as_cell!(5)); + }); mark_cells(&mut wam.machine_st.heap, 7); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1820,23 +1688,27 @@ mod tests { // representation of one of the heap terms as in issue #1384. - wam.machine_st.heap.push(list_loc_as_cell!(7)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); // A = [B|[]]. - wam.machine_st.heap.push(list_loc_as_cell!(5)); // B = [A|A]. - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(empty_list_as_cell!()); // C = [[]|B]. - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(7)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(list_loc_as_cell!(3)); // A = [B|[]]. + section.push_cell(list_loc_as_cell!(5)); // B = [A|A]. + section.push_cell(empty_list_as_cell!()); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(empty_list_as_cell!()); // C = [[]|B]. + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(0)); + }); mark_cells(&mut wam.machine_st.heap, 9); assert!(wam.machine_st.heap[0].get_mark_bit()); assert!(!wam.machine_st.heap[1].get_mark_bit()); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[2..]); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(2..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1874,31 +1746,31 @@ mod tests { unmark_cell_bits!(wam.machine_st.heap[8]), heap_loc_as_cell!(3) ); + assert_eq!( + unmark_cell_bits!(wam.machine_st.heap[9]), + heap_loc_as_cell!(0) + ); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2)); - wam.machine_st.heap.push(str_loc_as_cell!(4)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); - wam.machine_st.heap.push(atom_as_cell!(atom!("-"), 2)); - wam.machine_st.heap.push(str_loc_as_cell!(7)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1))); - wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(3))); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(4))); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("+"), 2)); + section.push_cell(str_loc_as_cell!(4)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(2))); + section.push_cell(atom_as_cell!(atom!("-"), 2)); + section.push_cell(str_loc_as_cell!(7)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(1))); + section.push_cell(atom_as_cell!(atom!("+"), 2)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(3))); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(4))); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 0f42b8c6..5dd33a9b 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1,97 +1,1274 @@ -use crate::arena::*; use crate::atom_table::*; use crate::forms::*; -use crate::machine::machine_indices::*; -use crate::machine::partial_string::*; -use crate::parser::ast::*; +use crate::functor_macro::*; use crate::types::*; -use crate::parser::dashu::{Integer, Rational}; - +use std::alloc; use std::convert::TryFrom; +use std::mem; +use std::ops::{Bound, Index, IndexMut, Range, RangeBounds}; +use std::ptr; +use std::sync::Once; -pub(crate) type Heap = Vec; +use super::MachineState; + +use bitvec::prelude::*; +use bitvec::slice::BitSlice; + +#[derive(Debug)] +pub struct Heap { + inner: InnerHeap, + pstr_vec: BitVec, + resource_err_loc: usize, +} + +impl Drop for Heap { + fn drop(&mut self) { + unsafe { + let layout = alloc::Layout::array::(self.inner.byte_cap).unwrap(); + alloc::dealloc(self.inner.ptr, layout); + } + } +} + +#[derive(Debug)] +struct InnerHeap { + ptr: *mut u8, + byte_len: usize, + byte_cap: usize, +} + +impl InnerHeap { + unsafe fn grow(&mut self) -> bool { + let new_cap = if self.byte_cap == 0 { + 256 * 256 * 8 + } else { + 2 * self.byte_cap + }; + + let new_layout = alloc::Layout::array::(new_cap).unwrap(); + + assert!( + new_layout.size() <= isize::MAX as usize, + "Allocation too large. We should probably GC (TODO)" + ); + + let new_ptr = if self.byte_cap == 0 { + alloc::alloc(new_layout) + } else { + let old_layout = alloc::Layout::array::(self.byte_cap).unwrap(); + alloc::realloc(self.ptr, old_layout, new_layout.size()) + }; + + if !new_ptr.is_null() { + self.ptr = new_ptr; + self.byte_cap = new_cap; + + true + } else { + false + } + } +} + +unsafe impl Send for Heap {} +unsafe impl Sync for Heap {} + +static RESOURCE_ERROR_OFFSET_INIT: Once = Once::new(); + +// return the string at ptr and the tail location relative to ptr. +// pstr_vec records the location of each string cell starting at index +// 0. +fn scan_slice_to_str(orig_ptr: *const u8, pstr_vec: &BitSlice) -> (&str, usize) { + unsafe { + debug_assert_eq!(pstr_vec[0], true); + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); + + let tail_cell_offset = pstr_vec[0..].first_zero().unwrap(); + let offset = (ALIGN_CELL - orig_ptr.align_offset(ALIGN_CELL)) % 8; + let buf_len = heap_index!(tail_cell_offset) - offset; + let slice = std::slice::from_raw_parts(orig_ptr, buf_len); + + // skip the final buffer byte which may not be 0 depending on + // the context, i.e. marking by an iterator. it is counted by + // the initial 1 as part of the padding but for this reason + // mustn't be allowed to stop the count. + + let padding_len = 1 + slice.iter() + .rev() + .skip(1) + .position(|b| *b != 0u8) + .unwrap(); + + let s_len = slice.len() - padding_len; + (std::str::from_utf8_unchecked(&slice[0 .. s_len]), tail_cell_offset) + } +} + +#[derive(Debug, Clone, Copy)] +pub(crate) enum PStrSegmentCmpResult { + Mismatch { c1: char, c2: char }, + FirstMatch { pstr_loc1: usize, pstr_loc2: usize, l1_offset: usize }, + SecondMatch { pstr_loc1: usize, pstr_loc2: usize, l2_offset: usize }, + BothMatch { pstr_loc1: usize, pstr_loc2: usize, null_offset: usize }, +} + +impl PStrSegmentCmpResult { + pub(crate) fn continue_pstr_compare( + self, + pdl: &mut Vec, + ) -> Option { + match self { + PStrSegmentCmpResult::FirstMatch { pstr_loc1, pstr_loc2, l1_offset } => { + let tail1 = Heap::neighboring_cell_offset(pstr_loc1 + l1_offset); + let rest_of_l2 = pstr_loc_as_cell!(pstr_loc2 + l1_offset); + + pdl.push(heap_loc_as_cell!(tail1)); + pdl.push(rest_of_l2); + } + PStrSegmentCmpResult::SecondMatch { pstr_loc1, pstr_loc2, l2_offset } => { + let tail2 = Heap::neighboring_cell_offset(pstr_loc2 + l2_offset); + let rest_of_l1 = pstr_loc_as_cell!(pstr_loc1 + l2_offset); + + pdl.push(rest_of_l1); + pdl.push(heap_loc_as_cell!(tail2)); + } + PStrSegmentCmpResult::BothMatch { pstr_loc1, pstr_loc2, null_offset } => { + // exhaustive match + let tail1 = Heap::neighboring_cell_offset(pstr_loc1 + null_offset); + let tail2 = Heap::neighboring_cell_offset(pstr_loc2 + null_offset); + + pdl.push(heap_loc_as_cell!(tail1)); + pdl.push(heap_loc_as_cell!(tail2)); + } + PStrSegmentCmpResult::Mismatch { c1, c2 } => { + return Some(c1.cmp(&c2)); + } + } + + None + } +} + +#[derive(Debug)] +pub(crate) struct HeapView<'a> { + slice: *const u8, + cell_offset: usize, + slice_cell_len: usize, + pstr_slice: &'a BitSlice, +} + +impl<'a> HeapView<'a> { + /* + pub fn get(&self, idx: usize) -> Option { + if idx < self.slice_cell_len { + Some(*self.index(idx)) + } else { + None + } + } + */ + + fn iter_follow(&mut self) -> Option { + if self.slice_cell_len == 0 { + None + } else { + let cell; + + if self.pstr_slice[0] { + cell = pstr_loc_as_cell!(heap_index!(self.cell_offset)); + let next_cell_idx = self.pstr_slice[0 ..].first_zero().unwrap(); + + unsafe { self.slice = self.slice.add(heap_index!(next_cell_idx)); } + self.slice_cell_len -= next_cell_idx; + self.cell_offset += next_cell_idx; + self.pstr_slice = &self.pstr_slice[next_cell_idx ..]; + } else { + unsafe { + cell = ptr::read(self.slice as *mut HeapCellValue); + self.slice = self.slice.add(heap_index!(1)); + } + + self.cell_offset += 1; + self.slice_cell_len -= 1; + self.pstr_slice = &self.pstr_slice[1 ..]; + } + + Some(cell) + } + } +} + +impl<'a> Iterator for HeapView<'a> { + type Item = HeapCellValue; -impl From for HeapCellValue { #[inline] - fn from(literal: Literal) -> Self { - match literal { - Literal::Atom(name) => atom_as_cell!(name), - Literal::Char(c) => char_as_cell!(c), - Literal::CodeIndex(ptr) => { - untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr)) - } - Literal::Fixnum(n) => fixnum_as_cell!(n), - Literal::Integer(bigint_ptr) => { - typed_arena_ptr_as_cell!(bigint_ptr) - } - Literal::Rational(bigint_ptr) => { - typed_arena_ptr_as_cell!(bigint_ptr) - } - Literal::Float(f) => HeapCellValue::from(f.as_ptr()), - Literal::String(s) => { - if s == atom!("") { - empty_list_as_cell!() + fn next(&mut self) -> Option { + self.iter_follow() + } +} + +impl<'a> Index for HeapView<'a> { + type Output = HeapCellValue; + + fn index(&self, idx: usize) -> &Self::Output { + debug_assert!(idx < self.slice_cell_len); + unsafe { + &*(self.slice.add(heap_index!(idx)) as *const HeapCellValue) + } + } +} + +#[derive(Debug)] +pub(crate) struct HeapViewMut<'a> { + slice: *mut u8, + cell_offset: usize, + slice_cell_len: usize, + pstr_slice: &'a BitSlice, +} + +impl<'a> HeapViewMut<'a> { + fn iter_follow(&mut self) -> Option<&'a mut HeapCellValue> { + if self.slice_cell_len == 0 { + None + } else { + let cell; + + loop { + if self.pstr_slice[0] { + let next_cell_idx = self.pstr_slice[0 ..].first_zero().unwrap(); + + unsafe { self.slice = self.slice.add(heap_index!(next_cell_idx)); } + + self.slice_cell_len -= next_cell_idx; + self.cell_offset += next_cell_idx; + self.pstr_slice = &self.pstr_slice[next_cell_idx ..]; } else { - string_as_cstr_cell!(s) + unsafe { + cell = &mut *(self.slice as *mut HeapCellValue); + self.slice = self.slice.add(heap_index!(1)); + } + + self.cell_offset += 1; + self.slice_cell_len -= 1; + self.pstr_slice = &self.pstr_slice[1 ..]; + + break; + } + } + + Some(cell) + } + } +} + + + +impl<'a> Index for HeapViewMut<'a> { + type Output = HeapCellValue; + + fn index(&self, idx: usize) -> &Self::Output { + debug_assert!(idx < self.slice_cell_len); + unsafe { + &*(self.slice.add(heap_index!(idx)) as *const HeapCellValue) + } + } +} + +impl<'a> IndexMut for HeapViewMut<'a> { + fn index_mut(&mut self, idx: usize) -> &mut Self::Output { + debug_assert!(idx < self.slice_cell_len); + unsafe { + &mut *(self.slice.add(heap_index!(idx)) as *mut HeapCellValue) + } + } +} + +impl<'a> Iterator for &'a mut HeapViewMut<'a> { + type Item = &'a mut HeapCellValue; + + #[inline] + fn next(&mut self) -> Option { + self.iter_follow() + } +} + +#[derive(Debug)] +pub struct PStrWriteInfo { + pstr_loc: usize, +} + +#[derive(Debug)] +pub(crate) struct ReservedHeapSection<'a> { + heap_ptr: *mut u8, + heap_cell_len: usize, + pstr_vec: &'a mut BitVec, +} + +impl<'a> ReservedHeapSection<'a> { + #[inline] + pub(crate) fn cell_len(&self) -> usize { + self.heap_cell_len + } + + pub(crate) fn push_cell(&mut self, cell: HeapCellValue) { + unsafe { + ptr::write(self.heap_ptr.add(heap_index!(self.heap_cell_len)) as *mut _, cell); + } + self.pstr_vec.push(false); + self.heap_cell_len += 1; + } + + fn push_pstr_segment( + &mut self, + src: &str, + ) -> usize { + if src.is_empty() { + return 0; + } + + let cells_written; + let str_byte_len = src.len(); + + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); + + unsafe { + ptr::copy_nonoverlapping( + src.as_ptr(), + self.heap_ptr.add(heap_index!(self.heap_cell_len)), + str_byte_len, + ); + + let zero_region_idx = heap_index!(self.heap_cell_len) + str_byte_len; + + let align_offset = self.heap_ptr + .add(zero_region_idx) + .align_offset(ALIGN_CELL); + + let align_offset = if align_offset == 0 { + ALIGN_CELL + } else { + align_offset + }; + + ptr::write_bytes( + self.heap_ptr.add(zero_region_idx), + 0u8, + align_offset, + ); + + cells_written = cell_index!(src.len() + align_offset); + self.heap_cell_len += cells_written; + } + + cells_written + } + + pub(crate) fn push_pstr( + &mut self, + mut src: &str, + ) -> Option { + let orig_h = self.cell_len(); + + if src.is_empty() { + return if orig_h == self.heap_cell_len { + // src is empty and always was. nothing allocated + // in this case, so nothing to point to in heap. + None + } else { + self.push_cell(heap_loc_as_cell!(orig_h)); + Some(heap_loc_as_cell!(orig_h)) + }; + } + + loop { + let null_char_idx = src.find('\u{0}').unwrap_or_else(|| src.len()); + + let cell_len = self.cell_len(); + let cells_written = self.push_pstr_segment(&src[0..null_char_idx]); + let tail_idx = self.cell_len(); + + self.pstr_vec.resize(cell_len + cells_written, true); + + if cells_written == 0 { + return None; + } else if null_char_idx + 1 < src.len() { + self.push_cell(pstr_loc_as_cell!(heap_index!(tail_idx + 1))); + src = &src[null_char_idx + 1 ..]; + } else { + return Some(pstr_loc_as_cell!(heap_index!(orig_h))); + } + } + } + + pub(crate) fn functor_writer( + functor: Vec, + ) -> impl FnMut(&mut ReservedHeapSection) { + struct FunctorData<'a> { + functor: &'a Vec, + cell_offset: usize, + cursor: usize, + } + + move |section| { + let mut functor_stack = vec![FunctorData { + functor: &functor, + cell_offset: section.heap_cell_len, + cursor: 0, + }]; + + while let Some(FunctorData { functor, cell_offset, mut cursor }) = functor_stack.pop() { + while cursor < functor.len() { + match &functor[cursor] { + &FunctorElement::AbsoluteCell(cell) => { + section.push_cell(cell); + } + &FunctorElement::Cell(cell) => { + section.push_cell(cell + cell_offset); + } + &FunctorElement::String(_cell_len, ref string) => { + if section.push_pstr(&string).is_some() { + section.push_cell(empty_list_as_cell!()); + } + } + FunctorElement::InnerFunctor(_inner_size, succ_functor) => { + if cursor + 1 < functor.len() { + functor_stack.push(FunctorData { + functor: &functor, + cell_offset, + cursor: cursor + 1, + }); + } + + functor_stack.push(FunctorData { + functor: succ_functor, + cell_offset: section.heap_cell_len, + cursor: 0, + }); + + break; + } + } + + cursor += 1; } } } } } -impl TryFrom for Literal { - type Error = (); +impl<'a> Index for ReservedHeapSection<'a> { + type Output = HeapCellValue; - fn try_from(value: HeapCellValue) -> Result { - read_heap_cell!(value, - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - Ok(Literal::Atom(name)) - } else { - Err(()) - } - } - (HeapCellValueTag::Char, c) => { - Ok(Literal::Char(c)) - } - (HeapCellValueTag::Fixnum, n) => { - Ok(Literal::Fixnum(n)) - } - (HeapCellValueTag::F64, f) => { - Ok(Literal::Float(f.as_offset())) - } - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::Integer, n) => { - Ok(Literal::Integer(n)) - } - (ArenaHeaderTag::Rational, n) => { - Ok(Literal::Rational(n)) - } - (ArenaHeaderTag::IndexPtr, ip) => { - Ok(Literal::CodeIndex(CodeIndex::from(ip))) - } - _ => { - Err(()) - } - ) - } - (HeapCellValueTag::CStr, cstr_atom) => { - Ok(Literal::String(cstr_atom)) - } - _ => { - Err(()) - } - ) + #[inline] + fn index(&self, idx: usize) -> &Self::Output { + debug_assert!(idx < self.heap_cell_len); + unsafe { + &*(self.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue) + } } } +#[must_use] +#[derive(Debug)] +pub struct HeapWriter<'a> { + section: ReservedHeapSection<'a>, + heap_byte_len: &'a mut usize, +} + +impl<'a> HeapWriter<'a> { + #[allow(dead_code)] + pub(crate) fn write_with_error_handling( + &mut self, + writer: impl FnOnce(&mut ReservedHeapSection) -> Result<(), E>, + ) -> Result { + let old_section_cell_len = self.section.heap_cell_len; + writer(&mut self.section)?; + *self.heap_byte_len = heap_index!(self.section.heap_cell_len); + + // return the number of bytes written + Ok(heap_index!(self.section.heap_cell_len - old_section_cell_len)) + } + + pub(crate) fn write_with( + &mut self, + writer: impl FnOnce(&mut ReservedHeapSection), + ) -> usize { + let old_section_cell_len = self.section.heap_cell_len; + writer(&mut self.section); + *self.heap_byte_len = heap_index!(self.section.heap_cell_len); + + // return the number of bytes written + heap_index!(self.section.heap_cell_len - old_section_cell_len) + } + + #[inline] + pub(crate) fn truncate(&mut self, cell_offset: usize) { + self.section.heap_cell_len = cell_offset; + self.section.pstr_vec.truncate(cell_offset); + *self.heap_byte_len = heap_index!(cell_offset); + } + + #[inline] + pub(crate) fn is_empty(&self) -> bool { + self.section.heap_cell_len == 0 + } + + #[inline] + pub(crate) fn cell_len(&self) -> usize { + self.section.heap_cell_len + } +} + +impl<'a> Index for HeapWriter<'a> { + type Output = HeapCellValue; + + #[inline] + fn index(&self, idx: usize) -> &Self::Output { + debug_assert!(heap_index!(idx) < *self.heap_byte_len); + unsafe { + &*(self.section.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue) + } + } +} + +impl<'a> IndexMut for HeapWriter<'a> { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut Self::Output { + debug_assert!(heap_index!(idx) < *self.heap_byte_len); + unsafe { + &mut *(self.section.heap_ptr.add(heap_index!(idx)) as *mut HeapCellValue) + } + } +} + +impl<'a> SizedHeap for HeapWriter<'a> { + fn cell_len(&self) -> usize { + self.section.cell_len() + } + + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { + let (s, tail_cell_offset) = scan_slice_to_str( + unsafe { self.section.heap_ptr.add(slice_loc) }, + &self.section.pstr_vec.as_bitslice()[cell_index!(slice_loc) ..], + ); + + (s, cell_index!(slice_loc) + tail_cell_offset) + } + + fn pstr_at(&self, cell_offset: usize) -> bool { + self.section.pstr_vec[cell_offset] + } +} + +impl<'a> SizedHeapMut for HeapWriter<'a> {} + +impl Heap { + pub(crate) fn new() -> Self { + Self { + inner: InnerHeap { + ptr: ptr::null_mut(), + byte_len: 0, + byte_cap: 0, + }, + pstr_vec: bitvec![], + resource_err_loc: 0, + } + } + + #[inline(always)] + unsafe fn grow(&mut self) -> bool { + let result = self.inner.grow(); + + if result { + self.pstr_vec.reserve(cell_index!(self.inner.byte_cap)); + } + + result + } + + #[inline] + fn resource_error_offset(&self) -> usize { + self.resource_err_loc + } + + pub(crate) fn with_cell_capacity(cap: usize) -> Result { + let ptr = unsafe { + let layout = alloc::Layout::array::(cap).unwrap(); + alloc::alloc(layout) + }; + + if ptr.is_null() { + panic!("could not allocate {} bytes for heap!", heap_index!(cap)) + } else { + Ok(Self { + inner: InnerHeap { + ptr, + byte_len: 0, + byte_cap: heap_index!(cap), + }, + pstr_vec: bitvec![], + resource_err_loc: 0, + }) + } + } + + #[must_use] + pub fn reserve(&mut self, num_cells: usize) -> Result { + let section; + let len = heap_index!(num_cells); + + loop { + unsafe { + if self.free_space() >= len { + section = ReservedHeapSection { + heap_ptr: self.inner.ptr, + heap_cell_len: cell_index!(self.inner.byte_len), + pstr_vec: &mut self.pstr_vec, + }; + break; + } else if !self.grow() { + return Err(self.resource_error_offset()); + } + } + } + + Ok(HeapWriter { + section, + heap_byte_len: &mut self.inner.byte_len, + }) + } + + pub(crate) fn last_cell_mut(&mut self) -> Option<&mut HeapCellValue> { + if self.inner.byte_len == 0 { + None + } else { + unsafe { + Some(&mut *(self.inner.ptr.add(self.inner.byte_len - heap_index!(1)) + as *mut HeapCellValue)) + } + } + } + + pub(crate) fn last_cell(&mut self) -> Option { + if self.inner.byte_len == 0 { + None + } else { + unsafe { + Some(ptr::read(self.inner.ptr.add(self.inner.byte_len - heap_index!(1)) + as *const HeapCellValue)) + } + } + } + + #[inline] + pub(crate) fn is_empty(&self) -> bool { + self.inner.byte_len == 0 + } + + pub(crate) fn index_of(&mut self, cell: HeapCellValue) -> Result { + Ok(if cell.is_var() { + cell.get_value() as usize + } else { + let focus = self.cell_len(); + self.push_cell(cell)?; + focus + }) + } + + pub(crate) fn clear(&mut self) { + unsafe { + let layout = alloc::Layout::array::(self.inner.byte_cap).unwrap(); + alloc::dealloc(self.inner.ptr, layout); + } + + self.inner.ptr = ptr::null_mut(); + self.inner.byte_len = 0; + self.inner.byte_cap = 0; + + self.pstr_vec.clear(); + } + + pub(crate) fn append(&mut self, heap_slice: HeapView) -> Result<(), usize> { + unsafe { + loop { + if self.free_space() >= heap_index!(heap_slice.slice_cell_len) { + ptr::copy_nonoverlapping( + heap_slice.slice, + self.inner.ptr.add(self.inner.byte_len), + heap_index!(heap_slice.slice_cell_len), + ); + + self.inner.byte_len += heap_index!(heap_slice.slice_cell_len); + self.pstr_vec.extend(heap_slice.pstr_slice.iter()); + + break; + } else if !self.grow() { + return Err(self.resource_error_offset()); + } + } + } + + Ok(()) + } + + pub(crate) fn store_resource_error(&mut self) { + RESOURCE_ERROR_OFFSET_INIT.call_once(move || { + let stub = functor!(atom!("resource_error"), [atom_as_cell((atom!("memory")))]); + self.resource_err_loc = cell_index!(self.inner.byte_len); + + let mut writer = Heap::functor_writer(stub); + writer(self).unwrap(); + }); + } + + pub(crate) fn compare_pstr_segments( + &self, + pstr_loc1: usize, + pstr_loc2: usize, + ) -> PStrSegmentCmpResult { + unsafe { + let slice1 = std::slice::from_raw_parts( + self.inner.ptr.add(pstr_loc1), + self.inner.byte_len - pstr_loc1, + ); + + let slice2 = std::slice::from_raw_parts( + self.inner.ptr.add(pstr_loc2), + self.inner.byte_len - pstr_loc2, + ); + + let str1 = std::str::from_utf8_unchecked(&slice1); + let str2 = std::str::from_utf8_unchecked(&slice2); + + debug_assert!(!str1.is_empty()); + debug_assert!(!str2.is_empty()); + + for ((idx, c1), c2) in str1.char_indices().zip(str2.chars()) { + if c1 == '\u{0}' && c2 == '\u{0}' { + return PStrSegmentCmpResult::BothMatch { pstr_loc1, pstr_loc2, null_offset: idx }; + } else if c1 == '\u{0}' { + return PStrSegmentCmpResult::FirstMatch { pstr_loc1, pstr_loc2, l1_offset: idx }; + } else if c2 == '\u{0}' { + return PStrSegmentCmpResult::SecondMatch { pstr_loc1, pstr_loc2, l2_offset: idx }; + } else if c1 != c2 { + return PStrSegmentCmpResult::Mismatch { c1, c2 }; + } + } + + unreachable!() // PStrSegmentCmpResult::Match(std::cmp::min(str1.len(), str2.len())) + } + } + + #[inline] + pub(crate) fn slice_to_str(&self, slice_loc: usize, slice_len: usize) -> &str { + unsafe { + let slice = std::slice::from_raw_parts(self.inner.ptr.add(slice_loc), slice_len); + std::str::from_utf8_unchecked(&slice) + } + } + + #[inline] + pub(crate) fn byte_len(&self) -> usize { + self.inner.byte_len + } + + #[inline] + pub(crate) fn cell_len(&self) -> usize { + cell_index!(self.inner.byte_len) + } + + // free space in bytes. + #[inline] + fn free_space(&self) -> usize { + self.inner.byte_cap - self.inner.byte_len + } + + pub(crate) fn char_iter<'a>(&'a self, pstr_loc: usize) -> PStrSegmentIter<'a> { + PStrSegmentIter::from(self, pstr_loc) + } + + // either succeed & return nothing or fail & return an offset into + // the heap to a pre-allocated resource error + pub(crate) fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), usize> { + unsafe { + if self.inner.byte_len == self.inner.byte_cap { + if !self.grow() { + return Err(self.resource_error_offset()); + } + } + + let cell_ptr = (self.inner.ptr as *mut HeapCellValue).add(self.cell_len()); + cell_ptr.write(cell); + self.pstr_vec.push(false); + self.inner.byte_len += heap_index!(1); + } + + Ok(()) + } + + /* + pub(crate) fn pop_cell(&mut self) -> Option { + unsafe { + if self.inner.byte_len > 0 { + let cell_ptr = (self.inner.ptr as *const HeapCellValue) + .add(self.cell_len()) + .sub(1); + let cell = ptr::read(cell_ptr); + + self.inner.byte_len -= heap_index!(1); + self.pstr_vec.pop(); + + Some(cell) + } else { + None + } + } + } + */ + + fn slice_range>(&self, range: R) -> Range { + let start = match range.start_bound() { + Bound::Included(lower_bound) => *lower_bound, + Bound::Excluded(lower_bound) => *lower_bound + 1, + Bound::Unbounded => 0, + }; + + let end = match range.end_bound() { + Bound::Included(upper_bound) => *upper_bound + 1, + Bound::Excluded(0) => 0, + Bound::Excluded(upper_bound) => *upper_bound, + Bound::Unbounded => self.cell_len(), + }; + + Range { start, end } + } + + pub(crate) fn splice>( + &self, + range: R, + ) -> HeapView { + let range = self.slice_range(range); + + HeapView { + slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, + cell_offset: range.start, + slice_cell_len: range.end - range.start, + pstr_slice: &self.pstr_vec.as_bitslice()[range], + } + } + + pub(crate) fn splice_mut>( + &self, + range: R, + ) -> HeapViewMut { + let range = self.slice_range(range); + + HeapViewMut { + slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, + cell_offset: range.start, + slice_cell_len: range.end - range.start, + pstr_slice: &self.pstr_vec.as_bitslice()[range], + } + } + + pub fn allocate_pstr(&mut self, src: &str) -> Result, usize> { + let size_in_heap = Self::compute_pstr_size(src); + let pstr_loc = heap_index!(self.cell_len()); + + Ok(if size_in_heap > 0 { + let mut writer = self.reserve(size_in_heap)?; + + writer.write_with(|section| { + section.push_pstr(src); + }); + + Some(PStrWriteInfo { pstr_loc }) + } else { + None + }) + } + + const fn heap_cell_alignment() -> usize { + // yes, size_of, not align_of. the alignment of HeapCellValue + // is 1 byte. In the heap, though, its alignment must be its + // size. + mem::size_of::() + } + + // takes a byte offset into the Heap ptr. + #[inline(always)] + pub(crate) const fn neighboring_cell_offset(offset: usize) -> usize { + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); + cell_index!((offset & !(ALIGN_CELL - 1)) + ALIGN_CELL) + } + + #[inline] + pub(crate) fn iter(&self) -> HeapView { + HeapView { + slice: self.inner.ptr, + cell_offset: 0, + slice_cell_len: cell_index!(self.inner.byte_len), + pstr_slice: &self.pstr_vec.as_bitslice(), + } + } + + #[inline] + pub(crate) fn pstr_vec(&self) -> &BitSlice { + self.pstr_vec.as_bitslice() + } + + #[inline] + pub(crate) fn char_at(&self, byte_idx: usize) -> char { + let s = unsafe { + let char_ptr = self.inner.ptr.add(byte_idx); + let slice = std::slice::from_raw_parts(char_ptr, mem::size_of::()); + std::str::from_utf8_unchecked(&slice) + }; + + s.chars().next().unwrap() + } + + pub(crate) fn last_str_char_and_tail(&self, loc: usize) -> (char, HeapCellValue) { + unsafe { + let char_ptr = self.inner.ptr.add(loc); + let slice = std::slice::from_raw_parts(char_ptr, self.inner.byte_len - loc); + + let s = std::str::from_utf8_unchecked(&slice); + let mut chars_iter = s.chars(); + let c = chars_iter.next().unwrap(); + let succ_len = loc + c.len_utf8(); + + if chars_iter.next() == Some('\u{0}') { + (c, heap_loc_as_cell!(Self::neighboring_cell_offset(succ_len))) + } else { + (c, pstr_loc_as_cell!(succ_len)) + } + } + } + + // copies only the string, not its tail. returns the cell index of + // the tail location + pub(crate) fn copy_pstr_within(&mut self, pstr_loc: usize) -> Result { + let (s, tail_loc) = self.scan_slice_to_str(pstr_loc); + let s_len = s.len(); + + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); + + let align_offset = unsafe { + self.inner.ptr + .add(self.inner.byte_len + s_len) + .align_offset(ALIGN_CELL) + }; + + let align_offset = if align_offset == 0 { + ALIGN_CELL + } else { + align_offset + }; + + let copy_size = s_len + align_offset; + + unsafe { + loop { + if self.free_space() >= copy_size { + let slice = std::slice::from_raw_parts_mut( + self.inner.ptr, + self.inner.byte_len + s_len, + ); + + slice.copy_within( + pstr_loc .. pstr_loc + s_len, + self.inner.byte_len, + ); + + ptr::write_bytes( + self.inner.ptr.add(self.inner.byte_len + s_len), + 0u8, + align_offset, + ); + + self.inner.byte_len += copy_size; + self.pstr_vec.resize(self.cell_len(), true); + + break; + } else if !self.grow() { + return Err(self.resource_error_offset()); + } + } + } + + Ok(tail_loc) + } + + // src is a cell-indexed range. + pub(crate) fn copy_slice_to_end>(&mut self, src: R) -> Result<(), usize> { + let range = self.slice_range(src); + let len = range.end - range.start; + + unsafe { + loop { + if self.free_space() >= len { + ptr::copy_nonoverlapping( + self.inner.ptr.add(heap_index!(range.start)), + self.inner.ptr.add(self.inner.byte_len), + heap_index!(len), + ); + + self.pstr_vec.resize(self.cell_len() + len, false); + self.inner.byte_len += heap_index!(len); + + break; + } else if !self.grow() { + return Err(self.resource_error_offset()); + } + } + } + + Ok(()) + } + + // assumes the string will be allocated on a ALIGN_CELL-byte boundary + pub(crate) const fn compute_pstr_size(src: &str) -> usize { + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); + + if src.is_empty() { + return 0; + } + + let mut byte_size = 0; + let mut null_idx = 0; + + loop { + let src_bytes = src.as_bytes(); + + while null_idx < src_bytes.len() { + if src_bytes[null_idx] == 0u8 { + break; + } + + null_idx += 1; + } + + byte_size += (null_idx & !(ALIGN_CELL - 1)) + ALIGN_CELL; + + if (null_idx + 1) % ALIGN_CELL == 0 { + byte_size += 2 * mem::size_of::(); + } else { + byte_size += mem::size_of::(); + } + + if null_idx + 1 >= src.len() { + break; + } else { + null_idx += 1; + } + } + + byte_size + } + + pub(crate) const fn compute_functor_byte_size(functor: &[FunctorElement]) -> usize { + let mut byte_size = 0; + let mut idx = 0; + + while idx < functor.len() { + match &functor[idx] { + &FunctorElement::InnerFunctor(inner_cell_size, ref _inner_functor) => { + byte_size += inner_cell_size as usize * mem::size_of::(); + } + FunctorElement::AbsoluteCell(_cell) | FunctorElement::Cell(_cell) => { + byte_size += mem::size_of::(); + } + &FunctorElement::String(cell_len, _) => { + byte_size += cell_len as usize * mem::size_of::(); + } + } + + idx += 1; + } + + byte_size + } + + pub(crate) fn functor_writer( + functor: Vec, + ) -> impl FnMut(&mut Heap) -> Result { + let size = Heap::compute_functor_byte_size(&functor); + let mut functor_writer = ReservedHeapSection::functor_writer(functor); + + move |heap| { + let mut writer = heap.reserve(size)?; + let heap_byte_len = *writer.heap_byte_len; + let bytes_written = writer.write_with(&mut functor_writer); + + Ok(if cell_index!(bytes_written) > 1 { + str_loc_as_cell!(cell_index!(heap_byte_len)) + } else { + heap_loc_as_cell!(cell_index!(heap_byte_len)) + }) + } + } + + #[inline] + pub(crate) fn truncate(&mut self, cell_offset: usize) { + self.inner.byte_len = heap_index!(cell_offset); + self.pstr_vec.truncate(cell_offset); + } +} + + + +pub(crate) struct PStrSegmentIter<'a> { + string_buf: &'a str, +} + +impl<'a> PStrSegmentIter<'a> { + fn from(heap: &'a Heap, pstr_loc: usize) -> Self { + debug_assert!(pstr_loc <= heap.inner.byte_len); + + let string_buf = unsafe { + let char_ptr = heap.inner.ptr.add(pstr_loc); + let slice = std::slice::from_raw_parts(char_ptr, heap.inner.byte_len - pstr_loc); + std::str::from_utf8_unchecked(&slice) + }; + + PStrSegmentIter { string_buf } + } +} + +impl<'a> Iterator for PStrSegmentIter<'a> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + self.string_buf.chars().next().and_then(|c| { + if c == '\u{0}' { + None + } else { + self.string_buf = &self.string_buf[c.len_utf8() ..]; + Some(c) + } + }) + } +} + +impl MachineState { + pub(crate) fn allocate_pstr(&mut self, src: &str) -> Result { + match self.heap.allocate_pstr(src)? { + None => Ok(empty_list_as_cell!()), + Some(PStrWriteInfo { pstr_loc, .. }) => Ok(pstr_loc_as_cell!(pstr_loc)), + } + } + + // note that allocate_cstr does emit a tail cell to the string + // (completing it with the empty list), allocate_pstr does not, in + // any incarnation. + pub(crate) fn allocate_cstr(&mut self, src: &str) -> Result { + match self.heap.allocate_pstr(src)? { + None => Ok(empty_list_as_cell!()), + Some(PStrWriteInfo { pstr_loc, .. }) => { + self.heap.push_cell(empty_list_as_cell!())?; + Ok(pstr_loc_as_cell!(pstr_loc)) + } + } + } +} + +pub trait SizedHeap: Index { + // return the size of the instance in cells + fn cell_len(&self) -> usize; + + // return a pointer to the heap string and the cell index of its tail + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize); + + // return true iff a partial string is stored at cell_offset. + fn pstr_at(&self, cell_offset: usize) -> bool; +} + +pub trait SizedHeapMut: IndexMut + SizedHeap { +} + +impl Index for Heap { + type Output = HeapCellValue; + + fn index(&self, idx: usize) -> &Self::Output { + unsafe { &*(self.inner.ptr as *const HeapCellValue).add(idx) } + } +} + +impl IndexMut for Heap { + fn index_mut(&mut self, idx: usize) -> &mut Self::Output { + unsafe { &mut *(self.inner.ptr as *mut HeapCellValue).add(idx) } + } +} + +impl SizedHeap for Heap { + fn cell_len(&self) -> usize { + self.cell_len() + } + + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { + let (s, tail_cell_offset) = scan_slice_to_str( + unsafe { self.inner.ptr.add(slice_loc) }, + &self.pstr_vec.as_bitslice()[cell_index!(slice_loc) ..], + ); + + (s, cell_index!(slice_loc) + tail_cell_offset) + } + + fn pstr_at(&self, cell_offset: usize) -> bool { + self.pstr_vec[cell_offset] + } +} + +impl SizedHeapMut for Heap {} + +impl<'a> SizedHeap for HeapView<'a> { + fn cell_len(&self) -> usize { + self.slice_cell_len + } + + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { + let (s, tail_cell_offset) = scan_slice_to_str( + unsafe { self.slice.add(slice_loc) }, + &self.pstr_slice[cell_index!(slice_loc) ..], + ); + + (s, cell_index!(slice_loc) + tail_cell_offset) + } + + fn pstr_at(&self, cell_offset: usize) -> bool { + self.pstr_slice[cell_offset] + } +} + +impl<'a> SizedHeap for HeapViewMut<'a> { + fn cell_len(&self) -> usize { + self.slice_cell_len + } + + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { + let (s, tail_cell_offset) = scan_slice_to_str( + unsafe { self.slice.add(slice_loc) }, + &self.pstr_slice[cell_index!(slice_loc) ..], + ); + + (s, cell_index!(slice_loc) + tail_cell_offset) + } + + fn pstr_at(&self, cell_offset: usize) -> bool { + self.pstr_slice[cell_offset] + } +} + +impl<'a> SizedHeapMut for HeapViewMut<'a> {} + // sometimes we need to dereference variables that are found only in // the heap without access to the full WAM (e.g., while detecting // cycles in terms), and which therefore may only point other cells in // the heap (thanks to the design of the WAM). -pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue { +pub fn heap_bound_deref(heap: &impl SizedHeap, mut value: HeapCellValue) -> HeapCellValue { loop { let new_value = read_heap_cell!(value, (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { @@ -111,7 +1288,7 @@ pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> Hea } } -pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue { +pub fn heap_bound_store(heap: &impl SizedHeap, value: HeapCellValue) -> HeapCellValue { read_heap_cell!(value, (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { heap[h] @@ -123,123 +1300,34 @@ pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCel } #[allow(dead_code)] -pub fn print_heap_terms<'a, I: Iterator>(heap: I, h: usize) { +pub fn print_heap_terms<'a, I: Iterator>(heap: I, h: usize) { for (index, term) in heap.enumerate() { println!("{} : {:?}", h + index, term); } } -#[inline] -pub(crate) fn put_complete_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue { - match allocate_pstr(heap, s, atom_tbl) { - Some(h) => { - heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr. - - if heap.len() == h + 1 { - let pstr_atom = cell_as_atom!(heap[h]); - heap[h] = atom_as_cstr_cell!(pstr_atom); - heap_loc_as_cell!(h) - } else { - heap.push(empty_list_as_cell!()); - pstr_loc_as_cell!(h) - } - } - None => { - let h = heap.len(); - heap.push(empty_list_as_cell!()); - heap_loc_as_cell!(h) - } - } -} - -#[inline] -pub(crate) fn put_partial_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue { - match allocate_pstr(heap, s, atom_tbl) { - Some(h) => { - pstr_loc_as_cell!(h) - } - None => { - empty_list_as_cell!() - } - } -} - -#[inline] -pub(crate) fn allocate_pstr(heap: &mut Heap, mut src: &str, atom_tbl: &AtomTable) -> Option { - let orig_h = heap.len(); - - loop { - if src.is_empty() { - return if orig_h == heap.len() { - None - } else { - let tail_h = heap.len() - 1; - heap[tail_h] = heap_loc_as_cell!(tail_h); - - Some(orig_h) - }; - } - - let h = heap.len(); - - let (pstr, rest_src) = match PartialString::new(src, atom_tbl) { - Some(tuple) => tuple, - None => { - if src.len() > '\u{0}'.len_utf8() { - src = &src['\u{0}'.len_utf8()..]; - continue; - } else if orig_h == h { - return None; - } else { - heap[h - 1] = heap_loc_as_cell!(h - 1); - return Some(orig_h); - } - } - }; - - heap.push(string_as_pstr_cell!(pstr)); - - if !rest_src.is_empty() { - heap.push(pstr_loc_as_cell!(h + 2)); - src = rest_src; - } else { - heap.push(heap_loc_as_cell!(h + 1)); - return Some(orig_h); - } - } -} - -pub fn filtered_iter_to_heap_list>( +pub fn sized_iter_to_heap_list>( heap: &mut Heap, + size: usize, values: impl Iterator, - filter_fn: impl Fn(&Heap, HeapCellValue) -> bool, -) -> usize { - let head_addr = heap.len(); - let mut h = head_addr; +) -> Result { + if size > 0 { + let h = heap.cell_len(); + let mut writer = heap.reserve(1 + 2 * size)?; - for value in values { - let value = value.into(); + writer.write_with(|section| { + for (idx, value) in values.enumerate() { + section.push_cell(list_loc_as_cell!(h + 1 + 2 * idx)); + section.push_cell(value.into()); + } - if filter_fn(heap, value) { - heap.push(list_loc_as_cell!(h + 1)); - heap.push(value); + section.push_cell(empty_list_as_cell!()); + }); - h += 2; - } + Ok(heap_loc_as_cell!(h)) + } else { + Ok(empty_list_as_cell!()) } - - heap.push(empty_list_as_cell!()); - - head_addr -} - -#[inline(always)] -pub fn iter_to_heap_list(heap: &mut Heap, values: Iter) -> usize -where - Iter: Iterator, - SrcT: Into, -{ - filtered_iter_to_heap_list(heap, values, |_, _| true) } pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option { diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index 79a8a1cf..90725d61 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -3,15 +3,14 @@ use std::collections::BTreeMap; use crate::atom_table; use crate::heap_iter::{stackful_post_order_iter, NonListElider}; -use crate::machine::machine_indices::VarKey; use crate::machine::mock_wam::CompositeOpDir; use crate::machine::{ ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS, }; -use crate::parser::ast::{Var, VarPtr}; -use crate::parser::parser::{Parser, Tokens}; -use crate::read::{write_term_to_heap, TermWriteResult}; +use crate::parser::ast::{TermWriteResult, Var}; +use crate::parser::lexer::LexerParser; +use crate::parser::parser::Tokens; use crate::types::UntypedArenaPtr; use dashu::{Integer, Rational}; @@ -171,29 +170,22 @@ impl Term { pub(crate) fn from_heapcell( machine: &mut Machine, heap_cell: HeapCellValue, - var_names: &mut IndexMap, + var_names: &mut IndexMap, ) -> Self { // Adapted from MachineState::read_term_from_heap let mut term_stack = vec![]; - let iter = stackful_post_order_iter::( + + machine.machine_st.heap[0] = heap_cell; + + let mut iter = stackful_post_order_iter::( &mut machine.machine_st.heap, &mut machine.machine_st.stack, - heap_cell, + 0, ); let mut anon_count: usize = 0; - let var_ptr_cmp = |a, b| match a { - Var::Named(name_a) => match b { - Var::Named(name_b) => name_a.cmp(&name_b), - _ => Ordering::Less, - }, - _ => match b { - Var::Named(_) => Ordering::Greater, - _ => Ordering::Equal, - }, - }; - for addr in iter { + while let Some(addr) = iter.next() { let addr = unmark_cell_bits!(addr); read_heap_cell!(addr, @@ -242,29 +234,28 @@ impl Term { term_stack.push(list); } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - let var = var_names.get(&addr).map(|x| x.borrow().clone()); + let var = var_names.get(&addr).cloned(); match var { - Some(Var::Named(name)) => term_stack.push(Term::Var(name)), + Some(name) => term_stack.push(Term::Var(name.to_string())), _ => { let anon_name = loop { // Generate a name for the anonymous variable let anon_name = count_to_letter_code(anon_count); // Find if this name is already being used - var_names.sort_by(|_, a, _, b| { - var_ptr_cmp(a.borrow().clone(), b.borrow().clone()) - }); + var_names.sort_by(|_, a, _, b| a.cmp(b)); + let binary_result = var_names.binary_search_by(|_,a| { - let var_ptr = Var::Named(anon_name.clone()); - var_ptr_cmp(a.borrow().clone(), var_ptr.clone()) + let a: &String = a.as_ref(); + a.cmp(&anon_name) }); match binary_result { Ok(_) => anon_count += 1, // Name already used Err(_) => { // Name not used, assign it to this variable - let var_ptr = VarPtr::from(Var::Named(anon_name.clone())); - var_names.insert(addr, var_ptr); + let var = anon_name.clone(); + var_names.insert(addr, Var::from(var)); break anon_name; }, } @@ -276,9 +267,6 @@ impl Term { (HeapCellValueTag::F64, f) => { term_stack.push(Term::Float((*f).into())); } - (HeapCellValueTag::Char, c) => { - term_stack.push(Term::Atom(c.into())); - } (HeapCellValueTag::Fixnum, n) => { term_stack.push(Term::Integer(n.into())); } @@ -310,9 +298,6 @@ impl Term { ); } } - (HeapCellValueTag::CStr, s) => { - term_stack.push(Term::String(s.as_str().to_string())); - } (HeapCellValueTag::Atom, (name, arity)) => { //let h = iter.focus().value() as usize; //let mut arity = arity; @@ -354,8 +339,9 @@ impl Term { term_stack.push(Term::Compound(name.as_str().to_string(), subterms)); } } - (HeapCellValueTag::PStr, atom) => { + (HeapCellValueTag::PStrLoc, pstr_loc) => { let tail = term_stack.pop().unwrap(); + let char_iter = iter.base_iter.heap.char_iter(pstr_loc); match tail { Term::Atom(atom) => { @@ -363,21 +349,18 @@ impl Term { term_stack.push(Term::String(atom.as_str().to_string())); } }, + Term::List(l) if l.is_empty() => { + term_stack.push(Term::String(char_iter.collect())); + } Term::List(l) => { - let mut list: Vec = atom - .as_str() - .to_string() - .chars() + let mut list: Vec = char_iter .map(|x| Term::Atom(x.to_string())) .collect(); list.extend(l.into_iter()); term_stack.push(Term::List(list)); }, _ => { - let mut list: Vec = atom - .as_str() - .to_string() - .chars() + let mut list: Vec = char_iter .map(|x| Term::Atom(x.to_string())) .collect(); @@ -403,19 +386,6 @@ impl Term { } } } - // I dont know if this is needed here. - /* - (HeapCellValueTag::PStrLoc, h) => { - let atom = cell_as_atom_cell!(iter.heap[h]).get_name(); - let tail = term_stack.pop().unwrap(); - - term_stack.push(Term::PartialString( - Cell::default(), - atom.as_str().to_owned(), - Box::new(tail), - )); - } - */ _ => { unreachable!(); } @@ -432,7 +402,7 @@ pub struct QueryState<'a> { machine: &'a mut Machine, term: TermWriteResult, stub_b: usize, - var_names: IndexMap, + var_names: IndexMap, called: bool, } @@ -472,7 +442,7 @@ impl Iterator for QueryState<'_> { if let Err(resource_err_loc) = machine .machine_st .heap - .append(&machine.machine_st.ball.stub) + .append(machine.machine_st.ball.stub.splice(..)) { return Some(Err(Term::from_heapcell( machine, @@ -589,13 +559,13 @@ impl Machine { or_frame.prelude.attr_var_queue_len = 0; self.machine_st.b = stub_b; - self.machine_st.hb = self.machine_st.heap.len(); + self.machine_st.hb = self.machine_st.heap.cell_len(); self.machine_st.block = stub_b; } /// Runs a query. pub fn run_query(&mut self, query: impl Into) -> QueryState { - let mut parser = Parser::new( + let mut parser = LexerParser::new( Stream::from_owned_string(query.into(), &mut self.machine_st.arena), &mut self.machine_st, ); diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index f62e01f6..9ac56972 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -2,7 +2,6 @@ use crate::forms::*; use crate::machine::loader::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::machine::preprocessor::*; use crate::machine::term_stream::*; use crate::machine::*; use crate::parser::ast::*; @@ -434,19 +433,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { self.retract_local_clauses_impl(clause_clause_compilation_target, key, clause_locs); } - pub(super) fn try_term_to_tl( - &mut self, - term: FocusedHeap, - preprocessor: &mut Preprocessor, - ) -> Result { - let tl = preprocessor.try_term_to_tl(self, term)?; - - Ok(match tl { - TopLevel::Fact(fact, var_data) => PredicateClause::Fact(fact, var_data), - TopLevel::Rule(rule, var_data) => PredicateClause::Rule(rule, var_data), - }) - } - #[inline] pub(super) fn remove_module_op_exports(&mut self) { for (mut op_decl, record) in self.payload.module_op_exports.drain(0..) { diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 40800f97..18a4c973 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -20,6 +20,25 @@ use std::convert::TryFrom; use std::fmt; use std::ops::{Deref, DerefMut}; +impl TermWriteResult { + pub(super) fn from(heap: &mut Heap, value: HeapCellValue) -> Result { + let focus = heap.index_of(value)?; + let mut stack = Stack::uninitialized(); + + heap[0] = value; + + let inverse_var_locs = inverse_var_locs_from_iter( + stackful_preorder_iter::( + heap, + &mut stack, + 0, + ), + ); + + Ok(Self { focus, inverse_var_locs }) + } +} + /* * The loader compiles Prolog terms read from a TermStream instance, * which may be incremental or monolithic. The monolithic term stream @@ -176,18 +195,18 @@ impl CompilationTarget { } pub struct PredicateQueue { - pub(super) predicates: Vec, - pub(super) compilation_target: CompilationTarget, + pub predicates: Vec, + pub compilation_target: CompilationTarget, } impl PredicateQueue { #[inline] - pub(super) fn push(&mut self, clause: FocusedHeap) { - self.predicates.push(clause); + pub(super) fn push(&mut self, term_write_result: TermWriteResult) { + self.predicates.push(term_write_result); } #[inline] - pub(crate) fn first(&self) -> Option<&FocusedHeap> { + pub(crate) fn first(&self) -> Option<&TermWriteResult> { self.predicates.first() } @@ -381,7 +400,6 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { let repo_len = loader.wam_prelude.code.len(); loader.payload.retraction_info.reset(repo_len); - loader.remove_module_op_exports(); Ok(loader.payload.compilation_target) @@ -399,7 +417,7 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { #[inline(always)] fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { - loader.term_stream.parser.lexer.machine_st + loader.term_stream.lexer_parser.machine_st } #[inline(always)] @@ -491,23 +509,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } - pub(crate) fn copy_term_from_heap(&mut self, cell: HeapCellValue) -> FocusedHeap { - use crate::iterators::fact_iterator; - - let mut term = FocusedHeap::empty(); - let mut stack = Stack::uninitialized(); - let machine_st = LS::machine_st(&mut self.payload); - - term.copy_term_from_machine_heap(machine_st, cell); - term.inverse_var_locs = inverse_var_locs_from_iter( - fact_iterator::( - &mut term.heap, - &mut stack, - 0, - ), - ); - - term + #[inline] + pub(super) fn machine_heap(&mut self) -> &mut Heap { + &mut LS::machine_st(&mut self.payload).heap } pub(crate) fn load(mut self) -> Result { @@ -525,14 +529,26 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target); let mut term = load_state.term_stream.next(&composite_op_dir)?; + let predicate_focus_opt = load_state.predicates.first().map(|term_write_result| { + term_write_result.focus + }); - if !term.is_consistent(&load_state.predicates) { - self.compile_and_submit()?; + let machine_st = LS::machine_st(&mut self.payload); + let term_key_opt = clause_predicate_key(&machine_st.heap, term.focus); + + if let Some(predicate_focus) = predicate_focus_opt { + let predicate_key_opt = clause_predicate_key(&machine_st.heap, predicate_focus); + + debug_assert!(predicate_key_opt.is_some()); + + if term_key_opt != predicate_key_opt { + self.compile_and_submit()?; + } } - if Some(atom!(":-")) == term.name(term.focus) && term.arity(term.focus) == 1 { - let new_focus = term.nth_arg(term.focus, 1).unwrap(); - let term = term.as_ref_mut(new_focus); + if Some((atom!(":-"), 1)) == term_key_opt { + let machine_st = LS::machine_st(&mut self.payload); + term.focus = term_nth_arg(&machine_st.heap, term.focus, 1).unwrap(); return Ok(Some(setup_declaration(self, term)?)); } @@ -1055,48 +1071,55 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let machine_st = LS::machine_st(&mut self.payload); let cell = machine_st[r]; - let export_list = FocusedHeapRefMut::from_cell(&mut machine_st.heap, cell); + let focus = machine_st.heap.cell_len(); + machine_st.heap.push_cell(cell) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + + let export_list = FocusedHeapRefMut { heap: &mut machine_st.heap, focus }; let export_list = setup_module_export_list(export_list)?; Ok(export_list.into_iter().collect()) } - fn clause_clause(&mut self, cell: HeapCellValue) -> Result { + fn clause_clause(&mut self, cell: HeapCellValue) -> Result { let machine_st = LS::machine_st(&mut self.payload); - let mut term = FocusedHeap::empty(); + let focus = machine_st.heap.cell_len(); read_heap_cell!(cell, (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) .get_name_and_arity(); - term.copy_term_from_machine_heap(machine_st, cell); - let focus = term.heap.len(); + let mut writer = machine_st.heap.reserve(4) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - term.heap.push(str_loc_as_cell!(focus+1)); - term.heap.push(atom_as_cell!(atom!("clause"), 2)); + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(focus+1)); + section.push_cell(atom_as_cell!(atom!("clause"), 2)); - match (name, arity) { - (atom!(":-"), 2) => { - term.heap.push(heap_loc_as_cell!(2)); - term.heap.push(heap_loc_as_cell!(3)); + match (name, arity) { + (atom!(":-"), 2) => { + section.push_cell(heap_loc_as_cell!(s+1)); + section.push_cell(heap_loc_as_cell!(s+2)); + } + _ => { + section.push_cell(str_loc_as_cell!(s)); + section.push_cell(atom_as_cell!(atom!("true"))); + } } - _ => { - term.heap.push(heap_loc_as_cell!(0)); - term.heap.push(atom_as_cell!(atom!("true"))); - } - } - - term.focus = focus; + }); } (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { - term.heap.push(str_loc_as_cell!(1)); - term.heap.push(atom_as_cell!(atom!("clause"), 2)); - term.heap.push(atom_as_cell!(name)); - term.heap.push(atom_as_cell!(atom!("true"))); + let mut writer = machine_st.heap.reserve(4) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - term.focus = 0; + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(focus+1)); + section.push_cell(atom_as_cell!(atom!("clause"), 2)); + section.push_cell(atom_as_cell!(name)); + section.push_cell(atom_as_cell!(atom!("true"))); + }); } else { return Err(CompilationError::InadmissibleFact); } @@ -1106,11 +1129,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } ); - let value = term.heap[term.focus]; - term.inverse_var_locs = inverse_var_locs_from_iter( - eager_stackful_preorder_iter(&mut term.heap, value), - ); - Ok(term) + Ok(TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus)) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?) } fn add_extensible_predicate_declaration( @@ -1330,18 +1350,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> { let machine_st = LS::machine_st(&mut self.payload); - let term = FocusedHeapRefMut::from_cell(&mut machine_st.heap, value); + let key_opt = clause_predicate_key_from_heap(&machine_st.heap, value); - let name_opt = ClauseInfo::name(&term); - - if let Some(predicate_name) = name_opt { - let arity = ClauseInfo::arity(&term); + if let Some((predicate_name, predicate_arity)) = key_opt { let predicates_compilation_target = self.payload.predicates.compilation_target; let is_dynamic = self .wam_prelude .indices - .get_predicate_skeleton(&predicates_compilation_target, &(predicate_name, arity)) + .get_predicate_skeleton( + &predicates_compilation_target, + &(predicate_name, predicate_arity), + ) .map(|skeleton| skeleton.core.is_dynamic) .unwrap_or(false); @@ -1574,11 +1594,14 @@ impl Machine { pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult { let value = self.machine_st.registers[1]; + let term = resource_error_call_result!( + self.machine_st, + TermWriteResult::from(&mut self.machine_st.heap, value) + ); + let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let add_clause = || { - let term = loader.copy_term_from_heap(value); - loader.incremental_compile_clause( (atom!("term_expansion"), 2), term, @@ -1599,31 +1622,40 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st.registers[1]))); - let value = self.machine_st.registers[2]; - let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); - let compilation_target = match target_module_name { atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(target_module_name), }; - let add_clause = || { - let term = loader.copy_term_from_heap(value); + let value = self.machine_st.registers[2]; + let term = resource_error_call_result!( + self.machine_st, + TermWriteResult::from(&mut self.machine_st.heap, value) + ); - let indexing_arg = match term.name(term.focus) { - Some(atom!(":-")) => term.nth_arg(term.focus, 1).and_then(|h| term.nth_arg(h, 1)), - Some(_) => term.nth_arg(term.focus, 1), + let add_clause = || { + let indexing_arg_opt = match term_predicate_key(&self.machine_st.heap, term.focus) { + Some((atom!(":-"), _)) => { + term_nth_arg(&self.machine_st.heap, term.focus, 1).and_then(|h| { + term_nth_arg(&self.machine_st.heap, h, 1) + }) + } + Some(_) => term_nth_arg(&self.machine_st.heap, term.focus, 1), None => None, }; - if let Some(indexing_term_loc) = indexing_arg { - if let Some(indexing_name) = term.name(indexing_term_loc) { - loader - .wam_prelude - .indices - .goal_expansion_indices - .insert((indexing_name, term.arity(indexing_term_loc))); - } + let key_opt = indexing_arg_opt.and_then(|indexing_term_loc| { + term_predicate_key(&self.machine_st.heap, indexing_term_loc) + }); + + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); + + if let Some((name, arity)) = key_opt { + loader + .wam_prelude + .indices + .goal_expansion_indices + .insert((name, arity)); } loader.incremental_compile_clause( @@ -1929,19 +1961,16 @@ impl Machine { let stub_gen = || functor_stub(key.0, key.1); let assert_clause = self.machine_st.registers[2]; - let (name, arity) = { - let term = FocusedHeapRefMut::from_cell(&mut self.machine_st.heap, assert_clause); - (ClauseInfo::name(&term), ClauseInfo::arity(&term)) - }; + let key_opt = clause_predicate_key_from_heap(&self.machine_st.heap, assert_clause); - let mut compile_assert = |assert_clause, name, arity| { + let mut compile_assert = |assert_clause, key_opt| { let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = Loader::new(self, LiveTermStream::new(ListingSource::User)); loader.payload.compilation_target = compilation_target; - let name = if let Some(name) = name { - name + let (name, arity) = if let Some(key) = key_opt { + key } else { return Err(SessionError::from(CompilationError::InvalidRuleHead)); }; @@ -1979,11 +2008,16 @@ impl Machine { // if a new predicate was just created, make it dynamic. loader.add_dynamic_predicate(compilation_target, name, arity)?; - let asserted_clause = loader.copy_term_from_heap(assert_clause); + + let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload); + // let asserted_clause = loader.copy_term_from_heap(assert_clause); + + let term = TermWriteResult::from(&mut machine_st.heap, assert_clause) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; loader.incremental_compile_clause( (name, arity), - asserted_clause, + term, compilation_target, false, append_or_prepend, @@ -2004,7 +2038,7 @@ impl Machine { LiveLoadAndMachineState::evacuate(loader) }; - match compile_assert(assert_clause, name, arity) { + match compile_assert(assert_clause, key_opt) { Ok(_) => Ok(()), Err(SessionError::CompilationError( CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact, @@ -2206,11 +2240,21 @@ impl Machine { }; let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); + let predicate_focus_opt = loader.payload.predicates.first().map(|term_write_result| { + term_write_result.focus + }); + + let is_consistent = if let Some(predicate_focus) = predicate_focus_opt { + let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload); + clause_predicate_key(&machine_st.heap, predicate_focus) == Some(key) + } else { + true + }; LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = (!loader.payload.predicates.is_empty() - && loader.payload.predicates.compilation_target != compilation_target) - || !key.is_consistent(&loader.payload.predicates); + && loader.payload.predicates.compilation_target != compilation_target) + || !is_consistent; let result = LiveLoadAndMachineState::evacuate(loader); self.restore_load_state_payload(result) @@ -2278,29 +2322,36 @@ impl Machine { .get_meta_predicate_spec(predicate_name, arity, &compilation_target) { Some(meta_specs) => { - let term_loc = self.machine_st.heap.len(); + let term_loc = self.machine_st.heap.cell_len(); - self.machine_st - .heap - .push(atom_as_cell!(predicate_name, arity)); - self.machine_st - .heap - .extend(meta_specs.iter().map(|meta_spec| match meta_spec { - MetaSpec::Minus => atom_as_cell!(atom!("+")), - MetaSpec::Plus => atom_as_cell!(atom!("-")), - MetaSpec::Either => atom_as_cell!(atom!("?")), - MetaSpec::Colon => atom_as_cell!(atom!(":")), - MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { - fixnum_as_cell!(Fixnum::build_with(*arg_num as i64)) - } - })); + let mut writer = match self.machine_st.heap.reserve(3 + meta_specs.len()) { + Ok(writer) => writer, + Err(err_loc) => { + self.machine_st.throw_resource_error(err_loc); + return; + } + }; - let heap_loc = self.machine_st.heap.len(); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(predicate_name, arity)); - self.machine_st - .heap - .push(atom_as_cell!(atom!("meta_predicate"), 1)); - self.machine_st.heap.push(str_loc_as_cell!(term_loc)); + for meta_spec in meta_specs.iter() { + section.push_cell(match meta_spec { + MetaSpec::Minus => atom_as_cell!(atom!("+")), + MetaSpec::Plus => atom_as_cell!(atom!("-")), + MetaSpec::Either => atom_as_cell!(atom!("?")), + MetaSpec::Colon => atom_as_cell!(atom!(":")), + MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { + fixnum_as_cell!(Fixnum::build_with(*arg_num as i64)) + } + }); + } + + section.push_cell(atom_as_cell!(atom!("meta_predicate"), 1)); + section.push_cell(str_loc_as_cell!(term_loc)); + }); + + let heap_loc = self.machine_st.heap.cell_len() - 2; unify!( self.machine_st, @@ -2411,13 +2462,16 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> { } let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); - let value = machine_st[term_reg]; + let value = machine_st.store(MachineState::deref(&machine_st, machine_st[term_reg])); self.add_clause_clause_if_dynamic(value)?; - let term = self.copy_term_from_heap(value); - self.payload.term_stream.term_queue.push_back(term); + let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); + let term = TermWriteResult::from(&mut machine_st.heap, value) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + + self.payload.term_stream.term_queue.push_back(term); self.load() } } diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index ea8db552..5017cb78 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -5,6 +5,7 @@ use crate::parser::ast::*; #[cfg(feature = "ffi")] use crate::ffi::FFIError; use crate::forms::*; +use crate::functor_macro::*; use crate::machine::heap::*; use crate::machine::loader::CompilationTarget; use crate::machine::machine_state::*; @@ -12,20 +13,13 @@ use crate::machine::streams::*; use crate::machine::system_calls::BrentAlgState; use crate::types::*; -pub type MachineStub = Vec; +pub type MachineStub = Vec; pub type MachineStubGen = Box MachineStub>; -#[derive(Debug, Clone, Copy)] -enum ErrorProvenance { - Constructed, // if constructed, offset the addresses. - Received, // otherwise, preserve the addresses. -} - #[derive(Debug)] pub(crate) struct MachineError { stub: MachineStub, location: Option, - from: ErrorProvenance, } // from 7.12.2 b) of 13211-1:1995 @@ -91,45 +85,26 @@ impl TypeError for HeapCellValue { fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { let stub = functor!( atom!("type_error"), - [atom(valid_type.as_atom()), cell(self)] + [atom_as_cell((valid_type.as_atom())), cell(self)] ); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } } impl TypeError for MachineStub { - fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { + fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { let stub = functor!( atom!("type_error"), - [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)], - [self] + [atom_as_cell((valid_type.as_atom())), functor(self)] ); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, - } - } -} - -impl TypeError for FunctorStub { - fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { - let stub = functor!( - atom!("type_error"), - [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)], - [self] - ); - - MachineError { - stub, - location: None, - from: ErrorProvenance::Constructed, } } } @@ -139,15 +114,14 @@ impl TypeError for Number { let stub = functor!( atom!("type_error"), [ - atom(valid_type.as_atom()), - number(&mut machine_st.arena, self) + atom_as_cell((valid_type.as_atom())), + number(self, (&mut machine_st.arena)) ] ); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } } @@ -171,16 +145,15 @@ impl PermissionError for Atom { let stub = functor!( atom!("permission_error"), [ - atom(perm.as_atom()), - atom(index_atom), - cell(atom_as_cell!(self)) + atom_as_cell((perm.as_atom())), + atom_as_cell(index_atom), + atom_as_cell(self) ] ); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } } @@ -214,13 +187,12 @@ impl PermissionError for HeapCellValue { let stub = functor!( atom!("permission_error"), - [atom(perm.as_atom()), atom(index_atom), cell(cell)] + [atom_as_cell((perm.as_atom())), atom_as_cell(index_atom), cell(cell)] ); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } } @@ -228,24 +200,22 @@ impl PermissionError for HeapCellValue { impl PermissionError for MachineStub { fn permission_error( self, - machine_st: &mut MachineState, + _machine_st: &mut MachineState, index_atom: Atom, perm: Permission, ) -> MachineError { let stub = functor!( atom!("permission_error"), [ - atom(perm.as_atom()), - atom(index_atom), - str(machine_st.heap.len(), 0) - ], - [self] + atom_as_cell((perm.as_atom())), + atom_as_cell(index_atom), + functor(self) + ] ); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, } } } @@ -256,32 +226,11 @@ pub(super) trait DomainError { impl DomainError for HeapCellValue { fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { - let stub = functor!(atom!("domain_error"), [atom(error.as_atom()), cell(self)]); + let stub = functor!(atom!("domain_error"), [atom_as_cell((error.as_atom())), cell(self)]); MachineError { stub, location: None, - from: ErrorProvenance::Received, - } - } -} - -impl DomainError for FunctorStub { - fn domain_error( - self, - machine_st: &mut MachineState, - valid_type: DomainErrorType, - ) -> MachineError { - let stub = functor!( - atom!("domain_error"), - [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)], - [self] - ); - - MachineError { - stub, - location: None, - from: ErrorProvenance::Constructed, } } } @@ -290,26 +239,33 @@ impl DomainError for Number { fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { let stub = functor!( atom!("domain_error"), - [atom(error.as_atom()), number(&mut machine_st.arena, self)] + [atom_as_cell((error.as_atom())), number(self, (&mut machine_st.arena))] ); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } } -pub(super) type FunctorStub = [HeapCellValue; 3]; +impl DomainError for MachineStub { + fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { + let stub = functor!( + atom!("domain_error"), + [atom_as_cell((error.as_atom())), functor(self)] + ); + + MachineError { + stub, + location: None, + } + } +} #[inline(always)] -pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub { - [ - atom_as_cell!(atom!("/"), 2), - atom_as_cell!(name), - fixnum_as_cell!(Fixnum::build_with(arity as i64)), - ] +pub(super) fn functor_stub(name: Atom, arity: usize) -> MachineStub { + functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]) } impl MachineState { @@ -320,17 +276,15 @@ impl MachineState { MachineError { stub, location: None, - from: ErrorProvenance::Received, } } pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError { - let stub = functor!(atom!("evaluation_error"), [atom(eval_error.as_atom())]); + let stub = functor!(atom!("evaluation_error"), [atom_as_cell((eval_error.as_atom()))]); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } @@ -339,18 +293,17 @@ impl MachineState { ResourceError::FiniteMemory(size_requested) => { functor!( atom!("resource_error"), - [atom(atom!("finite_memory")), cell(size_requested)] + [atom_as_cell((atom!("finite_memory"))), cell(size_requested)] ) } ResourceError::OutOfFiles => { - functor!(atom!("resource_error"), [atom(atom!("file_descriptors"))]) + functor!(atom!("resource_error"), [atom_as_cell((atom!("file_descriptors")))]) } }; MachineError { stub, location: None, - from: ErrorProvenance::Received, } } @@ -367,13 +320,12 @@ impl MachineState { ExistenceError::Module(name) => { let stub = functor!( atom!("existence_error"), - [atom(atom!("source_sink")), atom(name)] + [atom_as_cell((atom!("source_sink"))), atom_as_cell(name)] ); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } ExistenceError::QualifiedProcedure { @@ -381,36 +333,30 @@ impl MachineState { name, arity, } => { - let h = self.heap.len(); - - let ind_stub = functor!(atom!("/"), [atom(name), fixnum(arity)]); - let res_stub = functor!(atom!(":"), [atom(module_name), str(h + 3, 0)], [ind_stub]); + let ind_stub = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]); + let res_stub = functor!(atom!(":"), [atom_as_cell(module_name), functor(ind_stub)]); let stub = functor!( atom!("existence_error"), - [atom(atom!("procedure")), str(h, 0)], - [res_stub] + [atom_as_cell((atom!("procedure"))), functor(res_stub)] ); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, } } ExistenceError::Procedure(name, arity) => { - let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]); + let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]); let stub = functor!( atom!("existence_error"), - [atom(atom!("procedure")), str(self.heap.len(), 0)], - [culprit] + [atom_as_cell((atom!("procedure"))), functor(culprit)] ); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, } } ExistenceError::ModuleSource(source) => { @@ -418,43 +364,75 @@ impl MachineState { let stub = functor!( atom!("existence_error"), - [atom(atom!("source_sink")), str(self.heap.len(), 0)], - [source_stub] + [atom_as_cell((atom!("source_sink"))), functor(source_stub)] ); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, } } ExistenceError::SourceSink(culprit) => { let stub = functor!( atom!("existence_error"), - [atom(atom!("source_sink")), cell(culprit)] + [atom_as_cell((atom!("source_sink"))), cell(culprit)] ); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } ExistenceError::Stream(culprit) => { let stub = functor!( atom!("existence_error"), - [atom(atom!("stream")), cell(culprit)] + [atom_as_cell((atom!("stream"))), cell(culprit)] ); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } } } + pub(crate) fn directive_error(&mut self, err: DirectiveError) -> MachineError { + match err { + DirectiveError::ExpectedDirective(_term) => self.domain_error( + DomainErrorType::Directive, + atom_as_cell!(atom!("todo_insert_invalid_term_here")), + ), + DirectiveError::InvalidDirective(name, arity) => { + self.domain_error(DomainErrorType::Directive, functor_stub(name, arity)) + } + DirectiveError::InvalidOpDeclNameType(_term) => self.type_error( + ValidType::List, + atom_as_cell!(atom!("todo_insert_invalid_term_here")), + ), + DirectiveError::InvalidOpDeclSpecDomain(_term) => self.domain_error( + DomainErrorType::OperatorSpecifier, + atom_as_cell!(atom!("todo_insert_invalid_term_here")), + ), + DirectiveError::InvalidOpDeclSpecValue(atom) => { + self.domain_error(DomainErrorType::OperatorSpecifier, atom_as_cell!(atom)) + } + DirectiveError::InvalidOpDeclPrecType(_term) => self.type_error( + ValidType::Integer, + atom_as_cell!(atom!("todo_insert_invalid_term_here")), + ), + DirectiveError::InvalidOpDeclPrecDomain(num) => { + self.domain_error(DomainErrorType::OperatorPriority, fixnum_as_cell!(num)) + } + DirectiveError::ShallNotCreate(atom) => { + self.permission_error(Permission::Create, atom!("operator"), atom) + } + DirectiveError::ShallNotModify(atom) => { + self.permission_error(Permission::Modify, atom!("operator"), atom) + } + } + } + pub(super) fn permission_error( &mut self, err: Permission, @@ -471,7 +449,6 @@ impl MachineState { fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError { match err { - ArithmeticError::UninstantiatedVar => self.instantiation_error(), ArithmeticError::NonEvaluableFunctor(cell, arity) => { let culprit = functor!(atom!("/"), [cell(cell), fixnum(arity)]); @@ -495,7 +472,6 @@ impl MachineState { MachineError { stub, location: None, - from: ErrorProvenance::Received, } } @@ -505,15 +481,11 @@ impl MachineState { Permission::Modify, atom!("static_procedure"), functor_stub(key.0, key.1) - .into_iter() - .collect::(), ), SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error( Permission::Modify, atom!("static_procedure"), functor_stub(key.0, key.1) - .into_iter() - .collect::(), ), SessionError::CannotOverwriteBuiltInModule(module) => { self.permission_error(Permission::Modify, atom!("static_module"), module) @@ -524,8 +496,7 @@ impl MachineState { let stub = functor!( atom!("module_does_not_contain_claimed_export"), - [atom(module_name), str(self.heap.len() + 4, 0)], - [functor_stub] + [atom_as_cell(module_name), functor(functor_stub)] ); self.permission_error(Permission::Access, atom!("private_procedure"), stub) @@ -536,7 +507,7 @@ impl MachineState { self.permission_error( Permission::Modify, atom!("module"), - functor!(error_atom, [atom(module_name)]), + functor!(error_atom, [atom_as_cell(module_name)]), ) } SessionError::NamelessEntry => { @@ -555,15 +526,12 @@ impl MachineState { } SessionError::CompilationError(err) => self.syntax_error(err), SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => { - let functor_stub = functor_stub(key.0, key.1); - let stub = functor!( atom!(":"), [ - atom(compilation_target.module_name()), - str(self.heap.len() + 4, 0) - ], - [functor_stub] + atom_as_cell((compilation_target.module_name())), + functor((key.0), [fixnum((key.1))]) + ] ); self.permission_error( @@ -587,30 +555,27 @@ impl MachineState { } let location = err.line_and_col_num(); - let len = self.heap.len(); let stub = err.as_functor(); - let stub = functor!(atom!("syntax_error"), [str(len, 0)], [stub]); + let stub = functor!(atom!("syntax_error"), [functor(stub)]); MachineError { stub, location, - from: ErrorProvenance::Constructed, } } - pub(super) fn representation_error(&mut self, flag: RepFlag) -> MachineError { - let stub = functor!(atom!("representation_error"), [atom(flag.as_atom())]); + pub(super) fn representation_error(&self, flag: RepFlag) -> MachineError { + let stub = functor!(atom!("representation_error"), [atom_as_cell((flag.as_atom()))]); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } #[cfg(feature = "ffi")] - pub(super) fn ffi_error(&mut self, err: FFIError) -> MachineError { + pub(super) fn ffi_error(&self, err: FFIError) -> MachineError { let error_atom = match err { FFIError::ValueCast => atom!("value_cast"), FFIError::ValueDontFit => atom!("value_dont_fit"), @@ -619,62 +584,44 @@ impl MachineState { FFIError::FunctionNotFound => atom!("function_not_found"), FFIError::StructNotFound => atom!("struct_not_found"), }; - let stub = functor!(atom!("ffi_error"), [atom(error_atom)]); + let stub = functor!(atom!("ffi_error"), [atom_as_cell(error_atom)]); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, } } - pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub { - let h = self.heap.len(); - let location = err.location; - let stub_addition_len = if err.len() == 1 { - 0 // if err contains 1 cell, it can be inlined at stub[1]. + pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub { + if let Some(ParserErrorSrc { line_num, .. }) = err.location { + functor!(atom!("error"), [functor((err.stub)), + functor((atom!(":")), [functor(src), + number(line_num, (&mut self.arena))])]) } else { - err.len() - }; - - let mut stub = vec![ - atom_as_cell!(atom!("error"), 2), - str_loc_as_cell!(h + 3), - str_loc_as_cell!(h + 3 + stub_addition_len), - ]; - - if stub_addition_len > 0 { - stub.extend(err.into_iter(3)); - } else { - stub[1] = err.stub[0]; + functor!(atom!("error"), [functor((err.stub)), + functor(src)]) } + } - if let Some(ParserErrorSrc { line_num, .. }) = location { - stub.push(atom_as_cell!(atom!(":"), 2)); - stub.push(str_loc_as_cell!(h + 6 + stub_addition_len)); - stub.push(integer_as_cell!(Number::arena_from( - line_num, - &mut self.arena - ))); - } - - stub.extend(src.iter()); - stub + // throw an error pre-allocated in the heap + pub(super) fn throw_resource_error(&mut self, err_loc: usize) { + self.registers[1] = str_loc_as_cell!(err_loc); + self.set_ball(); + self.unwind_stack(); } pub(super) fn throw_exception(&mut self, err: MachineStub) { - let h = self.heap.len(); - let err_len = err.len(); - self.ball.boundary = 0; self.ball.stub.truncate(0); - self.heap.extend(err); + let mut writer = Heap::functor_writer(err); - self.registers[1] = if err_len == 1 { - heap_loc_as_cell!(h) - } else { - str_loc_as_cell!(h) + self.registers[1] = match writer(&mut self.heap) { + Ok(loc) => loc, + Err(resource_err_loc) => { + self.throw_resource_error(resource_err_loc); + return; + } }; self.set_ball(); @@ -682,21 +629,6 @@ impl MachineState { } } -impl MachineError { - fn into_iter(self, offset: usize) -> Box> { - match self.from { - ErrorProvenance::Constructed => { - Box::new(self.stub.into_iter().map(move |hcv| hcv + offset)) - } - ErrorProvenance::Received => Box::new(self.stub.into_iter()), - } - } - - fn len(&self) -> usize { - self.stub.len() - } -} - #[derive(Debug)] pub enum CompilationError { Arithmetic(ArithmeticError), @@ -715,12 +647,12 @@ pub enum CompilationError { #[derive(Debug)] pub enum DirectiveError { - ExpectedDirective(Term), + ExpectedDirective(HeapCellValue), InvalidDirective(Atom, usize /* arity */), - InvalidOpDeclNameType(Term), - InvalidOpDeclSpecDomain(Term), + InvalidOpDeclNameType(HeapCellValue), + InvalidOpDeclSpecDomain(HeapCellValue), InvalidOpDeclSpecValue(Atom), - InvalidOpDeclPrecType(Term), + InvalidOpDeclPrecType(HeapCellValue), InvalidOpDeclPrecDomain(Fixnum), ShallNotCreate(Atom), ShallNotModify(Atom), @@ -757,11 +689,9 @@ impl CompilationError { functor!(atom!("exceeded_max_arity")) } CompilationError::InadmissibleFact => { - // TODO: type_error(callable, _). functor!(atom!("inadmissible_fact")) } CompilationError::InadmissibleQueryTerm => { - // TODO: type_error(callable, _). functor!(atom!("inadmissible_query_term")) } CompilationError::InvalidDirective(_) => { @@ -776,8 +706,8 @@ impl CompilationError { CompilationError::InvalidModuleExport => { functor!(atom!("invalid_module_export")) } - CompilationError::InvalidModuleResolution(ref module_name) => { - functor!(atom!("no_such_module"), [atom(module_name)]) + &CompilationError::InvalidModuleResolution(module_name) => { + functor!(atom!("no_such_module"), [atom_as_cell(module_name)]) } CompilationError::InvalidRuleHead => { functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _). @@ -896,14 +826,13 @@ impl EvalError { // used by '$skip_max_list'. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CycleSearchResult { - Cyclic(usize), + Cyclic { lambda: usize }, // number of steps EmptyList, - NotList(usize, HeapCellValue), // the list length until the second argument in the heap - PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. - ProperList(usize), // the list length. - PStrLocation(usize, usize, usize), // list length (up to max), the heap address of the PStr, the offset - UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address). - UntouchedCStr(Atom, usize), + NotList { num_steps: usize, heap_loc: HeapCellValue }, + PartialList { num_steps: usize, heap_loc: HeapCellValue }, + ProperList { num_steps: usize }, + PStrLocation { num_steps: usize, pstr_loc: HeapCellValue }, + UntouchedList { num_steps: usize, list_loc: usize }, } impl MachineState { @@ -915,11 +844,11 @@ impl MachineState { let sorted = self.store(self.deref(self.registers[2])); match BrentAlgState::detect_cycles(&self.heap, list) { - CycleSearchResult::PartialList(..) => { + CycleSearchResult::PartialList { .. } => { let err = self.instantiation_error(); return Err(self.error_form(err, stub_gen())); } - CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => { + CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => { let err = self.type_error(ValidType::List, list); return Err(self.error_form(err, stub_gen())); } @@ -927,7 +856,7 @@ impl MachineState { }; match BrentAlgState::detect_cycles(&self.heap, sorted) { - CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !sorted.is_var() => { + CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } if !sorted.is_var() => { let err = self.type_error(ValidType::List, sorted); Err(self.error_form(err, stub_gen())) } @@ -939,7 +868,7 @@ impl MachineState { let stub_gen = || functor_stub(atom!("keysort"), 2); match BrentAlgState::detect_cycles(&self.heap, list) { - CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !list.is_var() => { + CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } if !list.is_var() => { let err = self.type_error(ValidType::List, list); Err(self.error_form(err, stub_gen())) } @@ -1001,11 +930,11 @@ impl MachineState { let sorted = self.store(self.deref(self[temp_v!(2)])); match BrentAlgState::detect_cycles(&self.heap, pairs) { - CycleSearchResult::PartialList(..) => { + CycleSearchResult::PartialList { .. } => { let err = self.instantiation_error(); Err(self.error_form(err, stub_gen())) } - CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => { + CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => { let err = self.type_error(ValidType::List, pairs); Err(self.error_form(err, stub_gen())) } diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 56c03e7e..e0142b77 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -169,6 +169,13 @@ impl From> for CodeIndex { } } +impl From for HeapCellValue { + #[inline(always)] + fn from(idx: CodeIndex) -> HeapCellValue { + untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)) + } +} + impl CodeIndex { #[inline] pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self { @@ -208,10 +215,12 @@ impl CodeIndex { std::mem::replace(self.0.deref_mut(), value) } + /* #[inline(always)] pub(crate) fn as_ptr(&self) -> *const IndexPtr { self.0.as_ptr() } + */ } pub(crate) type GlobalVarDir = IndexMap), FxBuildHasher>; diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 1c18f16a..b5fdc1c0 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -1,6 +1,7 @@ use crate::arena::*; use crate::atom_table::*; use crate::forms::*; +use crate::functor_macro::*; use crate::heap_iter::*; use crate::heap_print::*; use crate::machine::attributed_variables::*; @@ -12,7 +13,6 @@ use crate::machine::stack::*; use crate::machine::streams::*; use crate::machine::Machine; use crate::parser::ast::*; -use crate::read::TermWriteResult; use crate::types::*; use crate::parser::dashu::Integer; @@ -21,7 +21,7 @@ use indexmap::IndexMap; use std::convert::TryFrom; use std::fmt; -use std::ops::{Index, IndexMut}; +use std::ops::{Index, IndexMut, Range}; use std::rc::Rc; use std::sync::Arc; @@ -36,8 +36,8 @@ pub(super) enum MachineMode { #[derive(Debug, Clone)] pub(super) enum HeapPtr { HeapCell(usize), - PStrChar(usize, usize), - PStrLocation(usize, usize), + PStr(usize), // Char(usize), + // PStrLocation(usize), } impl Default for HeapPtr { @@ -184,8 +184,9 @@ impl IndexMut for MachineState { } } -pub type CallResult = Result<(), Vec>; +pub type CallResult = Result<(), Vec>; +/* #[inline(always)] pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) { read_heap_cell!(heap[index], @@ -200,30 +201,44 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn } ) } +*/ fn push_var_eq_functors( heap: &mut Heap, + size: usize, iter: impl Iterator, atom_tbl: &AtomTable, -) -> Vec { - let mut list_of_var_eqs = vec![]; +) -> Result { + let src_h = heap.cell_len(); - for (var_loc, var) in iter { // (var, binding) in iter { - let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); - let h = heap.len(); - let binding = heap[var_loc]; + if size > 0 { + let mut writer = heap.reserve(1 + 5 * size)?; - heap.push(atom_as_cell!(atom!("="), 2)); - heap.push(atom_as_cell!(var_atom)); - heap.push(binding); + writer.write_with(|section| { + for (var_loc, var) in iter { // (var, binding) in iter { + let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); + let binding = heap_loc_as_cell!(var_loc); - list_of_var_eqs.push(str_loc_as_cell!(h)); + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(var_atom)); + section.push_cell(binding); + } + + for idx in 0 .. size { + section.push_cell(list_loc_as_cell!(section.cell_len() + 1)); + section.push_cell(str_loc_as_cell!(src_h + 3 * idx)); + } + + section.push_cell(empty_list_as_cell!()); + }); + + Ok(heap_loc_as_cell!(src_h + 3 * size)) + } else { + Ok(empty_list_as_cell!()) } - - list_of_var_eqs } - +/* pub(crate) fn copy_and_align_iter>( iter: Iter, boundary: i64, @@ -232,6 +247,7 @@ pub(crate) fn copy_and_align_iter>( let diff = boundary - h; iter.map(move |heap_value| heap_value - diff) } +*/ #[derive(Debug)] pub struct Ball { @@ -252,8 +268,17 @@ impl Ball { self.stub.clear(); } - pub(super) fn copy_and_align(&self, h: usize) -> Heap { - copy_and_align_iter(self.stub.iter().cloned(), self.boundary as i64, h as i64).collect() + pub(super) fn copy_and_align_to(&self, dest: &mut Heap) -> Result { + let h = dest.cell_len(); + let diff = self.boundary as i64 - h as i64; + + dest.append(self.stub.splice(..))?; + + for cell in &mut dest.splice_mut(h ..) { + *cell = *cell - diff; + } + + Ok(h) } } @@ -285,21 +310,6 @@ impl<'a> IndexMut for CopyTerm<'a> { } impl<'a> CopierTarget for CopyTerm<'a> { - #[inline(always)] - fn threshold(&self) -> usize { - self.state.heap.len() - } - - #[inline(always)] - fn push(&mut self, hcv: HeapCellValue) { - self.state.heap.push(hcv); - } - - #[inline(always)] - fn push_attr_var_queue(&mut self, attr_var_loc: usize) { - self.state.attr_var_init.attr_var_queue.push(attr_var_loc); - } - #[inline(always)] fn store(&self, value: HeapCellValue) -> HeapCellValue { self.state.store(value) @@ -310,10 +320,56 @@ impl<'a> CopierTarget for CopyTerm<'a> { self.state.deref(value) } + #[inline(always)] + fn push_attr_var_queue(&mut self, attr_var_loc: usize) { + self.state.attr_var_init.attr_var_queue.push(attr_var_loc); + } + #[inline(always)] fn stack(&mut self) -> &mut Stack { &mut self.state.stack } + + #[inline(always)] + fn threshold(&self) -> usize { + self.state.heap.cell_len() + } + + #[inline(always)] + fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result { + self.state.heap.copy_pstr_within(pstr_loc) + } + + #[inline(always)] + fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize { + self.state.heap.pstr_vec()[0 .. cell_index!(pstr_loc)] + .last_zero() + .map(|idx| idx + 1) + .unwrap_or(0) + } + + #[inline(always)] + fn pstr_at(&self, loc: usize) -> bool { + self.state.heap.pstr_vec()[loc] + } + + #[inline(always)] + fn next_non_pstr_cell_index(&self, loc: usize) -> usize { + // unwrap is safe here because a partial string is always + // followed by a tail cell, i.e. a non-pstr cell, supposing + // self.state.heap[loc] is a pstr cell + self.state.heap.pstr_vec()[loc ..].first_zero().unwrap() + } + + #[inline(always)] + fn reserve(&mut self, num_cells: usize) -> Result { + self.state.heap.reserve(num_cells) + } + + #[inline(always)] + fn copy_slice_to_end(&mut self, bounds: Range) -> Result<(), usize> { + self.state.heap.copy_slice_to_end(bounds) + } } #[derive(Debug)] @@ -321,7 +377,6 @@ pub(crate) struct CopyBallTerm<'a> { attr_var_queue: &'a mut Vec, stack: &'a mut Stack, heap: &'a mut Heap, - heap_boundary: usize, stub: &'a mut Heap, } @@ -332,13 +387,10 @@ impl<'a> CopyBallTerm<'a> { heap: &'a mut Heap, stub: &'a mut Heap, ) -> Self { - let hb = heap.len(); - CopyBallTerm { attr_var_queue, stack, heap, - heap_boundary: hb, stub, } } @@ -348,10 +400,10 @@ impl<'a> Index for CopyBallTerm<'a> { type Output = HeapCellValue; fn index(&self, index: usize) -> &Self::Output { - if index < self.heap_boundary { + if index < self.heap.cell_len() { &self.heap[index] } else { - let index = index - self.heap_boundary; + let index = index - self.heap.cell_len(); &self.stub[index] } } @@ -359,10 +411,10 @@ impl<'a> Index for CopyBallTerm<'a> { impl<'a> IndexMut for CopyBallTerm<'a> { fn index_mut(&mut self, index: usize) -> &mut Self::Output { - if index < self.heap_boundary { + if index < self.heap.cell_len() { &mut self.heap[index] } else { - let index = index - self.heap_boundary; + let index = index - self.heap.cell_len(); &mut self.stub[index] } } @@ -370,11 +422,7 @@ impl<'a> IndexMut for CopyBallTerm<'a> { impl<'a> CopierTarget for CopyBallTerm<'a> { fn threshold(&self) -> usize { - self.heap_boundary + self.stub.len() - } - - fn push(&mut self, value: HeapCellValue) { - self.stub.push(value); + self.heap.cell_len() + self.stub.cell_len() } #[inline(always)] @@ -385,10 +433,10 @@ impl<'a> CopierTarget for CopyBallTerm<'a> { fn store(&self, value: HeapCellValue) -> HeapCellValue { read_heap_cell!(value, (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { - if h < self.heap_boundary { + if h < self.heap.cell_len() { self.heap[h] } else { - let index = h - self.heap_boundary; + let index = h - self.heap.cell_len(); self.stub[index] } } @@ -417,6 +465,67 @@ impl<'a> CopierTarget for CopyBallTerm<'a> { fn stack(&mut self) -> &mut Stack { self.stack } + + fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result { + debug_assert!(pstr_loc < self.heap.byte_len()); + + let (string, tail_loc) = self.heap.scan_slice_to_str(pstr_loc); + self.stub.allocate_pstr(string)?; + Ok(tail_loc) + } + + #[inline] + fn reserve(&mut self, num_cells: usize) -> Result { + self.stub.reserve(num_cells) + } + + #[inline] + fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize { + if pstr_loc >= self.heap.byte_len() { + self.stub.pstr_vec()[0 .. cell_index!(pstr_loc - self.heap.byte_len())] + .last_zero() + .map(|idx| idx + 1) + .unwrap_or(0) + } else { + self.heap.pstr_vec()[0 .. cell_index!(pstr_loc)] + .last_zero() + .map(|idx| idx + 1) + .unwrap_or(0) + } + } + + #[inline] + fn pstr_at(&self, loc: usize) -> bool { + if loc >= self.heap.cell_len() { + self.stub.pstr_vec()[loc - self.heap.cell_len()] + } else { + self.heap.pstr_vec()[loc] + } + } + + #[inline] + fn next_non_pstr_cell_index(&self, loc: usize) -> usize { + let zero_from_loc = if loc >= self.heap.cell_len() { + self.stub.pstr_vec()[loc - self.heap.cell_len() ..].first_zero().unwrap() + } else { + self.heap.pstr_vec()[loc ..].first_zero().unwrap() + }; + + zero_from_loc + loc + } + + fn copy_slice_to_end(&mut self, bounds: Range) -> Result<(), usize> { + let len = bounds.end - bounds.start; + let mut stub_writer = self.stub.reserve(len)?; + + stub_writer.write_with(|section| { + for idx in bounds { + section.push_cell(self.heap[idx]); + } + }); + + Ok(()) + } } impl MachineState { @@ -467,10 +576,6 @@ impl MachineState { let addr = self.store(self.deref(addr)); read_heap_cell!(addr, - (HeapCellValueTag::Char, c) => { - chars.push(c); - continue; - } (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { if let Some(c) = name.as_char() { @@ -543,35 +648,37 @@ impl MachineState { pub fn write_read_term_options( &mut self, mut var_list: Vec<(Var, HeapCellValue, usize)>, - singleton_var_list: Vec, + singletons_heap_list: HeapCellValue, ) -> CallResult { var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2)); + /* let list_of_var_eqs = push_var_eq_functors( &mut self.heap, var_list.iter().map(|(var_name, var, _)| { (var.get_value() as usize, var_name.clone()) }), + num_vars, &self.atom_tbl, ); + */ let singleton_addr = self.registers[3]; - let singletons_offset = heap_loc_as_cell!(iter_to_heap_list( - &mut self.heap, - singleton_var_list.into_iter() - )); - - unify_fn!(*self, singletons_offset, singleton_addr); + unify_fn!(*self, singletons_heap_list, singleton_addr); if self.fail { return Ok(()); } let vars_addr = self.registers[4]; - let vars_offset = heap_loc_as_cell!(iter_to_heap_list( - &mut self.heap, - var_list.into_iter().map(|(_, cell, _)| cell) - )); + let vars_offset = resource_error_call_result!( + self, + sized_iter_to_heap_list( + &mut self.heap, + var_list.len(), + var_list.iter().map(|(_, cell, _)| *cell), + ) + ); unify_fn!(*self, vars_offset, vars_addr); @@ -580,23 +687,41 @@ impl MachineState { } let var_names_addr = self.registers[5]; + /* let var_names_offset = heap_loc_as_cell!(iter_to_heap_list( &mut self.heap, list_of_var_eqs.into_iter() )); + */ + + let var_names_offset = resource_error_call_result!( + self, + push_var_eq_functors( + &mut self.heap, + var_list.len(), + var_list.iter().map(|(var_name, var, _)| { + (var.get_value() as usize, var_name.clone()) + }), + &self.atom_tbl, + ) + ); Ok(unify_fn!(*self, var_names_offset, var_names_addr)) } pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult { - let heap_loc = read_heap_cell!(self.heap[term.heap_loc], - (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + let heap_loc = self.heap[term.focus]; + + /* + read_heap_cell!(self.heap[term.heap_loc], + (HeapCellValueTag::PStr) => { // | HeapCellValueTag::PStrOffset) => { pstr_loc_as_cell!(term.heap_loc) } _ => { heap_loc_as_cell!(term.heap_loc) } ); + */ unify_fn!(*self, heap_loc, self.registers[2]); @@ -612,7 +737,7 @@ impl MachineState { let mut singleton_var_set: IndexMap = IndexMap::new(); - for cell in eager_stackful_preorder_iter(&mut self.heap, heap_loc) { + for cell in stackful_preorder_iter::(&mut self.heap, &mut self.stack, term.focus) { let cell = unmark_cell_bits!(cell); if let Some(var) = cell.as_var() { @@ -624,29 +749,33 @@ impl MachineState { } } - let singleton_var_list = push_var_eq_functors( - &mut self.heap, - term.inverse_var_locs - .iter() - .filter_map(|(var_loc, var_name)| { - // add h to offset the term variable into its heap location. - let r = Ref::heap_cell(*var_loc); + let singleton_var_list = resource_error_call_result!( + self, + push_var_eq_functors( + &mut self.heap, + singleton_var_set + .iter() + .filter(|(var, is_singleton)| { + **is_singleton && term.inverse_var_locs.contains_key( + &(var.get_value() as usize) + ) + }) + .count(), + term.inverse_var_locs + .iter() + .filter_map(|(var_loc, var_name)| { + let r = Ref::heap_cell(*var_loc); - if singleton_var_set.get(&r).cloned().unwrap_or(false) { - Some((*var_loc, var_name.clone())) - } else { - None - } - }), - &self.atom_tbl, + if singleton_var_set.get(&r).cloned().unwrap_or(false) { + Some((*var_loc, var_name.clone())) + } else { + None + } + }), + &self.atom_tbl, + ) ); - /* - for var in term_write_result.var_dict.values_mut() { - *var = heap_bound_deref(&self.heap, *var); - } - */ - let mut var_list = Vec::with_capacity(singleton_var_set.len()); for (var_loc, var_name) in term.inverse_var_locs { @@ -744,7 +873,7 @@ impl MachineState { CompilationError::ParserError(e) if e.is_unexpected_eof() => { match eof_handler(self, stream)? { OnEOF::Return => { - return self.write_read_term_options(vec![], vec![]) + return self.write_read_term_options(vec![], empty_list_as_cell!()); } OnEOF::Continue => continue, } @@ -793,9 +922,6 @@ impl MachineState { } read_heap_cell!(atom, - (HeapCellValueTag::Char, c) => { - var_names.insert(var, Rc::new(c.to_string())); - } (HeapCellValueTag::Atom, (name, _arity)) => { debug_assert_eq!(_arity, 0); var_names.insert(var, Rc::new(name.as_str().to_owned())); @@ -884,16 +1010,20 @@ impl MachineState { } ); - let h = self.heap.len(); - self.heap.push(term_to_be_printed); + let term_loc = self.heap.cell_len(); + + step_or_resource_error!( + self, + self.heap.push_cell(term_to_be_printed), + { return Ok(None); } + ); let mut printer = HCPrinter::new( &mut self.heap, - Arc::clone(&self.atom_tbl), &mut self.stack, op_dir, PrinterOutputter::new(), - h, + term_loc, ); printer.ignore_ops = ignore_ops; @@ -984,42 +1114,6 @@ impl MachineState { } ); } - - pub(crate) fn directive_error(&mut self, err: DirectiveError) -> MachineError { - match err { - DirectiveError::ExpectedDirective(_term) => self.domain_error( - DomainErrorType::Directive, - atom_as_cell!(atom!("todo_insert_invalid_term_here")), - ), - DirectiveError::InvalidDirective(name, arity) => { - self.domain_error(DomainErrorType::Directive, functor_stub(name, arity)) - } - DirectiveError::InvalidOpDeclNameType(_term) => self.type_error( - ValidType::List, - atom_as_cell!(atom!("todo_insert_invalid_term_here")), - ), - DirectiveError::InvalidOpDeclSpecDomain(_term) => self.domain_error( - DomainErrorType::OperatorSpecifier, - atom_as_cell!(atom!("todo_insert_invalid_term_here")), - ), - DirectiveError::InvalidOpDeclSpecValue(atom) => { - self.domain_error(DomainErrorType::OperatorSpecifier, atom_as_cell!(atom)) - } - DirectiveError::InvalidOpDeclPrecType(_term) => self.type_error( - ValidType::Integer, - atom_as_cell!(atom!("todo_insert_invalid_term_here")), - ), - DirectiveError::InvalidOpDeclPrecDomain(num) => { - self.domain_error(DomainErrorType::OperatorPriority, fixnum_as_cell!(num)) - } - DirectiveError::ShallNotCreate(atom) => { - self.permission_error(Permission::Create, atom!("operator"), atom) - } - DirectiveError::ShallNotModify(atom) => { - self.permission_error(Permission::Modify, atom!("operator"), atom) - } - } - } } #[allow(clippy::upper_case_acronyms)] diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index e93356fd..34fbe5ca 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -22,6 +22,12 @@ use std::convert::TryFrom; impl MachineState { pub(crate) fn new() -> Self { + let mut heap = Heap::with_cell_capacity(256 * 256).unwrap(); + + // this is an interstitial cell reserved for use by the runtime. + heap.push_cell(empty_list_as_cell!()).unwrap(); + heap.store_resource_error(); + MachineState { arena: Arena::new(), atom_tbl: AtomTable::new(), @@ -38,7 +44,7 @@ impl MachineState { cp: 0, attr_var_init: AttrVarInitializer::new(0), fail: false, - heap: Heap::with_capacity(256 * 256), + heap, mode: MachineMode::Write, stack: Stack::new(), registers: [heap_loc_as_cell!(0); MAX_ARITY + 1], // self.registers[0] is never used. @@ -261,9 +267,14 @@ impl MachineState { unifier.unify_atom(atom, value); } - pub fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) { + pub fn unify_list(&mut self, l1: usize, value: HeapCellValue) { let mut unifier = DefaultUnifier::from(self); - unifier.unify_complete_string(atom, value); + unifier.unify_list(l1, value); + } + + pub fn unify_partial_string(&mut self, pstr_loc: usize, value: HeapCellValue) { + let mut unifier = DefaultUnifier::from(self); + unifier.unify_partial_string(pstr_loc, value); } pub fn unify_char(&mut self, c: char, value: HeapCellValue) { @@ -316,18 +327,23 @@ impl MachineState { self.ball.reset(); let addr = self.registers[1]; - self.ball.boundary = self.heap.len(); + let ball_boundary = self.heap.cell_len(); - copy_term( - CopyBallTerm::new( - &mut self.attr_var_init.attr_var_queue, - &mut self.stack, - &mut self.heap, - &mut self.ball.stub, - ), - addr, - AttrVarPolicy::DeepCopy, + step_or_resource_error!( + self, + copy_term( + CopyBallTerm::new( + &mut self.attr_var_init.attr_var_queue, + &mut self.stack, + &mut self.heap, + &mut self.ball.stub, + ), + addr, + AttrVarPolicy::DeepCopy, + ) ); + + self.ball.boundary = ball_boundary; } #[inline(always)] @@ -336,84 +352,34 @@ impl MachineState { self.fail = true; } + // return the read value and the succeeding HeapPtr pub(crate) fn read_s(&mut self) -> HeapCellValue { - match &mut self.s { - &mut HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]), - &mut HeapPtr::PStrChar(h, n) if self.s_offset == 0 => { - read_heap_cell!(self.heap[h], - (HeapCellValueTag::PStr, pstr_atom) => { - let pstr = PartialString::from(pstr_atom); + match self.s { + HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]), + HeapPtr::PStr(h) => { + let mut char_iter = self.heap.char_iter(h); - if let Some(c) = pstr.as_str_from(n).chars().next() { - char_as_cell!(c) - } else { - self.deref(self.heap[h+1]) - } + if self.s_offset == 0 { // read the car of the list + let c = char_iter.next().unwrap(); + char_as_cell!(c) + } else { // read the (self.s_offset)^{th} cdr of the list + let byte_offset: usize = char_iter + .take(self.s_offset) + .map(|c| c.len_utf8()) + .sum(); + let new_h = h + byte_offset; + + self.s_offset = 0; + + if self.heap.char_iter(new_h).next().is_some() { + self.s = HeapPtr::PStr(new_h); + pstr_loc_as_cell!(new_h) + } else { + let h = Heap::neighboring_cell_offset(new_h); + self.s = HeapPtr::HeapCell(h); + self.deref(heap_loc_as_cell!(h)) } - (HeapCellValueTag::CStr, cstr_atom) => { - let pstr = PartialString::from(cstr_atom); - - if let Some(c) = pstr.as_str_from(n).chars().next() { - char_as_cell!(c) - } else { - empty_list_as_cell!() - } - } - _ => { - unreachable!() - } - ) - } - &mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrLocation(h, ref mut n) => { - read_heap_cell!(self.heap[h], - (HeapCellValueTag::PStr, pstr_atom) => { - let pstr = PartialString::from(pstr_atom); - let n_offset: usize = pstr.as_str_from(*n) - .chars() - .take(self.s_offset) - .map(|c| c.len_utf8()) - .sum(); - - self.s_offset = 0; - *n += n_offset; - - if *n < pstr_atom.len() { - let h_len = self.heap.len(); - - self.heap.push(pstr_offset_as_cell!(h)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64))); - - pstr_loc_as_cell!(h_len) - } else { - self.deref(self.heap[h+1]) - } - } - (HeapCellValueTag::CStr, cstr_atom) => { - let pstr = PartialString::from(cstr_atom); - let n_offset: usize = pstr.as_str_from(*n) - .chars() - .take(self.s_offset) - .map(|c| c.len_utf8()) - .sum(); - - self.s_offset = 0; - *n += n_offset; - - if *n < cstr_atom.len() { - let h_len = self.heap.len(); - - self.heap.push(pstr_offset_as_cell!(h)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64))); - - pstr_loc_as_cell!(h_len) - } else { - empty_list_as_cell!() - } - } - _ => { - unreachable!() - } - ) + } } } } @@ -482,6 +448,7 @@ impl MachineState { return Some(n1.cmp(&n2)); } } + /* (HeapCellValueTag::Char, c2) => { if let Some(c1) = n1.as_char() { if c1 != c2 { @@ -496,6 +463,7 @@ impl MachineState { ); } } + */ (HeapCellValueTag::Str, s) => { let n2 = cell_as_atom_cell!(self.heap[s]) .get_name(); @@ -510,6 +478,7 @@ impl MachineState { } ) } + /* (HeapCellValueTag::Char, c1) => { read_heap_cell!(v2, (HeapCellValueTag::Atom, (n2, _a2)) => { @@ -554,6 +523,7 @@ impl MachineState { } ) } + */ (HeapCellValueTag::Str, s) => { let n1 = cell_as_atom_cell!(self.heap[s]) .get_name(); @@ -565,6 +535,7 @@ impl MachineState { return Some(n1.cmp(&n2)); } } + /* (HeapCellValueTag::Char, c2) => { if let Some(c1) = n1.as_char() { if c1 != c2 { @@ -579,6 +550,7 @@ impl MachineState { ); } } + */ (HeapCellValueTag::Str, s) => { let n2 = cell_as_atom_cell!(self.heap[s]) .get_name(); @@ -599,121 +571,22 @@ impl MachineState { ) } Some(TermOrderCategory::Compound) => { - fn stalled_pstr_iter_comparator( - iteratee: PStrIteratee, - iter2: HeapPStrIter, - pdl: &mut Vec, - ) -> Option { - let compound = Some(TermOrderCategory::Compound); - - if iter2.focus.order_category(iter2.heap) != compound { - Some(compound.cmp(&iter2.focus.order_category(iter2.heap))) - } else { - let c1 = match iteratee { - PStrIteratee::Char(_, c) => c, - PStrIteratee::PStrSegment(focus, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - - match pstr.as_str_from(n).chars().next() { - Some(c) => c, - None => { - pdl.push(iter2.focus); - // iter2 is continuable, so it - // has a tail in the heap at - // focus+1. - pdl.push(iter2.heap[focus + 1]); - - return None; - } - } - } - }; - - read_heap_cell!(iter2.focus, - (HeapCellValueTag::Lis, l) => { - pdl.push(iter2.heap[l]); - pdl.push(char_as_cell!(c1)); - - None - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(iter2.heap[s]) - .get_name_and_arity(); - - if name == atom!(".") && arity == 2 { - pdl.push(iter2.heap[s+1]); - pdl.push(char_as_cell!(c1)); - - None - } else { - Some((2, atom!(".")).cmp(&(arity, name))) - } - } - _ => { - unreachable!() - } - ) - } - } - - fn pstr_comparator( - heap: &[HeapCellValue], - pdl: &mut Vec, - s1: usize, - s2: usize, - ) -> Option { - let mut iter1 = HeapPStrIter::new(heap, s1); - let mut iter2 = HeapPStrIter::new(heap, s2); - - match compare_pstr_prefixes(&mut iter1, &mut iter2) { - PStrCmpResult::Ordered(ordering) => Some(ordering), - PStrCmpResult::FirstIterContinuable(iteratee) => { - stalled_pstr_iter_comparator(iteratee, iter2, pdl) - } - PStrCmpResult::SecondIterContinuable(iteratee) => { - let result = stalled_pstr_iter_comparator(iteratee, iter1, pdl); - - if let Some(ordering) = result { - Some(ordering.reverse()) - } else { - let pdl_len = pdl.len(); - pdl.swap(pdl_len - 2, pdl_len - 1); - result - } - } - PStrCmpResult::Unordered => { - pdl.push(iter2.focus); - pdl.push(iter1.focus); - - None - } - } - } - read_heap_cell!(v1, (HeapCellValueTag::Lis, l1) => { read_heap_cell!(v2, - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - let h = self.heap.len(); + (HeapCellValueTag::PStrLoc, l2) => { + // like the action of + // partial_string_to_pdl here but + // the ordering of PDL pushes is + // (crucially for comparison + // correctness) different. + let (c, succ_cell) = self.heap.last_str_char_and_tail(l2); - self.heap.push(v1); - self.heap.push(v2); + self.pdl.push(succ_cell); + self.pdl.push(heap_loc_as_cell!(l1 + 1)); - if let Some(ordering) = pstr_comparator( - &self.heap, &mut self.pdl, h, h+1 - ) { - if ordering != Ordering::Equal { - self.heap.pop(); - self.heap.pop(); - - self.pdl.clear(); - - return Some(ordering); - } - } - - self.heap.pop(); - self.heap.pop(); + self.pdl.push(char_as_cell!(c)); + self.pdl.push(heap_loc_as_cell!(l1)); } (HeapCellValueTag::Lis, l2) => { if tabu_list.contains(&(l1, l2)) { @@ -757,27 +630,44 @@ impl MachineState { } ) } - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - let h = self.heap.len(); + (HeapCellValueTag::PStrLoc, l1) => { + read_heap_cell!(v2, + (HeapCellValueTag::PStrLoc, l2) => { + let cmp_result = self.heap.compare_pstr_segments(l1, l2); - self.heap.push(v1); - self.heap.push(v2); - - if let Some(ordering) = pstr_comparator( - &self.heap, &mut self.pdl, h, h+1, - ) { - if ordering != Ordering::Equal { - self.heap.pop(); - self.heap.pop(); - - self.pdl.clear(); - - return Some(ordering); + if let Some(ordering) = cmp_result.continue_pstr_compare(&mut self.pdl) { + return Some(ordering); + } } - } + (HeapCellValueTag::Lis, l2) => { + let (c, succ_cell) = self.heap.last_str_char_and_tail(l1); - self.heap.pop(); - self.heap.pop(); + self.pdl.push(succ_cell); + self.pdl.push(heap_loc_as_cell!(l2 + 1)); + + self.pdl.push(char_as_cell!(c)); + self.pdl.push(heap_loc_as_cell!(l2)); + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); + + if name == atom!(".") && arity == 2 { + let (c, succ_cell) = self.heap.last_str_char_and_tail(l1); + + self.pdl.push(heap_loc_as_cell!(s+2)); + self.pdl.push(succ_cell); + + self.pdl.push(heap_loc_as_cell!(s+1)); + self.pdl.push(char_as_cell!(c)); + } else { + self.fail = true; + } + } + _ => { + unreachable!() + } + ); } (HeapCellValueTag::Str, s1) => { read_heap_cell!(v2, @@ -831,27 +721,21 @@ impl MachineState { } } } - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - let h = self.heap.len(); + (HeapCellValueTag::PStrLoc, l2) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s1]) + .get_name_and_arity(); - self.heap.push(v1); - self.heap.push(v2); + if name == atom!(".") && arity == 2 { + let (c, succ_cell) = self.heap.last_str_char_and_tail(l2); - if let Some(ordering) = pstr_comparator( - &self.heap, &mut self.pdl, h, h+1, - ) { - if ordering != Ordering::Equal { - self.heap.pop(); - self.heap.pop(); + self.pdl.push(succ_cell); + self.pdl.push(heap_loc_as_cell!(s1+2)); - self.pdl.clear(); - - return Some(ordering); - } + self.pdl.push(char_as_cell!(c)); + self.pdl.push(heap_loc_as_cell!(s1+1)); + } else { + self.fail = true; } - - self.heap.pop(); - self.heap.pop(); } _ => { unreachable!() @@ -875,185 +759,37 @@ impl MachineState { Some(Ordering::Equal) } - pub fn match_partial_string(&mut self, value: HeapCellValue, string: Atom, has_tail: bool) { - let h = self.heap.len(); - self.heap.push(value); + /* TODO: new, inlined match_partial_string. now inlined into GetPartialString, + * the only place it is called from. Therefore, it has been inlined. - let prefix_len; - let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h); + pub fn match_partial_string( + &mut self, + value: HeapCellValue, + string: &str, + ) -> Result<(), usize> { + debug_assert!(value.is_ref()); - let s = string.as_str(); + self.heap[0] = value; + let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, 0); - match heap_pstr_iter.compare_pstr_to_string(&s) { - Some(PStrPrefixCmpResult { - focus, - offset, - prefix_len, - }) if prefix_len == s.len() => { - let focus_addr = self.heap[focus]; - - read_heap_cell!(focus_addr, - (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => { - if has_tail { - self.s = HeapPtr::PStrLocation(focus, offset); - self.s_offset = 0; - self.mode = MachineMode::Read; - } else if offset == pstr_atom.len() { - let focus = heap_pstr_iter.focus; - unify!(self, focus, empty_list_as_cell!()); - } else { - self.fail = true; - } - } - (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, h) => { - let (focus, _) = pstr_loc_and_offset(&self.heap, h); - let pstr_atom = cell_as_atom!(self.heap[focus]); - - if has_tail { - self.s = HeapPtr::PStrLocation(focus, offset); - self.s_offset = 0; - self.mode = MachineMode::Read; - } else if offset == pstr_atom.len() { - let focus = heap_pstr_iter.focus; - unify!(self, focus, empty_list_as_cell!()); - } else { - self.fail = true; - } - } - _ => { - let focus = heap_pstr_iter.focus(); - - if has_tail { - self.s = HeapPtr::HeapCell(focus); - self.s_offset = 0; - self.mode = MachineMode::Read; - } else { - let focus = heap_pstr_iter.focus; - unify!(self, focus, empty_list_as_cell!()); - } - } - ); - - return; + match heap_pstr_iter.compare_pstr_to_string(string) { + Some(PStrCmpResult::CompleteMatch { bytes_matched, pstr_loc }) => { + self.s_offset = bytes_matched; + self.s = HeapPtr::PStr(pstr_loc); + self.mode = MachineMode::Read; } - Some(PStrPrefixCmpResult { - prefix_len: inner_prefix_len, - .. - }) => { - prefix_len = inner_prefix_len; + Some(PStrCmpResult::PartialMatch { string, var_loc }) => { + let cell = self.heap.allocate_pstr(string)?; + unify!(self, cell, heap_loc_as_loc!(var_loc)); } None => { - read_heap_cell!(value, - (HeapCellValueTag::Str, s) => { - let cell = heap_loc_as_cell!(s + 1); - let is_list = self.heap[s] == atom_as_cell!(atom!("."), 2); - - if !(is_list && self.store(self.deref(cell)).is_var()) { - self.fail = true; - return; - } - } - (HeapCellValueTag::Lis, l) => { - let cell = heap_loc_as_cell!(l); - - if !self.store(self.deref(cell)).is_var() { - self.fail = true; - return; - } - } - (HeapCellValueTag::AttrVar | - HeapCellValueTag::StackVar | - HeapCellValueTag::Var) => { - } - _ => { - self.fail = true; - return; - } - ); - - prefix_len = 0; + self.fail = true; } } - let focus = heap_pstr_iter.focus(); - let tail_addr = self.heap[focus]; - let target_cell = self.push_str_to_heap(&string.as_str()[prefix_len..], has_tail); - - unify!(self, tail_addr, target_cell); - } - - #[inline(always)] - pub(super) fn push_str_to_heap(&mut self, pstr: &str, has_tail: bool) -> HeapCellValue { - let h = self.heap.len(); - - if has_tail { - self.s = HeapPtr::HeapCell(h + 1); - self.s_offset = 0; - self.mode = MachineMode::Read; - - put_partial_string(&mut self.heap, pstr, &self.atom_tbl) - } else { - put_complete_string(&mut self.heap, pstr, &self.atom_tbl) - } - } - - pub(super) fn write_literal_to_var(&mut self, deref_v: HeapCellValue, lit: HeapCellValue) { - let store_v = self.store(deref_v); - - read_heap_cell!(lit, - (HeapCellValueTag::Atom, (atom, arity)) => { - if arity == 0 { - self.unify_atom(atom, store_v); - } else { - self.fail = true; - } - } - (HeapCellValueTag::Char, c) => { - self.unify_char(c, store_v); - } - (HeapCellValueTag::Fixnum, n) => { - self.unify_fixnum(n, store_v); - } - (HeapCellValueTag::F64, f64_ptr) => { - self.unify_f64(f64_ptr, store_v); - } - (HeapCellValueTag::Cons, ptr) => { - match_untyped_arena_ptr!(ptr, - (ArenaHeaderTag::Integer, n) => { - self.unify_big_int(n, store_v); - } - (ArenaHeaderTag::Rational, r) => { - self.unify_rational(r, store_v); - } - _ => { - self.fail = true; - } - ) - } - (HeapCellValueTag::CStr, cstr_atom) => { - read_heap_cell!(store_v, - (HeapCellValueTag::PStrLoc | - HeapCellValueTag::Lis | - HeapCellValueTag::Str) => { - self.match_partial_string(store_v, cstr_atom, false); - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => { - let r = store_v.as_var().unwrap(); - self.bind(r, lit); - } - (HeapCellValueTag::CStr, cstr2_atom) => { - self.fail = cstr_atom != cstr2_atom; - } - _ => { - self.fail = true; - } - ); - } - _ => { - unreachable!() - } - ) + Ok(()) } + */ pub(crate) fn setup_call_n_init_goal_info( &mut self, @@ -1084,9 +820,11 @@ impl MachineState { (name, 0, 0) } + /* (HeapCellValueTag::Char, c) => { (AtomTable::build_with(&self.atom_tbl, &c.to_string()), 0, 0) } + */ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { let stub = functor_stub(atom!("call"), arity + 1); let err = self.instantiation_error(); @@ -1118,24 +856,14 @@ impl MachineState { } #[inline] - pub fn is_cyclic_term(&mut self, value: HeapCellValue) -> bool { - let value = self.store(self.deref(value)); - - if value.is_stack_var() || value.is_constant() { + pub fn is_cyclic_term(&mut self, term_loc: usize) -> bool { + if self.heap[term_loc].is_stack_var() { return false; } - let h = self.heap.len(); - self.heap.push(value); - - let cycle_found = { - let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, h); - for _ in iter.by_ref() {} - iter.cycle_found() - }; - - self.heap.pop(); - cycle_found + let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, term_loc); + for _ in iter.by_ref() {} + iter.cycle_found() } // arg(+N, +Term, ?Arg) @@ -1202,19 +930,27 @@ impl MachineState { (HeapCellValueTag::PStrLoc, pstr_loc) => { if n == 1 || n == 2 { let a3 = self.registers[3]; - let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc); + // let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc); + let mut char_iter = self.heap.char_iter(pstr_loc); - let pstr = cell_as_string!(self.heap[h]); - let offset = offset.get_num() as usize; + // let pstr = cell_as_string!(self.heap[h]); + // let offset = offset.get_num() as usize; - if let Some(c) = pstr.as_str_from(offset).chars().next() { + if let Some(c) = char_iter.next() { // pstr.as_str_from(offset).chars().next() { if n == 1 { self.unify_char(c, a3); } else { - let offset = (offset + c.len_utf8()) as i64; - let h_len = self.heap.len(); - let pstr_atom: Atom = pstr.into(); + // let offset = (offset + c.len_utf8()) as i64; + // let h_len = self.heap.len(); + // let pstr_atom: Atom = pstr.into(); + if char_iter.next().is_some() { + unify_fn!(*self, pstr_loc_as_cell!(pstr_loc + c.len_utf8()), a3); + } else { + let tail_idx = Heap::neighboring_cell_offset(pstr_loc); + unify_fn!(*self, self.heap[tail_idx]); + } + /* if pstr_atom.len() > offset as usize { self.heap.push(pstr_offset_as_cell!(h)); self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); @@ -1233,6 +969,7 @@ impl MachineState { } } } + */ } } else { unreachable!() @@ -1241,6 +978,7 @@ impl MachineState { self.fail = true; } } + /* (HeapCellValueTag::CStr, cstr_atom) => { let cstr = PartialString::from(cstr_atom); @@ -1267,6 +1005,7 @@ impl MachineState { unreachable!() } } + */ _ => { // 8.5.2.3 d) let err = self.type_error(ValidType::Compound, term); @@ -1297,7 +1036,7 @@ impl MachineState { fn try_functor_unify_components(&mut self, name: HeapCellValue, arity: usize) { let a2 = self.deref(self.registers[2]); - self.write_literal_to_var(a2, name); + unify!(self, a2, name); if !self.fail { let a3 = self.store(self.deref(self.registers[3])); @@ -1305,20 +1044,25 @@ impl MachineState { } } - fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) { - let h = self.heap.len(); + fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) -> Result<(), usize> { + let h = self.heap.cell_len(); + let mut writer = self.heap.reserve(arity + 1)?; let f_a = if name == atom!(".") && arity == 2 { - self.heap.push(heap_loc_as_cell!(h)); - self.heap.push(heap_loc_as_cell!(h + 1)); + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(h)); + section.push_cell(heap_loc_as_cell!(h + 1)); + }); list_loc_as_cell!(h) } else { - self.heap.push(atom_as_cell!(name, arity)); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(name, arity)); - for i in 0..arity { - self.heap.push(heap_loc_as_cell!(h + i + 1)); - } + for i in 0..arity { + section.push_cell(heap_loc_as_cell!(h + i + 1)); + } + }); if arity == 0 { heap_loc_as_cell!(h) @@ -1328,6 +1072,7 @@ impl MachineState { }; (self.bind_fn)(self, r, f_a); + Ok(()) } pub fn try_functor(&mut self) -> CallResult { @@ -1335,7 +1080,7 @@ impl MachineState { let a1 = self.store(self.deref(self.registers[1])); read_heap_cell!(a1, - (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum | + (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // | HeapCellValueTag::Char HeapCellValueTag::F64) => { self.try_functor_unify_components(a1, 0); } @@ -1347,7 +1092,7 @@ impl MachineState { let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); self.try_functor_compound_case(name, arity); } - (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { + (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { // | HeapCellValueTag::CStr) => { self.try_functor_compound_case(atom!("."), 2); } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { @@ -1399,16 +1144,19 @@ impl MachineState { }; read_heap_cell!(store_name, - (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum | + (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // HeapCellValueTag::Char | HeapCellValueTag::F64) if arity == 0 => { self.bind(a1.as_var().unwrap(), deref_name); } (HeapCellValueTag::Atom, (name, atom_arity)) => { debug_assert_eq!(atom_arity, 0); - self.try_functor_fabricate_struct( - name, - arity as usize, - a1.as_var().unwrap(), + resource_error_call_result!( + self, + self.try_functor_fabricate_struct( + name, + arity as usize, + a1.as_var().unwrap(), + ) ); } (HeapCellValueTag::Str, s) => { @@ -1416,25 +1164,33 @@ impl MachineState { .get_name_and_arity(); if atom_arity == 0 { - self.try_functor_fabricate_struct( - name, - arity as usize, - a1.as_var().unwrap(), + resource_error_call_result!( + self, + self.try_functor_fabricate_struct( + name, + arity as usize, + a1.as_var().unwrap(), + ) ); } else { let err = self.type_error(ValidType::Atomic, store_name); return Err(self.error_form(err, stub_gen())); } } + /* (HeapCellValueTag::Char, c) => { let c = AtomTable::build_with(&self.atom_tbl, &c.to_string()); - self.try_functor_fabricate_struct( - c, - arity as usize, - a1.as_var().unwrap(), + resource_error_call_result!( + self, + self.try_functor_fabricate_struct( + c, + arity as usize, + a1.as_var().unwrap(), + ) ); } + */ (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64) if arity != 0 => { let err = self.type_error(ValidType::Atom, store_name); @@ -1457,7 +1213,7 @@ impl MachineState { pub fn try_from_list( &mut self, value: HeapCellValue, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, ) -> Result, MachineStub> { let value = self.store(self.deref(value)); @@ -1465,8 +1221,8 @@ impl MachineState { (HeapCellValueTag::Lis, l) => { self.try_from_inner_list(vec![], l, stub_gen, value) } - (HeapCellValueTag::PStrLoc, h) => { - self.try_from_partial_string(vec![], h, stub_gen, value) + (HeapCellValueTag::PStrLoc, pstr_loc) => { + self.try_from_partial_string(vec![], pstr_loc, stub_gen, value) } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { let err = self.instantiation_error(); @@ -1491,10 +1247,12 @@ impl MachineState { Err(self.error_form(err, stub_gen())) } } + /* (HeapCellValueTag::CStr, cstr_atom) => { let cstr = cstr_atom.as_str(); Ok(cstr.chars().map(|c| char_as_cell!(c)).collect()) } + */ _ => { let err = self.type_error(ValidType::List, value); Err(self.error_form(err, stub_gen())) @@ -1506,7 +1264,7 @@ impl MachineState { &mut self, mut result: Vec, mut l: usize, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, a1: HeapCellValue, ) -> Result, MachineStub> { result.push(self.heap[l]); @@ -1520,8 +1278,8 @@ impl MachineState { result.push(self.heap[hcp]); l = hcp + 1; } - (HeapCellValueTag::PStrLoc, l) => { - return self.try_from_partial_string(result, l, stub_gen, a1); + (HeapCellValueTag::PStrLoc, pstr_loc) => { + return self.try_from_partial_string(result, pstr_loc, stub_gen, a1); } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.heap[s]) @@ -1560,52 +1318,34 @@ impl MachineState { fn try_from_partial_string( &mut self, mut chars: Vec, - h: usize, - stub_gen: impl Fn() -> FunctorStub, + pstr_loc: usize, + stub_gen: impl Fn() -> MachineStub, a1: HeapCellValue, ) -> Result, MachineStub> { - let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h); + self.heap[0] = pstr_loc_as_cell!(pstr_loc); + let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, 0); - for iteratee in heap_pstr_iter.by_ref() { + while let Some(iteratee) = heap_pstr_iter.next() { match iteratee { - PStrIteratee::Char(_, c) => chars.push(char_as_cell!(c)), - PStrIteratee::PStrSegment(_, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - chars.extend(pstr.as_str_from(n).chars().map(|c| char_as_cell!(c))); + PStrIteratee::Char { value: c, .. } => chars.push(char_as_cell!(c)), + PStrIteratee::PStrSlice { + slice_loc, + slice_len, + } => { + let pstr = heap_pstr_iter.heap.slice_to_str(slice_loc, slice_len); + chars.extend(pstr.chars().map(|c| char_as_cell!(c))); } } } - match self.heap[h].get_tag() { - HeapCellValueTag::PStr => { - if heap_pstr_iter.at_string_terminator() { - Ok(chars) - } else { - read_heap_cell!(self.heap[heap_pstr_iter.focus()], - (HeapCellValueTag::Lis, l) => { - self.try_from_inner_list(chars, l, stub_gen, a1) - } - (HeapCellValueTag::Atom, (name, arity)) => { - if name == atom!(".") && arity == 2 { - let l = heap_pstr_iter.focus() + 1; - self.try_from_inner_list(chars, l, stub_gen, a1) - } else { - let err = self.type_error(ValidType::List, a1); - Err(self.error_form(err, stub_gen())) - } - } - _ => { - let err = self.type_error(ValidType::List, a1); - Err(self.error_form(err, stub_gen())) - } - ) - } - } - HeapCellValueTag::CStr => Ok(chars), - _ => { - unreachable!() - } + let end_cell = heap_pstr_iter.heap[heap_pstr_iter.focus()]; + + if heap_pstr_iter.is_cyclic() || end_cell == empty_list_as_cell!() { + let err = self.type_error(ValidType::List, a1); + return Err(self.error_form(err, stub_gen())); } + + Ok(chars) } // returns true on failure. @@ -1624,7 +1364,7 @@ impl MachineState { pub fn integers_to_bytevec( &mut self, value: HeapCellValue, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, ) -> Vec { let mut bytes: Vec = Vec::new(); diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index badd6255..e0551a60 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -4,16 +4,12 @@ pub use crate::machine::machine_state::*; pub use crate::machine::streams::*; pub use crate::machine::*; pub use crate::parser::ast::*; -use crate::read::*; -pub use crate::types::*; - -use std::sync::Arc; #[cfg(test)] use crate::machine::copier::CopierTarget; #[cfg(test)] -use std::ops::{Deref, DerefMut, Index, IndexMut}; +use std::ops::{Deref, DerefMut, Index, IndexMut, Range}; // a mini-WAM for test purposes. @@ -31,7 +27,6 @@ impl MockWAM { Self { machine_st: MachineState::new(), op_dir, - //flags: MachineFlags::default(), } } @@ -56,7 +51,7 @@ impl MockWAM { ) -> Result { let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?; - print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc); + print_heap_terms(self.machine_st.heap.splice(..), term_write_result.focus); let var_names = term_write_result .inverse_var_locs @@ -68,11 +63,10 @@ impl MockWAM { let mut printer = HCPrinter::new( &mut self.machine_st.heap, - Arc::clone(&self.machine_st.atom_tbl), &mut self.machine_st.stack, &self.op_dir, PrinterOutputter::new(), - term_write_result.heap_loc, + term_write_result.focus, ); printer.var_names = var_names; @@ -154,10 +148,6 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> { } } - fn push(&mut self, val: HeapCellValue) { - self.wam.machine_st.heap.push(val); - } - fn push_attr_var_queue(&mut self, attr_var_loc: usize) { self.wam .machine_st @@ -171,43 +161,123 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> { } fn threshold(&self) -> usize { - self.wam.machine_st.heap.len() + self.wam.machine_st.heap.cell_len() + } + + #[inline(always)] + fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result { + self.wam.machine_st.heap.copy_pstr_within(pstr_loc) + } + + #[inline(always)] + fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize { + self.wam.machine_st.heap.pstr_vec()[0 .. cell_index!(pstr_loc)] + .last_zero() + .map(|idx| idx + 1) + .unwrap_or(0) + } + + #[inline(always)] + fn pstr_at(&self, loc: usize) -> bool { + self.wam.machine_st.heap.pstr_vec()[loc] + } + + #[inline(always)] + fn next_non_pstr_cell_index(&self, loc: usize) -> usize { + // unwrap is safe here because a partial string is always + // followed by a tail cell, i.e. a non-pstr cell, supposing + // self.machine_st.heap[loc] is a pstr cell + self.wam.machine_st.heap.pstr_vec()[loc ..].first_zero() + .map(|idx| idx + loc) + .unwrap() + } + + #[inline(always)] + fn reserve(&mut self, num_cells: usize) -> Result { + self.wam.machine_st.heap.reserve(num_cells) + } + + #[inline(always)] + fn copy_slice_to_end(&mut self, bounds: Range) -> Result<(), usize> { + self.wam.machine_st.heap.copy_slice_to_end(bounds) } } #[cfg(test)] -pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) { - for (idx, cell) in heap.iter().enumerate() { +pub fn all_cells_marked_and_unforwarded(iter: impl SizedHeap) { + let mut idx = 0; + let cell_len = iter.cell_len(); + + while idx < cell_len { + let curr_idx = idx; + let cell = if iter.pstr_at(idx) { + let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx)); + idx = last_cell_loc; + iter[last_cell_loc - 1] + } else { + idx += 1; + iter[curr_idx] + }; + assert!( cell.get_mark_bit(), "cell {:?} at index {} is not marked", cell, - idx + curr_idx ); assert!( !cell.get_forwarding_bit(), "cell {:?} at index {} is forwarded", cell, - idx + curr_idx ); } } #[cfg(test)] -pub fn all_cells_unmarked(heap: &Heap) { - for (idx, cell) in heap.iter().enumerate() { +pub fn unmark_all_cells(mut iter: impl SizedHeapMut) { + let mut idx = 0; + let cell_len = iter.cell_len(); + + while idx < cell_len { + if iter.pstr_at(idx) { + iter[idx].set_mark_bit(false); + + let last_cell_loc = { + let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx)); + last_cell_loc + }; + + iter[last_cell_loc].set_mark_bit(false); + idx = last_cell_loc; + } else { + iter[idx].set_mark_bit(false); + idx += 1; + } + } +} + +#[cfg(test)] +pub fn all_cells_unmarked(iter: impl SizedHeap) { + let mut idx = 0; + let cell_len = iter.cell_len(); + + while idx < cell_len { + let curr_idx = idx; + let cell = if iter.pstr_at(idx) { + let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx)); + idx = last_cell_loc; + iter[last_cell_loc - 1] + } else { + idx += 1; + iter[curr_idx] + }; + assert!( !cell.get_mark_bit(), "cell {:?} at index {} is still marked", cell, - idx - ); - - assert!( - !cell.get_forwarding_bit(), - "cell {:?} at index {} is still forwarded", - cell, - idx + curr_idx ); } } @@ -256,6 +326,8 @@ impl Machine { mod tests { use super::*; + use crate::functor_macro::FunctorElement; + #[test] fn unify_tests() { let mut wam = MachineState::new(); @@ -276,13 +348,13 @@ mod tests { unify!( wam, str_loc_as_cell!(0), - str_loc_as_cell!(term_write_result_2.heap_loc) + str_loc_as_cell!(term_write_result_2.focus) ); assert!(wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -296,14 +368,14 @@ mod tests { unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -317,14 +389,14 @@ mod tests { unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -338,14 +410,14 @@ mod tests { unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -359,14 +431,14 @@ mod tests { unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -378,95 +450,119 @@ mod tests { let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.heap.clear(); - wam.heap.push(pstr_as_cell!(atom!("this is a string"))); - wam.heap.push(heap_loc_as_cell!(1)); + let mut writer = wam.heap.reserve(96).unwrap(); - wam.heap.push(pstr_as_cell!(atom!("this is a string"))); - wam.heap.push(pstr_loc_as_cell!(4)); + writer.write_with(|section| { + section.push_pstr("this is a string"); // 0 - wam.heap.push(pstr_offset_as_cell!(0)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6))); + let h = section.cell_len(); + assert_eq!(h, 3); - unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2)); + section.push_cell(heap_loc_as_cell!(h)); // 3 + section.push_pstr("this is a string"); // 4 + + let h = section.cell_len(); + assert_eq!(h + 1, 8); + + section.push_cell(pstr_loc_as_cell!(heap_index!(h + 1))); // 7 + section.push_pstr("this is a string"); // 8 + + section.push_cell(pstr_loc_as_cell!(heap_index!(h + 1))); + }); + + unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(heap_index!(4))); assert!(!wam.fail); - assert_eq!(wam.heap[1], pstr_loc_as_cell!(4)); + assert_eq!(wam.heap[3], pstr_loc_as_cell!(heap_index!(8))); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.heap.clear(); - wam.heap.push(list_loc_as_cell!(1)); - wam.heap.push(atom_as_cell!(atom!("a"))); - wam.heap.push(list_loc_as_cell!(3)); - wam.heap.push(atom_as_cell!(atom!("b"))); - wam.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.heap.reserve(96).unwrap(); - wam.heap.push(list_loc_as_cell!(6)); - wam.heap.push(atom_as_cell!(atom!("a"))); - wam.heap.push(list_loc_as_cell!(8)); - wam.heap.push(atom_as_cell!(atom!("b"))); - wam.heap.push(heap_loc_as_cell!(5)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("a"))); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(atom!("b"))); + section.push_cell(heap_loc_as_cell!(0)); + + section.push_cell(list_loc_as_cell!(6)); + section.push_cell(atom_as_cell!(atom!("a"))); + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(atom_as_cell!(atom!("b"))); + section.push_cell(heap_loc_as_cell!(5)); + }); unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); assert!(!wam.fail); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.heap.clear(); - wam.heap.push(list_loc_as_cell!(1)); - wam.heap.push(atom_as_cell!(atom!("a"))); - wam.heap.push(list_loc_as_cell!(3)); - wam.heap.push(atom_as_cell!(atom!("b"))); - wam.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.heap.reserve(96).unwrap(); - wam.heap.push(list_loc_as_cell!(6)); - wam.heap.push(atom_as_cell!(atom!("a"))); - wam.heap.push(list_loc_as_cell!(8)); - wam.heap.push(atom_as_cell!(atom!("c"))); - wam.heap.push(heap_loc_as_cell!(5)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("a"))); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(atom!("b"))); + section.push_cell(heap_loc_as_cell!(0)); + + section.push_cell(list_loc_as_cell!(6)); + section.push_cell(atom_as_cell!(atom!("a"))); + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(atom_as_cell!(atom!("c"))); + section.push_cell(heap_loc_as_cell!(5)); + }); unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); assert!(wam.fail); wam.fail = false; - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); + wam.heap.clear(); - wam.heap.push(list_loc_as_cell!(1)); - wam.heap.push(atom_as_cell!(atom!("a"))); - wam.heap.push(list_loc_as_cell!(3)); - wam.heap.push(atom_as_cell!(atom!("b"))); - wam.heap.push(heap_loc_as_cell!(5)); + let mut writer = wam.heap.reserve(96).unwrap(); - wam.heap.push(list_loc_as_cell!(6)); - wam.heap.push(atom_as_cell!(atom!("a"))); - wam.heap.push(list_loc_as_cell!(8)); - wam.heap.push(atom_as_cell!(atom!("b"))); - wam.heap.push(heap_loc_as_cell!(0)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("a"))); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(atom!("b"))); + section.push_cell(heap_loc_as_cell!(5)); + + section.push_cell(list_loc_as_cell!(6)); + section.push_cell(atom_as_cell!(atom!("a"))); + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(atom_as_cell!(atom!("b"))); + section.push_cell(heap_loc_as_cell!(0)); + }); unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); assert!(!wam.fail); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); } #[test] @@ -485,12 +581,12 @@ mod tests { let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); unify_with_occurs_check!( wam, heap_loc_as_cell!(0), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(wam.fail); @@ -503,8 +599,15 @@ mod tests { let mut wam = MachineState::new(); - wam.heap.push(heap_loc_as_cell!(0)); - wam.heap.push(heap_loc_as_cell!(1)); + // clear the heap of resource error data etc + wam.heap.clear(); + + let mut writer = wam.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(heap_loc_as_cell!(1)); + }); assert_eq!( compare_term_test!(wam, wam.heap[0], wam.heap[1]), @@ -526,11 +629,13 @@ mod tests { Some(Ordering::Equal) ); + let cstr_cell = wam.allocate_cstr("string").unwrap(); + assert_eq!( compare_term_test!( wam, atom_as_cell!(atom!("atom")), - atom_as_cstr_cell!(atom!("string")) + cstr_cell ), Some(Ordering::Less) ); @@ -564,8 +669,12 @@ mod tests { wam.heap.clear(); - wam.heap.push(atom_as_cell!(atom!("f"), 1)); - wam.heap.push(heap_loc_as_cell!(1)); + let mut writer = wam.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("f"), 1)); + section.push_cell(heap_loc_as_cell!(1)); + }); assert_eq!( compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(0)), @@ -579,21 +688,25 @@ mod tests { wam.heap.clear(); - // [1,2,3] - wam.heap.push(list_loc_as_cell!(1)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); - wam.heap.push(list_loc_as_cell!(3)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); - wam.heap.push(list_loc_as_cell!(5)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3))); - wam.heap.push(empty_list_as_cell!()); + let mut writer = wam.heap.reserve(96).unwrap(); - // [1,2] - wam.heap.push(list_loc_as_cell!(8)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); - wam.heap.push(list_loc_as_cell!(10)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); - wam.heap.push(empty_list_as_cell!()); + writer.write_with(|section| { + // [1,2,3] + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(1))); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(2))); + section.push_cell(list_loc_as_cell!(5)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(3))); + section.push_cell(empty_list_as_cell!()); + + // [1,2] + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(1))); + section.push_cell(list_loc_as_cell!(10)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(2))); + section.push_cell(empty_list_as_cell!()); + }); assert_eq!( compare_term_test!(wam, heap_loc_as_cell!(7), heap_loc_as_cell!(7)), @@ -619,11 +732,13 @@ mod tests { Some(Ordering::Greater) ); + let cstr_cell = wam.allocate_cstr("string").unwrap(); + assert_eq!( compare_term_test!( wam, empty_list_as_cell!(), - atom_as_cstr_cell!(atom!("string")) + cstr_cell ), Some(Ordering::Less) ); @@ -655,55 +770,66 @@ mod tests { fn is_cyclic_term_tests() { let mut wam = MachineState::new(); - assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f")))); - assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555)))); + let mut writer = wam.heap.reserve(96).unwrap(); - wam.heap.push(heap_loc_as_cell!(0)); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("f"))); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(555))); + section.push_cell(heap_loc_as_cell!(0)); + }); - assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0))); + assert!(!wam.is_cyclic_term(0)); + assert!(!wam.is_cyclic_term(1)); + assert!(!wam.is_cyclic_term(2)); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.heap.clear(); - wam.heap - .extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))])); + let mut functor_writer = Heap::functor_writer( + functor!( + atom!("f"), + [atom_as_cell((atom!("a"))), + atom_as_cell((atom!("b")))] + ), + ); - assert!(!wam.is_cyclic_term(str_loc_as_cell!(0))); + functor_writer(&mut wam.heap).unwrap(); - all_cells_unmarked(&wam.heap); + let h = wam.heap.cell_len(); + wam.heap.push_cell(str_loc_as_cell!(0)).unwrap(); - assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1))); + assert!(!wam.is_cyclic_term(h)); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); - assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2))); + assert!(!wam.is_cyclic_term(1)); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); + + assert!(!wam.is_cyclic_term(2)); + + all_cells_unmarked(wam.heap.splice(..)); wam.heap[2] = str_loc_as_cell!(0); print_heap_terms(wam.heap.iter(), 0); - assert!(wam.is_cyclic_term(str_loc_as_cell!(0))); + assert!(wam.is_cyclic_term(2)); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.heap[2] = atom_as_cell!(atom!("b")); wam.heap[1] = str_loc_as_cell!(0); - assert!(wam.is_cyclic_term(str_loc_as_cell!(0))); + assert!(wam.is_cyclic_term(1)); - all_cells_unmarked(&wam.heap); - - assert!(wam.is_cyclic_term(heap_loc_as_cell!(1))); - - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.heap.clear(); - wam.heap.push(pstr_as_cell!(atom!("a string"))); - wam.heap.push(empty_list_as_cell!()); + let h = wam.heap.cell_len(); + wam.allocate_cstr("a string").unwrap(); - assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0))); + assert!(!wam.is_cyclic_term(h)); } } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index d180f02d..06abf425 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -485,7 +485,10 @@ impl Machine { #[inline(always)] pub(crate) fn run_verify_attr_interrupt(&mut self, arity: usize) { let p = self.machine_st.attr_var_init.verify_attrs_loc; - self.machine_st.verify_attr_interrupt(p, arity); + step_or_resource_error!( + self.machine_st, + self.machine_st.verify_attr_interrupt(p, arity) + ); } fn next_clause_applicable(&mut self, mut offset: usize) -> bool { @@ -505,12 +508,11 @@ impl Machine { s, )) => { cell = self.deref_register(arg); - self.machine_st - .select_switch_on_term_index(cell, v, c, l, s) + self.machine_st.select_switch_on_term_index(cell, v, c, l, s) } IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => { - let lit = self.machine_st.constant_to_literal(cell); - hm.get(&lit).cloned().unwrap_or(IndexingCodePtr::Fail) + // let lit = self.machine_st.constant_to_literal(cell); + hm.get(&cell).cloned().unwrap_or(IndexingCodePtr::Fail) } IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => { self.machine_st.select_switch_on_structure_index(cell, hm) @@ -536,6 +538,7 @@ impl Machine { if cell.is_var() { offset += 1; + /* } else if lit.get_tag() == HeapCellValueTag::CStr { read_heap_cell!(cell, (HeapCellValueTag::CStr) => { @@ -562,8 +565,10 @@ impl Machine { return false; } ); + */ } else { - self.machine_st.write_literal_to_var(cell, lit); + unify!(self.machine_st, cell, lit); + // self.machine_st.write_literal_to_var(cell, lit); if self.machine_st.fail { self.machine_st.fail = false; @@ -577,7 +582,7 @@ impl Machine { let cell = self.deref_register(t); read_heap_cell!(cell, - (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { + (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {// | HeapCellValueTag::CStr) => { offset += 1; } (HeapCellValueTag::Str, s) => { @@ -618,25 +623,32 @@ impl Machine { } &Instruction::GetPartialString( Level::Shallow, - string, + ref string, RegType::Temp(t), - has_tail, + // has_tail, ) => { + use crate::machine::partial_string::HeapPStrIter; + let cell = self.deref_register(t); read_heap_cell!(cell, - (HeapCellValueTag::CStr, cstr) => { - if !has_tail && string != cstr { + (HeapCellValueTag::PStrLoc) => { + self.machine_st.heap[0] = cell; + let iter = HeapPStrIter::new(&self.machine_st.heap, 0); + + if iter.compare_pstr_to_string(&string).is_none() { return false; } offset += 1; + } - (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { + (HeapCellValueTag::Lis) => { offset += 1; } (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity(); + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) + .get_name_and_arity(); if name == atom!(".") && arity == 2 { offset += 1; @@ -759,7 +771,7 @@ impl Machine { or_frame.prelude.boip = 0; or_frame.prelude.biip = 0; or_frame.prelude.tr = self.machine_st.tr; - or_frame.prelude.h = self.machine_st.heap.len(); + or_frame.prelude.h = self.machine_st.heap.cell_len(); or_frame.prelude.b0 = self.machine_st.b0; or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len(); @@ -770,7 +782,7 @@ impl Machine { or_frame[i] = self.machine_st.registers[i + 1]; } - self.machine_st.hb = self.machine_st.heap.len(); + self.machine_st.hb = self.machine_st.heap.cell_len(); } self.machine_st.p += 1; @@ -791,7 +803,7 @@ impl Machine { or_frame.prelude.boip = self.machine_st.oip; or_frame.prelude.biip = self.machine_st.iip + iip_offset; // 1 or_frame.prelude.tr = self.machine_st.tr; - or_frame.prelude.h = self.machine_st.heap.len(); + or_frame.prelude.h = self.machine_st.heap.cell_len(); or_frame.prelude.b0 = self.machine_st.b0; or_frame.prelude.attr_var_queue_len = self.machine_st.attr_var_init.attr_var_queue.len(); @@ -802,7 +814,7 @@ impl Machine { or_frame[i] = self.machine_st.registers[i + 1]; } - self.machine_st.hb = self.machine_st.heap.len(); + self.machine_st.hb = self.machine_st.heap.cell_len(); // self.machine_st.oip = 0; // self.machine_st.iip = 0; diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 6a6ba96d..6176e73a 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -1,78 +1,27 @@ use crate::atom_table::*; -use crate::parser::ast::*; use crate::machine::heap::*; use crate::machine::machine_errors::CycleSearchResult; use crate::machine::system_calls::BrentAlgState; use crate::types::*; -use std::cmp::Ordering; use std::ops::Deref; use std::str; -#[derive(Copy, Clone, Debug)] -pub struct PartialString(Atom); - -fn scan_for_terminator>(iter: Iter) -> usize { - let mut terminator_idx = 0; - - for c in iter { - if c == '\u{0}' && terminator_idx != 0 { - return terminator_idx; - } - - terminator_idx += c.len_utf8(); - } - - terminator_idx -} - -impl From for PartialString { - #[inline] - fn from(buf: Atom) -> PartialString { - PartialString(buf) - } -} - -impl From for Atom { - #[inline] - fn from(val: PartialString) -> Self { - val.0 - } -} - -impl PartialString { - #[inline] - pub(super) fn new<'a>(src: &'a str, atom_tbl: &AtomTable) -> Option<(Self, &'a str)> { - let terminator_idx = scan_for_terminator(src.chars()); - let pstr = PartialString(AtomTable::build_with(atom_tbl, &src[..terminator_idx])); - Some(if terminator_idx < src.as_bytes().len() { - (pstr, &src[terminator_idx + 1..]) - } else { - (pstr, "") - }) - } - - #[inline(always)] - pub(crate) fn as_str_from(&self, n: usize) -> AtomString { - self.0.as_str().map(|str| &str[n..]) - } -} - #[derive(Clone, Copy)] pub struct HeapPStrIter<'a> { - pub heap: &'a [HeapCellValue], - pub focus: HeapCellValue, + pub heap: &'a Heap, + // pub focus: HeapCellValue, orig_focus: usize, brent_st: BrentAlgState, stepper: fn(&mut HeapPStrIter<'a>) -> Option, } #[derive(Debug, Clone, Copy)] -pub struct PStrPrefixCmpResult { - pub focus: usize, - pub offset: usize, - pub prefix_len: usize, +pub enum PStrCmpResult<'a> { + ListMatch { list_loc: usize }, + CompletePStrMatch { chars_matched: usize, pstr_loc: usize }, + PartialPStrMatch { string: &'a str, var_loc: usize }, } struct PStrIterStep { @@ -80,15 +29,20 @@ struct PStrIterStep { next_hare: usize, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PStrIteratee { + Char { heap_loc: usize, value: char }, + PStrSlice { slice_loc: usize, slice_len: usize }, +} + impl<'a> HeapPStrIter<'a> { - pub fn new(heap: &'a [HeapCellValue], h: usize) -> Self { - let value = heap[h]; + pub fn new(heap: &'a Heap, orig_focus: usize) -> Self { + debug_assert!(heap[orig_focus].is_ref()); Self { heap, - focus: value, - orig_focus: h, - brent_st: BrentAlgState::new(h), + orig_focus, + brent_st: BrentAlgState::new(orig_focus), stepper: HeapPStrIter::pre_cycle_discovery_stepper, } } @@ -98,97 +52,83 @@ impl<'a> HeapPStrIter<'a> { self.brent_st.hare } - #[inline(always)] - pub fn at_string_terminator(&self) -> bool { - self.focus.is_string_terminator(self.heap) - } + pub fn compare_pstr_to_string<'b>(self, mut s: &'b str) -> Option> { + let mut curr_hare = self.brent_st.hare; - #[inline(always)] - pub fn chars(mut self) -> PStrCharsIter<'a> { - let item = self.next(); - PStrCharsIter { iter: self, item } - } + while !s.is_empty() { + read_heap_cell!(self.heap[curr_hare], + (HeapCellValueTag::PStrLoc, h) => { + let t = self.heap.slice_to_str(h, self.heap.byte_len() - h); - pub fn compare_pstr_to_string(&mut self, s: &str) -> Option { - let mut result = PStrPrefixCmpResult { - focus: self.brent_st.hare, - offset: 0, - prefix_len: 0, - }; + let mut bytes_matched = 0; + let mut chars_matched = 0; - let mut final_result = None; - - while let Some(PStrIterStep { - iteratee, - next_hare, - }) = self.step(self.brent_st.hare) - { - self.brent_st.hare = next_hare; - self.focus = self.heap[iteratee.focus()]; - - result.focus = iteratee.focus(); - result.offset = iteratee.offset(); - - match iteratee { - PStrIteratee::Char(_, c1) => { - if let Some(c2) = s[result.prefix_len..].chars().next() { - if c1 != c2 { - return None; - } else { - result.prefix_len += c1.len_utf8(); - result.offset += c1.len_utf8(); + for (sc, tc) in s.chars().zip(t.chars()) { + if sc != tc { + if tc != '\u{0}' { + return None; + } else { + break; + } } + + bytes_matched += sc.len_utf8(); + chars_matched += 1; + } + + s = &s[bytes_matched ..]; + + if s.is_empty() { + return Some(PStrCmpResult::CompletePStrMatch { chars_matched, pstr_loc: h }); } else { - final_result = Some(result); - break; + let next_hare = Heap::neighboring_cell_offset(h + bytes_matched); + curr_hare = next_hare; } } - PStrIteratee::PStrSegment(_, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - let t = pstr.as_str_from(n); - let s = &s[result.prefix_len..]; + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h == curr_hare { + return Some(PStrCmpResult::PartialPStrMatch { string: s, var_loc: h }); + } - if s.len() >= t.len() { - if s.starts_with(&*t) { - result.prefix_len += t.len(); - result.offset += t.len(); - } else { + curr_hare = h; + continue; + } + _ => { + match self.step(curr_hare).ok() { + Some(PStrIterStep { iteratee, next_hare }) => { + let value = if let PStrIteratee::Char { value, .. } = iteratee { + value + } else { + unreachable!() + }; + + let c = s.chars().next().unwrap(); + + if c == value { + s = &s[c.len_utf8() ..]; + + if s.is_empty() { + return Some( + PStrCmpResult::ListMatch { + list_loc: next_hare, + } + ); + } + + curr_hare = next_hare; + } else { + return None; + } + } + None => { return None; } - } else if t.starts_with(s) { - result.prefix_len += s.len(); - result.offset += s.len(); - - final_result = Some(result); - break; - } else { - return None; } } - } - - if s.len() == result.prefix_len { - final_result = Some(result); - break; - } + ); } - if let Some(result) = &final_result { - if self.at_string_terminator() { - self.focus = empty_list_as_cell!(); - self.brent_st.hare = result.focus; - } else { - read_heap_cell!(self.heap[result.focus], - (HeapCellValueTag::Lis | HeapCellValueTag::Str | HeapCellValueTag::PStr) => { - self.focus = self.heap[self.brent_st.hare]; - } - _ => { - } - ); - } - } - - Some(result) + None } fn walk_hare_to_cycle_end(&mut self) { @@ -209,21 +149,23 @@ impl<'a> HeapPStrIter<'a> { self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare; } - self.focus = self.heap[orig_hare]; + // self.focus = self.heap[orig_hare]; self.brent_st.hare = orig_hare; } pub fn to_string_mut(&mut self) -> String { let mut buf = String::with_capacity(32); - for iteratee in self.by_ref() { + while let Some(iteratee) = self.next() { match iteratee { - PStrIteratee::Char(_, c) => { + PStrIteratee::Char { value: c, .. } => { buf.push(c); } - PStrIteratee::PStrSegment(_, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - buf += &*pstr.as_str_from(n); + PStrIteratee::PStrSlice { + slice_loc, + slice_len, + } => { + buf += self.heap.slice_to_str(slice_loc, slice_len); } } } @@ -231,98 +173,19 @@ impl<'a> HeapPStrIter<'a> { buf } - #[inline] - pub fn is_continuable(&self) -> bool { - let mut focus = self.focus; - - loop { - read_heap_cell!(focus, - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - return true; - } - (HeapCellValueTag::Atom, (name, arity)) => { // TODO: use Str here? - return name == atom!(".") && arity == 2; - } - (HeapCellValueTag::Lis, h) => { - let value = self.heap[h]; - let value = heap_bound_store( - self.heap, - heap_bound_deref(self.heap, value), - ); - - return read_heap_cell!(value, - (HeapCellValueTag::Atom, (name, arity)) => { - arity == 0 && name.as_char().is_some() - } - (HeapCellValueTag::Char) => { - true - } - _ => { - false - } - ); - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if focus == self.heap[h] { - return false; - } - - focus = self.heap[h]; - } - _ => { - return false; - } - ); - } - } - - #[inline(always)] - pub fn cycle_detected(&self) -> bool { - self.stepper as usize == HeapPStrIter::post_cycle_discovery_stepper as usize - } - - fn step(&self, mut curr_hare: usize) -> Option { + // return the next step in the iteration or the updated curr_hare + // for the sake of pointing to the pstr tail + fn step(&self, mut curr_hare: usize) -> Result { loop { read_heap_cell!(self.heap[curr_hare], - (HeapCellValueTag::CStr, cstr_atom) => { - return if self.focus == empty_list_as_cell!() { - None - } else { - Some(PStrIterStep { - iteratee: PStrIteratee::PStrSegment(curr_hare, cstr_atom, 0), - next_hare: curr_hare, - }) - } - } (HeapCellValueTag::PStrLoc, h) => { - curr_hare = h; - } - (HeapCellValueTag::PStr, pstr_atom) => { - return Some(PStrIterStep { - iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, 0), - next_hare: curr_hare+1, + let (s, tail_loc) = self.heap.scan_slice_to_str(h); + + return Ok(PStrIterStep { + iteratee: PStrIteratee::PStrSlice { slice_loc: h, slice_len: s.len() }, + next_hare: tail_loc, }); } - (HeapCellValueTag::PStrOffset, pstr_offset) => { - if self.focus == empty_list_as_cell!() { - return None; - } - - let pstr_atom = cell_as_atom!(self.heap[pstr_offset]); - let n = cell_as_fixnum!(self.heap[curr_hare+1]).get_num() as usize; - - return if self.heap[pstr_offset].get_tag() == HeapCellValueTag::CStr { - Some(PStrIterStep { - iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n), - next_hare: pstr_offset, - }) - } else { - Some(PStrIterStep { - iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n), - next_hare: pstr_offset+1, - }) - }; - } (HeapCellValueTag::Lis, h) => { let value = heap_bound_store( self.heap, @@ -330,9 +193,9 @@ impl<'a> HeapPStrIter<'a> { ); return value.as_char().map(|c| PStrIterStep { - iteratee: PStrIteratee::Char(curr_hare, c), + iteratee: PStrIteratee::Char { heap_loc: curr_hare, value: c }, next_hare: h+1, - }); + }).ok_or(curr_hare) } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.heap[s]) @@ -345,26 +208,26 @@ impl<'a> HeapPStrIter<'a> { ); value.as_char().map(|c| PStrIterStep { - iteratee: PStrIteratee::Char(curr_hare, c), + iteratee: PStrIteratee::Char { heap_loc: curr_hare, value: c }, next_hare: s+2, - }) + }).ok_or(curr_hare) } else { - None + Err(curr_hare) }; } (HeapCellValueTag::Atom, (_name, arity)) => { debug_assert!(arity == 0); - return None; + return Err(curr_hare); } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if h == curr_hare { - return None; + return Err(curr_hare); } curr_hare = h; } _ => { - return None; + return Err(curr_hare); } ); } @@ -375,30 +238,22 @@ impl<'a> HeapPStrIter<'a> { iteratee, next_hare, } = match self.step(self.brent_st.hare) { - Some(results) => results, - None => { + Ok(results) => results, + Err(next_hare) => { + self.brent_st.hare = next_hare; return None; } }; - self.focus = self.heap[iteratee.focus()]; - - if self.at_string_terminator() { - self.focus = empty_list_as_cell!(); - self.brent_st.hare = iteratee.focus(); - - return Some(iteratee); - } - match self.brent_st.step(next_hare) { Some(cycle_result) => { - debug_assert!(matches!(cycle_result, CycleSearchResult::Cyclic(..))); + debug_assert!(matches!(cycle_result, CycleSearchResult::Cyclic { .. })); self.walk_hare_to_cycle_end(); self.stepper = HeapPStrIter::post_cycle_discovery_stepper; } None => { - self.focus = self.heap[next_hare]; + // self.focus = self.heap[next_hare]; } } @@ -414,40 +269,21 @@ impl<'a> HeapPStrIter<'a> { iteratee, next_hare, } = match self.step(self.brent_st.hare) { - Some(results) => results, - None => { + Ok(results) => results, + Err(next_hare) => { + self.brent_st.hare = next_hare; return None; } }; - self.focus = self.heap[next_hare]; + // self.focus = self.heap[next_hare]; self.brent_st.hare = next_hare; Some(iteratee) } -} -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PStrIteratee { - Char(usize, char), - PStrSegment(usize, Atom, usize), -} - -impl PStrIteratee { - #[inline] - fn offset(&self) -> usize { - match self { - PStrIteratee::Char(_, _) => 0, - PStrIteratee::PStrSegment(_, _, n) => *n, - } - } - - #[inline] - fn focus(&self) -> usize { - match self { - PStrIteratee::Char(focus, _) => *focus, - PStrIteratee::PStrSegment(focus, _, _) => *focus, - } + pub(crate) fn is_cyclic(&self) -> bool { + self.stepper as usize == Self::post_cycle_discovery_stepper as usize } } @@ -465,24 +301,6 @@ pub struct PStrCharsIter<'a> { pub item: Option, } -impl<'a> PStrCharsIter<'a> { - pub fn peek(&self) -> Option { - if let Some(iteratee) = self.item { - match iteratee { - PStrIteratee::Char(_, c) => { - return Some(c); - } - PStrIteratee::PStrSegment(_, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - return pstr.as_str_from(n).chars().next(); - } - } - } - - None - } -} - impl<'a> Deref for PStrCharsIter<'a> { type Target = HeapPStrIter<'a>; @@ -497,18 +315,19 @@ impl<'a> Iterator for PStrCharsIter<'a> { fn next(&mut self) -> Option { while let Some(item) = self.item { match item { - PStrIteratee::Char(_, c) => { + PStrIteratee::Char { value, .. } => { self.item = self.iter.next(); - return Some(c); + return Some(value); } - PStrIteratee::PStrSegment(f1, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); + PStrIteratee::PStrSlice { slice_loc, slice_len } => { + let s = self.iter.heap.slice_to_str(slice_loc, slice_len); - match pstr.as_str_from(n).chars().next() { + match s.chars().next() { Some(c) => { - self.item = - Some(PStrIteratee::PStrSegment(f1, pstr_atom, n + c.len_utf8())); - + self.item = Some(PStrIteratee::PStrSlice { + slice_loc: slice_loc + c.len_utf8(), + slice_len: slice_len - c.len_utf8(), + }); return Some(c); } None => { @@ -523,272 +342,6 @@ impl<'a> Iterator for PStrCharsIter<'a> { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PStrCmpResult { - Ordered(Ordering), - FirstIterContinuable(PStrIteratee), - SecondIterContinuable(PStrIteratee), - Unordered, -} - -impl PStrCmpResult { - #[inline] - pub fn is_second_iter(&self) -> bool { - matches!(self, PStrCmpResult::SecondIterContinuable(_)) - } -} - -#[inline] -pub fn compare_pstr_prefixes<'a>( - i1: &mut HeapPStrIter<'a>, - i2: &mut HeapPStrIter<'a>, -) -> PStrCmpResult { - #[inline(always)] - fn step(iter: &mut HeapPStrIter, hare: usize) -> Option { - let result = iter.step(hare); - iter.focus = iter.heap[hare]; - - if iter.focus.is_string_terminator(iter.heap) { - iter.focus = empty_list_as_cell!(); - } - - result - } - - #[inline(always)] - fn cycle_detection_step(i1: &mut HeapPStrIter, i2: &HeapPStrIter, step: &PStrIterStep) -> bool { - if i1.cycle_detected() { - i1.brent_st.hare = step.next_hare; - i2.cycle_detected() - } else if i1.brent_st.step(step.next_hare).is_some() { - i1.stepper = HeapPStrIter::post_cycle_discovery_stepper; - i2.cycle_detected() - } else { - false - } - } - - let mut r1 = step(i1, i1.brent_st.hare); - let mut r2 = step(i2, i2.brent_st.hare); - - loop { - if let Some(step_1) = r1.as_mut() { - if let Some(step_2) = r2.as_mut() { - match (step_1.iteratee, step_2.iteratee) { - (PStrIteratee::Char(_, c1), PStrIteratee::Char(_, c2)) => { - if c1 != c2 { - return PStrCmpResult::Ordered(c1.cmp(&c2)); - } - - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - } - (PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => { - let pstr = PartialString::from(pstr_atom); - - if let Some(c2) = pstr.as_str_from(n).chars().next() { - if c1 != c2 { - return PStrCmpResult::Ordered(c1.cmp(&c2)); - } - - let n1 = n + c2.len_utf8(); - - if n1 < pstr_atom.len() { - step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1); - - let c1_result = cycle_detection_step(i1, i2, step_1); - r1 = step(i1, i1.brent_st.hare); - - if !c1_result { - continue; - } - } else { - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - } - } else { - let c2_result = cycle_detection_step(i2, i1, step_2); - r2 = step(i2, i2.brent_st.hare); - - if !c2_result { - continue; - } - } - } - (PStrIteratee::PStrSegment(f1, pstr_atom, n), PStrIteratee::Char(_, c2)) => { - let pstr = PartialString::from(pstr_atom); - - if let Some(c1) = pstr.as_str_from(n).chars().next() { - if c1 != c2 { - return PStrCmpResult::Ordered(c1.cmp(&c2)); - } - - let n1 = n + c1.len_utf8(); - - if n1 < pstr_atom.len() { - step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1); - - let c2_result = cycle_detection_step(i2, i1, step_2); - r2 = step(i2, step_2.next_hare); - - if !c2_result { - continue; - } - } else { - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - } - } else { - let c1_result = cycle_detection_step(i1, i2, step_1); - r1 = step(i1, i1.brent_st.hare); - - if !c1_result { - continue; - } - } - } - ( - PStrIteratee::PStrSegment(f1, pstr1_atom, n1), - PStrIteratee::PStrSegment(f2, pstr2_atom, n2), - ) => { - if pstr1_atom == pstr2_atom && n1 == n2 { - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - - break; - } - - let pstr1 = PartialString::from(pstr1_atom); - let pstr2 = PartialString::from(pstr2_atom); - - let str1 = pstr1.as_str_from(n1); - let str2 = pstr2.as_str_from(n2); - - match str1.len().cmp(&str2.len()) { - Ordering::Equal if *str1 == *str2 => { - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - } - Ordering::Less if str2.starts_with(&*str1) => { - step_2.iteratee = - PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len()); - let c1_result = cycle_detection_step(i1, i2, step_1); - r1 = step(i1, i1.brent_st.hare); - - if !c1_result { - continue; - } - } - Ordering::Greater if str1.starts_with(&*str2) => { - step_1.iteratee = - PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len()); - let c2_result = cycle_detection_step(i2, i1, step_2); - r2 = step(i2, i2.brent_st.hare); - - if !c2_result { - continue; - } - } - _ => { - return PStrCmpResult::Ordered(str1.cmp(&*str2)); - } - } - } - } - } - } - - break; - } - - // to have a cyclic term, the cell at i1.focus must be: - // - // 1) 'continuable' as a cell in a string traversal, and, - // 2) matchable by compare_pstr_prefixes to the cell at i2.focus. - // - // If both cells are continuable they must have been encountered - // and thus matched by the compare_pstr_prefixes loop previously, - // so here it suffices to check if they are both continuable. - - let r1_at_end = r1.is_none(); - let r2_at_end = r2.is_none(); - - if r1_at_end && r2_at_end { - if i1.focus == i2.focus { - PStrCmpResult::Ordered(Ordering::Equal) - } else { - PStrCmpResult::Unordered - } - } else if r1_at_end { - if i1.focus == empty_list_as_cell!() { - PStrCmpResult::Ordered(Ordering::Less) - } else { - let r2_step = r2.unwrap(); - - // advance i2 to the next character so the same character - // isn't repeated - if matches!(r2_step.iteratee, PStrIteratee::Char(..)) { - cycle_detection_step(i2, i1, &r2_step); - } - - PStrCmpResult::SecondIterContinuable(r2_step.iteratee) - } - } else if r2_at_end { - if i2.focus == empty_list_as_cell!() { - PStrCmpResult::Ordered(Ordering::Greater) - } else { - let r1_step = r1.unwrap(); - - // advance i1 to the next character so the same character - // isn't repeated - if matches!(r1_step.iteratee, PStrIteratee::Char(..)) { - cycle_detection_step(i1, i2, &r1_step); - } - - PStrCmpResult::FirstIterContinuable(r1_step.iteratee) - } - } else if i1.is_continuable() && i2.is_continuable() { - PStrCmpResult::Ordered(Ordering::Equal) - } else { - PStrCmpResult::Unordered - } -} - #[cfg(test)] mod test { use super::*; @@ -799,233 +352,158 @@ mod test { fn pstr_iter_tests() { let mut wam = MockWAM::new(); - let pstr_var_cell = - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap(); + wam.machine_st.heap.push_cell(empty_list_as_cell!()).unwrap(); - let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + // not overwriting anything! 0 is an interstitial cell + // reserved for use by the runtime + wam.machine_st.heap[0] = pstr_cell; { let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }), ); assert_eq!(iter.next(), None); - - assert!(!iter.at_string_terminator()); + assert!(!iter.is_cyclic()); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + assert_eq!(wam.machine_st.heap[2], empty_list_as_cell!()); - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); + wam.machine_st.heap[2] = pstr_loc_as_cell!(heap_index!(3)); - let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + wam.machine_st.allocate_pstr("def").unwrap(); + let h = wam.machine_st.heap.cell_len(); + + wam.machine_st.heap.push_cell(heap_loc_as_cell!(h)).unwrap(); { let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }) ); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment( - 2, - cell_as_atom!(pstr_second_cell), - 0 - )) + Some(PStrIteratee::PStrSlice { + slice_loc: heap_index!(3), + slice_len: "def".len(), + }) ); assert_eq!(iter.next(), None); - assert!(!iter.at_string_terminator()); + assert!(!iter.is_cyclic()); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(empty_list_as_cell!()); + assert_eq!(wam.machine_st.heap[h], heap_loc_as_cell!(h)); + + wam.machine_st.heap[h] = empty_list_as_cell!(); { let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }) ); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment( - 2, - cell_as_atom!(pstr_second_cell), - 0 - )) + Some(PStrIteratee::PStrSlice { + slice_loc: heap_index!(3), + slice_len: "def".len(), + }) ); assert_eq!(iter.next(), None); - assert!(iter.at_string_terminator()); + assert!(!iter.is_cyclic()); } - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); - - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0))); + wam.machine_st.heap[h] = pstr_loc_as_cell!(heap_index!(3)); { let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); - for _ in iter.by_ref() {} - - assert!(!iter.at_string_terminator()); - } - - { - let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); - let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 0); - - assert_eq!( - compare_pstr_prefixes(&mut iter1, &mut iter2), - PStrCmpResult::Ordered(Ordering::Equal) - ); - } - - { - let second_h = wam.machine_st.heap.len(); - - // construct a structurally similar but different cyclic partial string - // matching the one beginning at wam.machine_st.heap[0]. - - put_partial_string(&mut wam.machine_st.heap, "ab", &wam.machine_st.atom_tbl); - - wam.machine_st.heap.pop(); - - wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 2)); - - put_partial_string(&mut wam.machine_st.heap, "c ", &wam.machine_st.atom_tbl); - - wam.machine_st.heap.pop(); - - wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 4)); - - wam.machine_st.heap.push(pstr_second_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 6)); - - wam.machine_st.heap.push(pstr_offset_as_cell!(second_h)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0))); - - let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); - let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, second_h); - - assert_eq!( - compare_pstr_prefixes(&mut iter1, &mut iter2), - PStrCmpResult::Ordered(Ordering::Equal) - ); - } - - wam.machine_st.heap.clear(); - - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); - - let pstr_cell = wam.machine_st.heap[0]; - - wam.machine_st.heap[1] = list_loc_as_cell!(2); - - wam.machine_st.heap.push(char_as_cell!('a')); - wam.machine_st.heap.push(list_loc_as_cell!(4)); - wam.machine_st.heap.push(char_as_cell!('b')); - wam.machine_st.heap.push(empty_list_as_cell!()); - - wam.machine_st.heap.push(pstr_cell); - wam.machine_st.heap.push(heap_loc_as_cell!(7)); - - { - let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); - let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 6); - - assert_eq!( - compare_pstr_prefixes(&mut iter1, &mut iter2), - PStrCmpResult::FirstIterContinuable(PStrIteratee::Char(1, 'a')), - ); - - assert_eq!(iter2.focus, heap_loc_as_cell!(7)); + assert!(iter.is_cyclic()); } // test "abc" = [X,Y,Z]. wam.machine_st.heap.clear(); - let cstr_var_cell = - put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(list_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(4)); - wam.machine_st.heap.push(heap_loc_as_cell!(4)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1 + start)); + section.push_cell(heap_loc_as_cell!(1 + start)); - wam.machine_st.heap.push(list_loc_as_cell!(6)); - wam.machine_st.heap.push(heap_loc_as_cell!(6)); + section.push_cell(list_loc_as_cell!(3 + start)); + section.push_cell(heap_loc_as_cell!(3 + start)); - wam.machine_st.heap.push(empty_list_as_cell!()); + section.push_cell(list_loc_as_cell!(5 + start)); + section.push_cell(heap_loc_as_cell!(5 + start)); - unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + section.push_cell(empty_list_as_cell!()); + }); - assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),); + unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(2)); - assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),); - - assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),); + assert_eq!(wam.machine_st.heap[1 + start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[3 + start], char_as_cell!('b')); + assert_eq!(wam.machine_st.heap[5 + start], char_as_cell!('c')); // test "abc" = [X,Y,Z|D]. wam.machine_st.heap.clear(); - let cstr_var_cell = - put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(list_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); // X + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(4)); - wam.machine_st.heap.push(heap_loc_as_cell!(4)); // Y + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1 + start)); + section.push_cell(heap_loc_as_cell!(1 + start)); // X - wam.machine_st.heap.push(list_loc_as_cell!(6)); - wam.machine_st.heap.push(heap_loc_as_cell!(6)); // Z + section.push_cell(list_loc_as_cell!(3 + start)); + section.push_cell(heap_loc_as_cell!(3 + start)); // Y - wam.machine_st.heap.push(heap_loc_as_cell!(7)); // D + section.push_cell(list_loc_as_cell!(5 + start)); + section.push_cell(heap_loc_as_cell!(5 + start)); // Z - unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(6 + start)); // D + }); + + unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(2)); assert!(!wam.machine_st.fail); - assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),); - - assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),); - - assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),); - - assert_eq!(wam.machine_st.heap[7], empty_list_as_cell!(),); + assert_eq!(wam.machine_st.heap[3], char_as_cell!('a'),); + assert_eq!(wam.machine_st.heap[5], char_as_cell!('b'),); + assert_eq!(wam.machine_st.heap[7], char_as_cell!('c'),); + assert_eq!(wam.machine_st.heap[8], empty_list_as_cell!(),); // test "d" = [d]. wam.machine_st.heap.clear(); - let cstr_var_cell = - put_complete_string(&mut wam.machine_st.heap, "d", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_cstr("d").unwrap(); + let start = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(list_loc_as_cell!(2)); - wam.machine_st.heap.push(char_as_cell!('d')); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1 + start)); + section.push_cell(char_as_cell!('d')); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(start)); assert!(!wam.machine_st.fail); @@ -1033,71 +511,83 @@ mod test { wam.machine_st.heap.clear(); - let cstr_var_cell = - put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(list_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(4)); - wam.machine_st.heap.push(char_as_cell!('b')); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1 + start)); + section.push_cell(heap_loc_as_cell!(1 + start)); - wam.machine_st.heap.push(list_loc_as_cell!(6)); - wam.machine_st.heap.push(heap_loc_as_cell!(6)); + section.push_cell(list_loc_as_cell!(3 + start)); + section.push_cell(char_as_cell!('b')); - wam.machine_st.heap.push(empty_list_as_cell!()); + section.push_cell(list_loc_as_cell!(5 + start)); + section.push_cell(heap_loc_as_cell!(5 + start)); - unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(start)); assert!(!wam.machine_st.fail); - assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),); - - assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),); - - assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),); + assert_eq!(wam.machine_st.heap[1 + start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[3 + start], char_as_cell!('b')); + assert_eq!(wam.machine_st.heap[5 + start], char_as_cell!('c')); // test "abcdef" = [a,b,c|X]. wam.machine_st.heap.clear(); - put_complete_string(&mut wam.machine_st.heap, "abcdef", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_cstr("abcdef").unwrap(); + let start = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - unify!(wam.machine_st, heap_loc_as_cell!(0), pstr_loc_as_cell!(1)); + writer.write_with(|section| { + section.push_pstr("abc"); + let h = section.cell_len(); // h == 3 + section.push_cell(heap_loc_as_cell!(h)); + }); - print_heap_terms(wam.machine_st.heap.iter(), 0); + unify!(wam.machine_st, pstr_cell, pstr_loc_as_cell!(heap_index!(start))); assert!(!wam.machine_st.fail); - assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(5)); - assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(1)); - assert_eq!(wam.machine_st.heap[4], atom_as_cstr_cell!(atom!("abcdef"))); - assert_eq!(wam.machine_st.heap[5], pstr_offset_as_cell!(4)); assert_eq!( - wam.machine_st.heap[6], - fixnum_as_cell!(Fixnum::build_with("abc".len() as i64)) + wam.machine_st.heap.slice_to_str(0, "abcdef".len()), + "abcdef" + ); + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(start), "abc".len()), + "abc" + ); + assert_eq!( + wam.machine_st.heap[3], + pstr_loc_as_cell!(heap_index!(0) + 3) ); // test iteration on X = [b,c,b,c,b,c,b,c|...] as an offset. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1))); + wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); + + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + section.push_cell(pstr_loc_as_cell!('a'.len_utf8())); + }); { - let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 2); + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, start); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment(2, atom!("abc"), 1)) + Some(PStrIteratee::PStrSlice { slice_loc: 'a'.len_utf8(), slice_len: "bc".len() }) ); for _ in iter {} @@ -1107,13 +597,19 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a "))); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr("a ").unwrap(); + let start = wam.machine_st.heap.cell_len(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(start)); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(char_as_cell!(' ')); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); assert!(!wam.machine_st.fail); @@ -1121,98 +617,143 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a"))); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr(" a").unwrap(); + let start = wam.machine_st.heap.cell_len(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + writer.write_with(|section| { + section.push_cell(char_as_cell!(' ')); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(heap_loc_as_cell!(2 + start)); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a')); assert!(!wam.machine_st.fail); // #2293, test3. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a b"))); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(heap_loc_as_cell!(5)); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr("a b").unwrap(); + let start = wam.machine_st.heap.cell_len(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(start)); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(char_as_cell!(' ')); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(heap_loc_as_cell!(4 + start)); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[4 + start], char_as_cell!('b')); assert!(!wam.machine_st.fail); // #2293, test4. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a "))); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr(" a ").unwrap(); + let start = wam.machine_st.heap.cell_len(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + writer.write_with(|section| { + section.push_cell(char_as_cell!(' ')); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(heap_loc_as_cell!(2 + start)); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(char_as_cell!(' ')); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a')); assert!(!wam.machine_st.fail); // #2293, test5. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a bc"))); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(heap_loc_as_cell!(6)); + wam.machine_st.allocate_cstr(" a bc").unwrap(); + let start = wam.machine_st.heap.cell_len(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + writer.write_with(|section| { + section.push_cell(char_as_cell!(' ')); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(heap_loc_as_cell!(2 + start)); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(char_as_cell!(' ')); + section.push_cell(heap_loc_as_cell!(5 + start)); + }); + + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[5 + start], pstr_loc_as_cell!(heap_index!(0) + 3)); assert!(!wam.machine_st.fail); // #2293, test6. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abc"))); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(char_as_cell!('b')); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(heap_loc_as_cell!(5)); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(start)); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(char_as_cell!('b')); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(heap_loc_as_cell!(4 + start)); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[4 + start], char_as_cell!('c')); assert!(!wam.machine_st.fail); // #2293, test7. wam.machine_st.heap.clear(); + wam.machine_st.allocate_cstr("abcde").unwrap(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abcde"))); - wam.machine_st.heap.push(char_as_cell!('a')); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(char_as_cell!('c')); - wam.machine_st.heap.push(list_loc_as_cell!(7)); - wam.machine_st.heap.push(heap_loc_as_cell!(7)); - wam.machine_st.heap.push(list_loc_as_cell!(9)); - wam.machine_st.heap.push(char_as_cell!('e')); - wam.machine_st.heap.push(empty_list_as_cell!()); + let start = wam.machine_st.heap.cell_len(); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + writer.write_with(|section| { + section.push_cell(char_as_cell!('a')); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(heap_loc_as_cell!(2 + start)); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(char_as_cell!('c')); + section.push_cell(list_loc_as_cell!(6 + start)); + section.push_cell(heap_loc_as_cell!(6 + start)); + section.push_cell(list_loc_as_cell!(8 + start)); + section.push_cell(char_as_cell!('e')); + section.push_cell(empty_list_as_cell!()); + }); + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('b')); + assert_eq!(wam.machine_st.heap[6 + start], char_as_cell!('d')); assert!(!wam.machine_st.fail); } } diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index 0173285e..751b55b6 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -3,6 +3,7 @@ use crate::codegen::CodeGenSettings; use crate::forms::*; use crate::instructions::*; use crate::machine::disjuncts::*; +use crate::machine::heap::*; use crate::machine::loader::*; use crate::machine::machine_errors::*; use crate::machine::CodeIndex; @@ -27,25 +28,42 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result Result { let (focus, _cell) = subterm_index(term.heap, term.focus); - let name = match term.name(focus+3) { - Some(name) => name, - None => return Err(CompilationError::InconsistentEntry), + let name = match term_predicate_key(term.heap, focus+3) { + Some((name, 0)) => name, + _ => { + return Err(CompilationError::InvalidDirective( + DirectiveError::InvalidOpDeclNameType(term.heap[focus+3]), + )); + } }; - let spec = match term.name(focus+2) { - Some(name) => name, - None => return Err(CompilationError::InconsistentEntry), + let spec = match term_predicate_key(term.heap, focus+2) { + Some((name, _)) => name, + None => { + return Err(CompilationError::InvalidDirective( + DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus+2]), + )); + } }; - let prec = read_heap_cell!(term.deref_loc(focus+1), + let spec = to_op_decl_spec(spec)?; + let prec = term.deref_loc(focus+1); + + let prec = read_heap_cell!(prec, (HeapCellValueTag::Fixnum, n) => { match u16::try_from(n.get_num()) { Ok(n) if n <= 1200 => n, - _ => return Err(CompilationError::InconsistentEntry), + _ => { + return Err(CompilationError::InvalidDirective( + DirectiveError::InvalidOpDeclPrecDomain(n), + )); + } } } _ => { - return Err(CompilationError::InconsistentEntry); + return Err(CompilationError::InvalidDirective( + DirectiveError::InvalidOpDeclPrecType(prec), + )); } ); @@ -71,10 +89,9 @@ fn setup_op_decl(term: &FocusedHeapRefMut) -> Result { } fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result { - let name_opt = term.name(term.focus); - let arity = term.arity(term.focus); + let key_opt = term_predicate_key(term.heap, term.focus); - if let (Some(atom!("/") | atom!("//")), 2) = (name_opt, arity) { + if let Some((atom!("/") | atom!("//"), 2)) = key_opt { let arity_loc = term.nth_arg(term.focus, 2).unwrap(); let arity = match Number::try_from(term.deref_loc(arity_loc)) { @@ -85,11 +102,11 @@ fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result Result { - if h == focus { - break; - } else { - focus = h; - } - } - (HeapCellValueTag::Lis, l) => { - let term = FocusedHeapRefMut { - heap: term.heap, - focus: l, - }; - exports.push(setup_module_export(&term)?); + 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, + }; - focus = l + 1; - } - (HeapCellValueTag::Atom, (name, _arity)) => { - if name == atom!("[]") { - return Ok(exports); - } else { - break; - } - } - _ => { - break; - } - ); + exports.push(setup_module_export(&term)?); + focus = l + 1; + } + (HeapCellValueTag::Atom, (name, _arity)) => { + if name == atom!("[]") { + return Ok(exports); + } else { + break; + } + } + _ => { + break; + } + ); } Err(CompilationError::InvalidModuleDecl) } -fn setup_module_decl(term: FocusedHeapRefMut) -> Result { - let name = term - .name(term.focus + 1) +fn setup_module_decl(mut term: FocusedHeapRefMut) -> Result { + let name = term_predicate_key(term.heap, term.focus + 1) + .map(|(name, _)| name) .ok_or(CompilationError::InvalidModuleDecl)?; - let export_list = FocusedHeapRefMut { - heap: term.heap, - focus: term.focus + 2, - }; - let exports = setup_module_export_list(export_list)?; + + term.focus = term.focus + 2; + let exports = setup_module_export_list(term)?; Ok(ModuleDecl { name, exports }) } @@ -224,8 +238,8 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result Result>( - term: FocusedHeapRefMut, + term: TermWriteResult, loader: &mut Loader<'a, LS>, ) -> Result<(Atom, Atom, Vec), CompilationError> { fn get_meta_specs( @@ -319,24 +333,27 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>( Ok(meta_specs) } - read_heap_cell!(term.deref_loc(term.focus+1), + let heap = loader.machine_heap(); + let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[term.focus+1])); + + read_heap_cell!(cell, (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity(); + let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); match (name, arity) { (atom!(":"), 2) => { - let module_name = term.heap[s+1]; - let spec = term.heap[s+2]; + let module_name = heap[s+1]; + let spec = heap[s+2]; read_heap_cell!(module_name, (HeapCellValueTag::Atom, (module_name, arity)) => { if arity == 0 { read_heap_cell!(spec, (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(term.heap[s]) + let (name, arity) = cell_as_atom_cell!(heap[s]) .get_name_and_arity(); - let term = FocusedHeapRefMut { heap: term.heap, focus: s }; + let term = FocusedHeapRefMut { heap, focus: s }; return Ok((module_name, name, get_meta_specs(term, arity)?)); } _ => { @@ -351,9 +368,11 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>( ); } _ => { - let term = FocusedHeapRefMut { heap: term.heap, focus: s }; + let term = FocusedHeapRefMut { heap, focus: s }; + let specs = get_meta_specs(term, arity)?; let module_name = loader.payload.compilation_target.module_name(); - return Ok((module_name, name, get_meta_specs(term, arity)?)); + + return Ok((module_name, name, specs)); } } @@ -367,38 +386,41 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>( pub(super) fn setup_declaration<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, - term: FocusedHeapRefMut, + mut term: TermWriteResult, ) -> Result { let mut focus = term.focus; + let machine_st = LS::machine_st(&mut loader.payload); loop { - read_heap_cell!(term.heap[focus], + let decl = machine_st.heap[focus]; + + read_heap_cell!(decl, (HeapCellValueTag::Atom, (name, arity)) => { - let term = FocusedHeapRefMut { heap: term.heap, focus }; + let mut focused = FocusedHeapRefMut::from(&mut machine_st.heap, focus); return match (name, arity) { (atom!("dynamic"), 1) => { - let (name, arity) = setup_predicate_indicator(&term)?; + let (name, arity) = setup_predicate_indicator(&focused)?; Ok(Declaration::Dynamic(name, arity)) } (atom!("module"), 2) => { - Ok(Declaration::Module(setup_module_decl(term)?)) + Ok(Declaration::Module(setup_module_decl(focused)?)) } (atom!("op"), 3) => { - Ok(Declaration::Op(setup_op_decl(&term)?)) + Ok(Declaration::Op(setup_op_decl(&focused)?)) } (atom!("non_counted_backtracking"), 1) => { - let focus = term.nth_arg(term.focus, 1).unwrap(); - let (name, arity) = setup_predicate_indicator(&FocusedHeapRefMut { heap: term.heap, focus })?; + focused.focus = focused.nth_arg(focused.focus, 1).unwrap(); + let (name, arity) = setup_predicate_indicator(&focused)?; Ok(Declaration::NonCountedBacktracking(name, arity)) } - (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&term)?)), + (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&focused)?)), (atom!("use_module"), 2) => { - let (name, exports) = setup_qualified_import(term)?; - + let (name, exports) = setup_qualified_import(focused)?; Ok(Declaration::UseQualifiedModule(name, exports)) } (atom!("meta_predicate"), 1) => { + term.focus = focus; let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?; Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) } @@ -415,13 +437,13 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>( focus = h; } else { return Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(heap_loc_as_cell!(h)), + DirectiveError::ExpectedDirective(decl), )); } } _ => { return Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(term.heap[focus]) + DirectiveError::ExpectedDirective(decl), )); } ); @@ -432,41 +454,44 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, module_name: Atom, arity: usize, - term: &FocusedHeapRefMut, + term: &TermWriteResult, meta_specs: Vec, ) -> IndexMap { + use crate::machine::heap::Heap; let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default()); for (subterm_loc, meta_spec) in (term.focus + 1..term.focus + arity + 1).zip(meta_specs) { if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec { - if let Some(name) = term.name(subterm_loc) { + let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); + + if let Some((name, arity)) = predicate_key_opt { if name == atom!("$call") { continue; } - let arity = term.arity(subterm_loc); - struct QualifiedNameInfo { module_name: Atom, name: Atom, + arity: usize, qualified_term_loc: usize, } fn get_qualified_name( - term: &FocusedHeapRefMut, + heap: &Heap, module_term_loc: usize, qualified_term_loc: usize, ) -> Option { - let (module_term_loc, _) = subterm_index(term.heap, module_term_loc); - let (qualified_term_loc, _) = subterm_index(term.heap, qualified_term_loc); + let (module_term_loc, _) = subterm_index(heap, module_term_loc); + let (qualified_term_loc, _) = subterm_index(heap, qualified_term_loc); - read_heap_cell!(term.heap[module_term_loc], + read_heap_cell!(heap[module_term_loc], (HeapCellValueTag::Atom, (module_name, arity)) => { if arity == 0 { - if let Some(name) = term.name(qualified_term_loc) { + if let Some((name, arity)) = term_predicate_key(heap, qualified_term_loc) { return Some(QualifiedNameInfo { module_name, name, + arity, qualified_term_loc, }); } @@ -478,23 +503,20 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( None } - let (subterm_loc, _) = subterm_index(term.heap, subterm_loc); - - let subterm_arity = term.arity(subterm_loc); - let subterm_name_opt = term.name(subterm_loc); + let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc); + let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); let (module_name, key, term_loc) = - if subterm_name_opt == Some(atom!(":")) && subterm_arity == 2 { - debug_assert_eq!(term.heap[subterm_loc].get_tag(), HeapCellValueTag::Atom); - - match get_qualified_name(term, subterm_loc + 1, subterm_loc + 2) { + if subterm_key_opt == Some((atom!(":"), 2)) { + match get_qualified_name(loader.machine_heap(), subterm_loc + 1, subterm_loc + 2) { Some(QualifiedNameInfo { module_name, name, + arity, qualified_term_loc, }) => ( module_name, - (name, term.arity(qualified_term_loc) + supp_args), + (name, arity + supp_args), qualified_term_loc, ), None => { @@ -505,7 +527,7 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( (module_name, (name, arity + supp_args), subterm_loc) }; - if let Some(index_ptr) = fetch_index_ptr(term.heap, key.1, term_loc) { + if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), key.1, term_loc) { index_ptrs.insert(term_loc, index_ptr); continue; } @@ -525,13 +547,13 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, key: PredicateKey, - terms: FocusedHeapRefMut, + terms: &TermWriteResult, term: HeapCellValue, call_policy: CallPolicy, ) -> QueryClause { // supplementary code vector indices are unnecessary for // root-level clauses. - blunt_index_ptr(terms.heap, key, terms.focus); + blunt_index_ptr(loader.machine_heap(), key, terms.focus); let mut ct = loader.get_clause_type(key.0, key.1); @@ -539,11 +561,10 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { let module_name = loader.payload.compilation_target.module_name(); let code_indices = - build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs); + build_meta_predicate_clause(loader, module_name, arity, terms, meta_specs); return QueryClause { ct: ClauseType::Named(key.1, key.0, idx), - arity, term, code_indices, call_policy, @@ -555,7 +576,6 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( QueryClause { ct, - arity: key.1, term, code_indices: IndexMap::with_hasher(FxBuildHasher::default()), call_policy, @@ -567,13 +587,13 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, key: PredicateKey, module_name: Atom, - terms: FocusedHeapRefMut, + terms: &TermWriteResult, term: HeapCellValue, call_policy: CallPolicy, ) -> QueryClause { // supplementary code vector indices are unnecessary for // root-level clauses. - blunt_index_ptr(terms.heap, key, terms.focus); + blunt_index_ptr(loader.machine_heap(), key, terms.focus); let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1); @@ -584,7 +604,6 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( return QueryClause { ct: ClauseType::Named(key.1, key.0, idx), - arity, term, code_indices, call_policy, @@ -596,7 +615,6 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( QueryClause { ct, - arity: key.1, term, code_indices: IndexMap::with_hasher(FxBuildHasher::default()), call_policy, @@ -613,15 +631,18 @@ impl Preprocessor { Preprocessor { settings } } - pub fn setup_fact( + pub fn setup_fact<'a, LS: LoadState<'a>>( &mut self, - mut term: FocusedHeap, + loader: &mut Loader<'a, LS>, + term: TermWriteResult, ) -> Result<(Fact, VarData), CompilationError> { - if term.name(term.focus).is_some() { - let classifier = VariableClassifier::new(self.settings.default_call_policy()); - let var_data = classifier.classify_fact(&mut term)?; + let heap = loader.machine_heap(); - Ok((Fact { term }, var_data)) + if term_predicate_key(heap, term.focus).is_some() { + let classifier = VariableClassifier::new(self.settings.default_call_policy()); + let var_data = classifier.classify_fact(loader, &term)?; + + Ok((Fact { term_loc: term.focus }, var_data)) } else { Err(CompilationError::InadmissibleFact) } @@ -630,14 +651,16 @@ impl Preprocessor { fn setup_rule<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - mut term: FocusedHeap, + term: TermWriteResult, ) -> Result<(Rule, VarData), CompilationError> { let classifier = VariableClassifier::new(self.settings.default_call_policy()); - let (clauses, var_data) = classifier.classify_rule(loader, &mut term)?; - let head_loc = term.nth_arg(term.focus, 1).unwrap(); + let (clauses, var_data) = classifier.classify_rule(loader, &term)?; - if term.name(head_loc).is_some() { - Ok((Rule { term, clauses }, var_data)) + let heap = loader.machine_heap(); + let head_loc = term_nth_arg(heap, term.focus, 1).unwrap(); + + if term_predicate_key(heap, head_loc).is_some() { + Ok((Rule { term_loc: term.focus, clauses }, var_data)) } else { Err(CompilationError::InvalidRuleHead) } @@ -646,19 +669,18 @@ impl Preprocessor { pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - term: FocusedHeap, - ) -> Result { - let name = term.name(term.focus); - let arity = term.arity(term.focus); + term: TermWriteResult, + ) -> Result { + let heap = &LS::machine_st(&mut loader.payload).heap; - match (name, arity) { - (Some(atom!(":-")), 2) => { + match term_predicate_key(heap, term.focus) { + Some((atom!(":-"), 2)) => { let (rule, var_data) = self.setup_rule(loader, term)?; - Ok(TopLevel::Rule(rule, var_data)) + Ok(PredicateClause::Rule(rule, var_data)) } _ => { - let (fact, var_data) = self.setup_fact(term)?; - Ok(TopLevel::Fact(fact, var_data)) + let (fact, var_data) = self.setup_fact(loader, term)?; + Ok(PredicateClause::Fact(fact, var_data)) } } } diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 25b2d725..356072bc 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1,12 +1,12 @@ use crate::arena::*; use crate::atom_table::*; +use crate::functor_macro::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::read::*; #[cfg(feature = "http")] use crate::http::HttpResponse; -use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; @@ -476,7 +476,7 @@ impl StreamOptions { #[inline] pub fn get_alias(self) -> Option { if self.has_alias() { - Some(Atom::from(self.alias() << 3)) + Some(Atom::from(self.alias())) } else { None } @@ -487,7 +487,7 @@ impl StreamOptions { self.set_has_alias(alias.is_some()); if let Some(alias) = alias { - self.set_alias(alias.flat_index()); + self.set_alias(alias.index); } } } @@ -1953,7 +1953,7 @@ impl MachineState { let err = self.permission_error( Permission::Open, atom!("source_sink"), - functor!(atom!("alias"), [atom(alias)]), + functor!(atom!("alias"), [atom_as_cell(alias)]), ); self.error_form(err, stub) @@ -1961,7 +1961,7 @@ impl MachineState { pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub { let stub = functor_stub(stub_name, stub_arity); - let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]); + let rep_stub = functor!(atom!("reposition"), [atom_as_cell((atom!("true")))]); let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub); self.error_form(err, stub) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 5505f68e..fac20d46 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1,4 +1,5 @@ use crate::parser::ast::*; +use crate::parser::lexer::LexerParser; use crate::parser::parser::*; use base64::Engine; @@ -11,6 +12,7 @@ use crate::atom_table::*; #[cfg(feature = "ffi")] use crate::ffi::*; use crate::forms::*; +use crate::functor_macro::*; use crate::heap_iter::*; use crate::heap_print::*; #[cfg(feature = "http")] @@ -39,7 +41,6 @@ use ordered_float::OrderedFloat; use fxhash::{FxBuildHasher, FxHasher}; use indexmap::IndexSet; -use std::cell::Cell; use std::cmp::Ordering; use std::convert::TryFrom; use std::env; @@ -127,15 +128,10 @@ pub(crate) enum ModuleQuantification { } impl ModuleQuantification { - fn to_functor(&self) -> (Vec, HeapCellValueTag) { + fn to_functor(&self) -> Vec { match self { - &ModuleQuantification::Specified(cell) => ( - functor!(atom!("specified"), [cell(cell)]), - HeapCellValueTag::Str, - ), - ModuleQuantification::Unspecified => { - (functor!(atom!("unspecified")), HeapCellValueTag::Var) - } + &ModuleQuantification::Specified(cell) => functor!(atom!("specified"), [cell(cell)]), + ModuleQuantification::Unspecified => functor!(atom!("unspecified")), } } @@ -170,6 +166,65 @@ pub(crate) fn get_key() -> KeyEvent { key } +fn pstr_segment_char_count_and_tail(heap: &Heap, pstr_loc: usize) -> (usize, usize) { + let char_iter = heap.char_iter(pstr_loc); + + let mut char_count = 0; + let mut byte_offset = 0; + + for c in char_iter { + if c == '\u{0}' { + break; + } + + char_count += 1; + byte_offset += c.len_utf8(); + } + + ( + char_count, + Heap::neighboring_cell_offset(pstr_loc + byte_offset), + ) +} + +fn pstr_segment_char_count_up_to( + heap: &Heap, + pstr_loc: usize, + max_chars: usize, +) -> PStrSegmentCountResult { + let mut char_iter = heap.char_iter(pstr_loc); + let mut char_count = 0; + let mut byte_offset = 0; + + if max_chars > 0 { + while let Some(c) = char_iter.next() { + if c == '\u{0}' { + break; + } + + char_count += 1; + byte_offset += c.len_utf8(); + + if char_count >= max_chars { + break; + } + } + } + + if char_iter.next().is_some() { + PStrSegmentCountResult::Mid { + char_count, + pstr_loc: pstr_loc + byte_offset, + } + } else { + let tail_loc = Heap::neighboring_cell_offset(pstr_loc + byte_offset); + PStrSegmentCountResult::End { + char_count, + tail_loc, + } + } +} + #[derive(Debug, Clone, Copy)] pub struct BrentAlgState { pub hare: usize, @@ -207,7 +262,7 @@ impl BrentAlgState { self.lam += 1; if self.tortoise == self.hare { - return Some(CycleSearchResult::Cyclic(self.lam)); + return Some(CycleSearchResult::Cyclic { lambda: self.lam }); } else { self.teleport_tortoise(); } @@ -225,28 +280,26 @@ impl BrentAlgState { self.max_steps > -1 && self.num_steps() as i64 >= self.max_steps } - pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult { + pub fn to_result(mut self, heap: &Heap) -> CycleSearchResult { loop { read_heap_cell!(heap[self.hare], - (HeapCellValueTag::PStrOffset) => { - let (pstr_loc, offset) = pstr_loc_and_offset(heap, self.hare); - let offset = offset.get_num() as usize; - - let pstr = cell_as_string!(heap[self.hare]); - self.pstr_chars += pstr.as_str_from(offset).chars().count(); - - return CycleSearchResult::PStrLocation(self.num_steps(), pstr_loc, offset); - } - (HeapCellValueTag::PStrLoc, l) => { - let (_pstr_loc, offset) = pstr_loc_and_offset(heap, l); - let offset = offset.get_num() as usize; - return CycleSearchResult::PStrLocation(self.num_steps(), l, offset); + (HeapCellValueTag::PStrLoc) => { + // let (_pstr_loc, offset) = pstr_loc_and_offset(heap, l); + // let offset = offset.get_num() as usize; + let num_steps = self.num_steps(); + return CycleSearchResult::PStrLocation { num_steps, pstr_loc: heap[self.hare] }; } (HeapCellValueTag::Atom, (name, arity)) => { return if name == atom!("[]") && arity == 0 { - CycleSearchResult::ProperList(self.num_steps()) + CycleSearchResult::ProperList { num_steps: self.num_steps() } } else { - CycleSearchResult::NotList(self.num_steps(), heap[self.hare]) + let heap_loc = if arity > 0 { + str_loc_as_cell!(self.hare) + } else { + heap_loc_as_cell!(self.hare) + }; + + CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc } }; } (HeapCellValueTag::Str, s) => { @@ -254,96 +307,78 @@ impl BrentAlgState { .get_name_and_arity(); return if name == atom!("[]") && arity == 0 { - CycleSearchResult::ProperList(self.num_steps()) + CycleSearchResult::ProperList { num_steps: self.num_steps() } } else { - CycleSearchResult::NotList(self.num_steps(), heap[self.hare]) + CycleSearchResult::NotList { + num_steps: self.num_steps(), + heap_loc: heap[self.hare], + } }; } (HeapCellValueTag::Lis, l) => { - return CycleSearchResult::UntouchedList(self.num_steps(), l); + return CycleSearchResult::UntouchedList { num_steps: self.num_steps(), list_loc: l }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if h == self.hare { - let var = heap[self.hare].as_var().unwrap(); - return CycleSearchResult::PartialList(self.num_steps(), var); + // let var = heap[self.hare].as_var().unwrap(); + return CycleSearchResult::PartialList { + num_steps: self.num_steps(), + heap_loc: heap[self.hare], + }; } else { self.hare = h; } } _ => { - return CycleSearchResult::NotList(self.num_steps(), heap[self.hare]); + let heap_loc = heap_loc_as_cell!(self.hare); + return CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc }; } ); } } - fn add_pstr_offset_chars( - &mut self, - heap: &[HeapCellValue], - h: usize, - offset: usize, - ) -> Option { - read_heap_cell!(heap[h], - (HeapCellValueTag::CStr, cstr_atom) => { - let cstr = PartialString::from(cstr_atom); - let num_chars = cstr.as_str_from(offset).chars().count(); + fn add_pstr_chars(&mut self, heap: &Heap, pstr_loc: usize) -> Option { + let next_cell_loc; - if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize { - self.pstr_chars += num_chars; - Some(CycleSearchResult::ProperList(self.num_steps())) - } else { - let char_offset = self.max_steps as usize - self.num_steps(); - self.pstr_chars += char_offset; - Some(CycleSearchResult::PStrLocation(self.max_steps as usize, h, char_offset + offset)) + if self.max_steps == -1 { + let num_chars; + (num_chars, next_cell_loc) = pstr_segment_char_count_and_tail(heap, pstr_loc); + self.pstr_chars += num_chars - 1; + } else { + let max_chars = self.max_steps as usize - self.num_steps(); + + match pstr_segment_char_count_up_to(heap, pstr_loc, max_chars) { + PStrSegmentCountResult::Mid { + char_count, + pstr_loc, + } => { + self.pstr_chars += char_count; + return Some(CycleSearchResult::PStrLocation { + num_steps: self.num_steps(), + pstr_loc: pstr_loc_as_cell!(pstr_loc), + }); + } + PStrSegmentCountResult::End { + char_count, + tail_loc, + } => { + self.pstr_chars += char_count.saturating_sub(1); + next_cell_loc = tail_loc; } } - (HeapCellValueTag::PStr, pstr_atom) => { - let pstr = PartialString::from(pstr_atom); - let num_chars = pstr.as_str_from(offset).chars().count(); + } - if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize { - self.pstr_chars += num_chars - 1; - self.step(h+1) - } else { - let char_offset = self.max_steps as usize - self.num_steps(); - self.pstr_chars += char_offset; - Some(CycleSearchResult::PStrLocation(self.max_steps as usize, h, char_offset + offset)) - } - } - _ => { - unreachable!() - } - ) - } - - fn add_pstr_chars_and_step( - &mut self, - heap: &[HeapCellValue], - h: usize, - ) -> Option { - read_heap_cell!(heap[h], - (HeapCellValueTag::PStrOffset, l) => { - let (pstr_loc, _) = pstr_loc_and_offset(heap, l); - let offset = cell_as_fixnum!(heap[h+1]); - self.add_pstr_offset_chars(heap, pstr_loc, offset.get_num() as usize) - } - _ => { - self.add_pstr_offset_chars(heap, h, 0) - } - ) + self.step(next_cell_loc) } #[inline(always)] - fn cycle_step(&mut self, heap: &[HeapCellValue]) -> Option { + fn cycle_step(&mut self, heap: &Heap) -> Option { loop { let value = heap[self.hare]; read_heap_cell!(value, (HeapCellValueTag::PStrLoc, h) => { - return self.add_pstr_chars_and_step(heap, h); - } - (HeapCellValueTag::CStr | HeapCellValueTag::PStrOffset) => { - return self.add_pstr_chars_and_step(heap, self.hare); + return self.add_pstr_chars(heap, h); } (HeapCellValueTag::Lis, h) => { return self.step(h+1); @@ -354,63 +389,49 @@ impl BrentAlgState { return if name == atom!(".") && arity == 2 { self.step(s+2) } else { - Some(CycleSearchResult::NotList(self.num_steps(), value)) + Some(CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc: value }) }; } (HeapCellValueTag::Atom, (name, arity)) => { debug_assert!(arity == 0); return if name == atom!("[]") { - Some(CycleSearchResult::ProperList(self.num_steps())) + Some(CycleSearchResult::ProperList { num_steps: self.num_steps() }) } else { - Some(CycleSearchResult::NotList(self.num_steps(), value)) + Some(CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc: value }) }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if self.hare == h { - let r = value.as_var().unwrap(); - return Some(CycleSearchResult::PartialList(self.num_steps(), r)); + return Some(CycleSearchResult::PartialList { num_steps: self.num_steps(), heap_loc: value }); } self.hare = h; } _ => { - return Some(CycleSearchResult::NotList(self.num_steps(), value)); + return Some(CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc: value }); } ); } } - pub fn detect_cycles(heap: &[HeapCellValue], value: HeapCellValue) -> CycleSearchResult { - let mut pstr_chars = 0; + pub fn detect_cycles(heap: &Heap, value: HeapCellValue) -> CycleSearchResult { + let mut char_count = 0; let hare = read_heap_cell!(value, (HeapCellValueTag::Lis, offset) => { offset+1 } (HeapCellValueTag::PStrLoc, h) => { - let (h_offset, n) = pstr_loc_and_offset(heap, h); - let n = n.get_num() as usize; - let pstr = cell_as_string!(heap[h_offset]); + let tail_idx; + (char_count, tail_idx) = pstr_segment_char_count_and_tail(heap, h); - pstr_chars = pstr.as_str_from(n).chars().count() - 1; - - if heap[h].get_tag() == HeapCellValueTag::PStrOffset { - debug_assert!(heap[h].get_tag() == HeapCellValueTag::PStrOffset); - - if heap[h_offset].get_tag() == HeapCellValueTag::CStr { - return CycleSearchResult::ProperList(pstr_chars + 1); - } + if heap[tail_idx] == empty_list_as_cell!() { + return CycleSearchResult::ProperList { num_steps: char_count }; } - h_offset+1 - } - (HeapCellValueTag::PStrOffset) => { - unreachable!() - } - (HeapCellValueTag::CStr, cstr_atom) => { - let cstr = PartialString::from(cstr_atom); - return CycleSearchResult::ProperList(cstr.as_str_from(0).chars().count()); + char_count = char_count.saturating_sub(1); + tail_idx } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(heap[s]) @@ -421,28 +442,29 @@ impl BrentAlgState { } else if name == atom!(".") && arity == 2 { s + 2 } else { - return CycleSearchResult::NotList(0, value); + return CycleSearchResult::NotList { num_steps: 0, heap_loc: value }; } } (HeapCellValueTag::Atom, (name, arity)) => { return if name == atom!("[]") && arity == 0 { CycleSearchResult::EmptyList } else { - CycleSearchResult::NotList(0, value) + debug_assert_eq!(arity, 0); + CycleSearchResult::NotList { num_steps: 0, heap_loc: value } }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { - return CycleSearchResult::PartialList(0, value.as_var().unwrap()); + return CycleSearchResult::PartialList { num_steps: 0, heap_loc: value }; } _ => { - return CycleSearchResult::NotList(0, value); + return CycleSearchResult::NotList { num_steps: 0, heap_loc: value }; } ); let mut brent_st = BrentAlgState::new(hare); brent_st.power += 1; // advance a step. - brent_st.pstr_chars = pstr_chars; + brent_st.pstr_chars = char_count; loop { if let Some(result) = brent_st.cycle_step(heap) { @@ -452,58 +474,31 @@ impl BrentAlgState { } pub fn detect_cycles_with_max( - heap: &[HeapCellValue], + heap: &Heap, max_steps: usize, value: HeapCellValue, ) -> CycleSearchResult { - let mut pstr_chars = 0; + let mut char_count = 0; let hare = read_heap_cell!(value, (HeapCellValueTag::Lis, offset) => { if max_steps > 0 { offset+1 } else { - return CycleSearchResult::UntouchedList(0, offset); + return CycleSearchResult::UntouchedList { num_steps: 0, list_loc: offset }; } } (HeapCellValueTag::PStrLoc, h) => { - let (h_offset, n) = pstr_loc_and_offset(heap, h); - let n = n.get_num() as usize; - let pstr = cell_as_string!(heap[h_offset]); - - pstr_chars = pstr.as_str_from(n).chars().count() - 1; - - if heap[h].get_tag() == HeapCellValueTag::PStrOffset && heap[h_offset].get_tag() == HeapCellValueTag::CStr { - return if pstr_chars < max_steps { - CycleSearchResult::ProperList(pstr_chars + 1) - } else { - let offset = max_steps + n; - CycleSearchResult::PStrLocation(max_steps, h_offset, offset) + match pstr_segment_char_count_up_to(heap, h, max_steps) { + PStrSegmentCountResult::Mid { char_count, pstr_loc } => { + let pstr_loc = pstr_loc_as_cell!(pstr_loc); + return CycleSearchResult::PStrLocation { num_steps: char_count, pstr_loc }; + } + PStrSegmentCountResult::End { char_count: num_chars, tail_loc } => { + char_count = num_chars - 1; + tail_loc } } - - if pstr_chars + 1 > max_steps { - return CycleSearchResult::PStrLocation(max_steps, h_offset, max_steps); - } - - h_offset+1 - } - (HeapCellValueTag::PStrOffset) => { - unreachable!() - } - (HeapCellValueTag::CStr, cstr_atom) => { - return if max_steps > 0 { - let cstr = PartialString::from(cstr_atom); - let pstr_chars = cstr.as_str_from(0).chars().count(); - - if pstr_chars <= max_steps { - CycleSearchResult::ProperList(pstr_chars) - } else { - CycleSearchResult::UntouchedCStr(cstr_atom, max_steps) - } - } else { - CycleSearchResult::UntouchedCStr(cstr_atom, 0) - }; } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); @@ -514,31 +509,32 @@ impl BrentAlgState { if max_steps > 0 { s + 2 } else { - return CycleSearchResult::UntouchedList(0, s + 1); + return CycleSearchResult::UntouchedList { num_steps: 0, list_loc: s + 1 }; } } else { - return CycleSearchResult::NotList(0, value); + return CycleSearchResult::NotList { num_steps: 0, heap_loc: value }; } } (HeapCellValueTag::Atom, (name, arity)) => { return if name == atom!("[]") && arity == 0 { CycleSearchResult::EmptyList } else { - CycleSearchResult::NotList(0, value) + debug_assert_eq!(arity, 0); + CycleSearchResult::NotList { num_steps: 0, heap_loc: value } }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { - return CycleSearchResult::PartialList(0, value.as_var().unwrap()); + return CycleSearchResult::PartialList { num_steps: 0, heap_loc: value }; } _ => { - return CycleSearchResult::NotList(0, value); + return CycleSearchResult::NotList { num_steps: 0, heap_loc: value }; } ); let mut brent_st = BrentAlgState::new(hare); brent_st.power += 1; // advance a step. - brent_st.pstr_chars = pstr_chars; + brent_st.pstr_chars = char_count; brent_st.max_steps = max_steps as i64; loop { @@ -559,6 +555,12 @@ enum MatchSite { Match(usize), // a match } +#[derive(Debug)] +enum PStrSegmentCountResult { + Mid { char_count: usize, pstr_loc: usize }, + End { char_count: usize, tail_loc: usize }, +} + #[derive(Debug)] struct AttrListMatch { match_site: MatchSite, @@ -585,24 +587,29 @@ impl MachineState { ); } - pub(crate) fn get_attr_var_list(&mut self, attr_var: HeapCellValue) -> Option { + pub(crate) fn get_attr_var_list( + &mut self, + attr_var: HeapCellValue, + ) -> Result, usize> { read_heap_cell!(attr_var, (HeapCellValueTag::AttrVar, h) => { - Some(h + 1) + Ok(Some(h + 1)) } (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { // create an AttrVar in the heap. - let h = self.heap.len(); + let h = self.heap.cell_len(); + let mut writer = self.heap.reserve(2)?; - self.heap.push(attr_var_as_cell!(h)); - self.heap.push(heap_loc_as_cell!(h+1)); + writer.write_with(|section| { + section.push_cell(attr_var_as_cell!(h)); + section.push_cell(heap_loc_as_cell!(h+1)); + }); self.bind(Ref::attr_var(h), attr_var); - - Some(h + 1) + Ok(Some(h + 1)) } _ => { - None + Ok(None) } ) } @@ -637,12 +644,13 @@ impl MachineState { } fn skip_max_list_cycle(&mut self, lam: usize) { - fn step(heap: &[HeapCellValue], mut value: HeapCellValue) -> usize { + fn step(heap: &Heap, mut value: HeapCellValue) -> usize { loop { read_heap_cell!(value, (HeapCellValueTag::PStrLoc, h) => { - let (h_offset, _) = pstr_loc_and_offset(heap, h); - return h_offset+1; + let (_, tail) = heap.scan_slice_to_str(h); + // let (h_offset, _) = pstr_loc_and_offset(heap, h); + return tail; } (HeapCellValueTag::Lis, h) => { return h+1; @@ -660,13 +668,14 @@ impl MachineState { } } - let h = self.heap.len(); - self.heap.push(self.registers[3]); + // let h = self.heap.cell_len(); + // self.heap.push(self.registers[3]); - let mut hare = h; + let orig_hare = step(&self.heap, self.registers[3]); + let mut hare = orig_hare; let mut tortoise = hare; - for _ in 0..lam { + for _ in 1..lam { hare = step(&self.heap, self.heap[hare]); } @@ -682,7 +691,7 @@ impl MachineState { // reached in the fashion of a C do-while loop since hare // may point to the beginning of a cycle. - let mut brent_st = BrentAlgState::new(h); + let mut brent_st = BrentAlgState::new(orig_hare); brent_st.cycle_step(&self.heap); @@ -690,7 +699,7 @@ impl MachineState { brent_st.cycle_step(&self.heap); } - self.heap.pop(); + // self.heap.pop_cell(); let target_n = self.store(self.deref(self.registers[1])); self.unify_fixnum(Fixnum::build_with(brent_st.num_steps() as i64), target_n); @@ -711,72 +720,51 @@ impl MachineState { } fn skip_max_list_result(&mut self, max_steps: i64) { + let cell = self.store(self.deref(self.registers[3])); + let search_result = if max_steps == -1 { - BrentAlgState::detect_cycles(&self.heap, self.store(self.deref(self.registers[3]))) + BrentAlgState::detect_cycles(&self.heap, cell) } else { - BrentAlgState::detect_cycles_with_max( - &self.heap, - max_steps as usize, - self.store(self.deref(self.registers[3])), - ) + BrentAlgState::detect_cycles_with_max(&self.heap, max_steps as usize, cell) }; match search_result { - CycleSearchResult::PStrLocation(steps, pstr_loc, offset) => { + CycleSearchResult::PStrLocation { + num_steps, + pstr_loc, + } => { let steps = if max_steps > -1 { - std::cmp::min(max_steps, steps as i64) + std::cmp::min(max_steps, num_steps as i64) } else { - steps as i64 + max_steps as i64 }; - let cell = if offset > 0 { - let h = self.heap.len(); - let (pstr_loc, _) = pstr_loc_and_offset(&self.heap, pstr_loc); - - self.heap.push(pstr_offset_as_cell!(pstr_loc)); - self.heap - .push(fixnum_as_cell!(Fixnum::build_with(offset as i64))); - - pstr_loc_as_cell!(h) - } else { - pstr_loc_as_cell!(pstr_loc) - }; - - self.finalize_skip_max_list(steps, cell); + self.finalize_skip_max_list(steps, pstr_loc); // cell); } - CycleSearchResult::UntouchedList(n, l) => { - self.finalize_skip_max_list(n as i64, list_loc_as_cell!(l)); - } - CycleSearchResult::UntouchedCStr(cstr_atom, n) => { - let cell = if n > 0 { - let h = self.heap.len(); - - self.heap.push(string_as_cstr_cell!(cstr_atom)); - self.heap.push(pstr_offset_as_cell!(h)); - self.heap - .push(fixnum_as_cell!(Fixnum::build_with(n as i64))); - - pstr_loc_as_cell!(h + 1) - } else { - string_as_cstr_cell!(cstr_atom) - }; - - self.finalize_skip_max_list(n as i64, cell); + CycleSearchResult::UntouchedList { + num_steps, + list_loc: l, + } => { + self.finalize_skip_max_list(num_steps as i64, list_loc_as_cell!(l)); } CycleSearchResult::EmptyList => { self.finalize_skip_max_list(0, empty_list_as_cell!()); } - CycleSearchResult::PartialList(n, r) => { - self.finalize_skip_max_list(n as i64, r.as_heap_cell_value()); + CycleSearchResult::PartialList { + num_steps, + heap_loc, + } => self.finalize_skip_max_list(num_steps as i64, heap_loc), + CycleSearchResult::ProperList { num_steps } => { + self.finalize_skip_max_list(num_steps as i64, empty_list_as_cell!()) } - CycleSearchResult::ProperList(steps) => { - self.finalize_skip_max_list(steps as i64, empty_list_as_cell!()) + CycleSearchResult::NotList { + num_steps, + heap_loc, + } => { + self.finalize_skip_max_list(num_steps as i64, heap_loc); } - CycleSearchResult::NotList(n, value) => { - self.finalize_skip_max_list(n as i64, value); - } - CycleSearchResult::Cyclic(lam) => { - self.skip_max_list_cycle(lam); + CycleSearchResult::Cyclic { lambda } => { + self.skip_max_list_cycle(lambda); } }; } @@ -824,30 +812,31 @@ impl MachineState { ) { let mut seen_set = IndexSet::new(); - let outcome = if term.is_ref() { - { - let mut iter = stackful_post_order_iter::( - &mut self.heap, &mut self.stack, term.get_value() as usize, - ); + 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); } } + } - heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter())) - } else { - empty_list_as_cell!() - }; + let outcome = step_or_resource_error!( + self, + sized_iter_to_heap_list(&mut self.heap, seen_set.len(), seen_set.into_iter(),) + ); unify_fn!(*self, list_of_vars, outcome); } @@ -866,8 +855,8 @@ impl MachineState { &mut self, lh_offset: usize, copy_target: HeapCellValue, - ) -> usize { - let threshold = self.lifted_heap.len() - lh_offset; + ) -> Result { + let threshold = self.lifted_heap.cell_len() - lh_offset; let mut copy_ball_term = CopyBallTerm::new( &mut self.attr_var_init.attr_var_queue, @@ -876,13 +865,17 @@ impl MachineState { &mut self.lifted_heap, ); - copy_ball_term.push(list_loc_as_cell!(threshold + 1)); - copy_ball_term.push(heap_loc_as_cell!(threshold + 3)); - copy_ball_term.push(heap_loc_as_cell!(threshold + 2)); + let mut writer = copy_ball_term.reserve(3)?; - copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(threshold + 1)); + section.push_cell(heap_loc_as_cell!(threshold + 3)); + section.push_cell(heap_loc_as_cell!(threshold + 2)); + }); - threshold + lh_offset + 2 + copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy)?; + + Ok(threshold + lh_offset + 2) } #[inline(always)] @@ -894,11 +887,14 @@ impl MachineState { (HeapCellValueTag::Fixnum, n) => { let lh_offset = n.get_num() as usize; - if lh_offset >= self.lifted_heap.len() { + if lh_offset >= self.lifted_heap.cell_len() { self.lifted_heap.truncate(lh_offset); } else { - let threshold = self.lifted_heap.len() - lh_offset; - self.lifted_heap.push(addr_constr(threshold)); + let threshold = self.lifted_heap.cell_len() - lh_offset; + step_or_resource_error!( + self, + self.lifted_heap.push_cell(addr_constr(threshold)) + ); } } _ => { @@ -911,14 +907,14 @@ impl MachineState { &mut self, string: &str, indices: &IndexStore, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, ) -> CallResult { use crate::parser::lexer::*; let nx = self.store(self.deref(self.registers[2])); let iter = std::io::Cursor::new(string); - let mut lexer = Lexer::new(CharReader::new(iter), self); + let mut lexer_parser = LexerParser::new(CharReader::new(iter), self); let mut tokens = vec![]; match lexer.next_number_token() { @@ -939,23 +935,16 @@ impl MachineState { } loop { - match lexer.lookahead_char() { + match lexer_parser.lookahead_char() { Err(e) if e.is_unexpected_eof() => { - let mut parser = Parser::from_lexer(lexer); let op_dir = CompositeOpDir::new(&indices.op_dir, None); tokens.reverse(); + let byte_size = heap_index!(tokens.len()); - match parser.read_term(&op_dir, Tokens::Provided(tokens)) { + match lexer_parser.read_term(&op_dir, Tokens::Provided(tokens, byte_size)) { Ok(term) => { - let mut error_gen = || { - let e = ParserError::ParseBigInt(ParserErrorSrc::default()); - let e = self.syntax_error(e); - - return Err(self.error_form(e, stub_gen())); - }; - - read_heap_cell!(term.heap[term.focus], + read_heap_cell!(lexer_parser.machine_st.heap[term.focus], (HeapCellValueTag::Cons, c) => { match_untyped_arena_ptr!(c, (ArenaHeaderTag::Rational, n) => { @@ -965,7 +954,10 @@ impl MachineState { self.unify_big_int(n, nx); } _ => { - return error_gen(); + let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src()); + let e = self.syntax_error(e); + + return Err(self.error_form(e, stub_gen())); } ) } @@ -976,20 +968,23 @@ impl MachineState { self.unify_fixnum(n, nx); } _ => { - return error_gen(); + let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src()); + let e = self.syntax_error(e); + + return Err(self.error_form(e, stub_gen())); } ); + + return Ok(()); } Err(e) => { let e = self.syntax_error(e); return Err(self.error_form(e, stub_gen())); } } - - break; } Ok(c) => { - let err_src = lexer.loc_to_err_src(); + let err_src = lexer_parser.loc_to_err_src(); let err = ParserError::UnexpectedChar(c, err_src); let err = self.syntax_error(err); @@ -999,8 +994,6 @@ impl MachineState { Err(_) => unreachable!(), } } - - Ok(()) } pub(crate) fn call_continuation_chunk( @@ -1052,6 +1045,7 @@ impl MachineState { pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option { read_heap_cell!(value, + /* (HeapCellValueTag::CStr, cstr_atom) => { // avoid allocating a String if possible: // We must be careful to preserve the string "[]" as is, @@ -1062,6 +1056,7 @@ impl MachineState { Some(AtomOrString::Atom(cstr_atom)) } } + */ (HeapCellValueTag::Atom, (atom, arity)) => { if arity == 0 { // ... likewise. @@ -1080,27 +1075,23 @@ impl MachineState { None } } - (HeapCellValueTag::Char, c) => { - Some(AtomOrString::String(c.to_string())) - } _ => { if value.is_constant() { return None; } - let h = self.heap.len(); - self.heap.push(value); + // 0 is reserved for use by the machine. See + // MachineState::new. + self.heap[0] = value; - let mut iter = HeapPStrIter::new(&self.heap, h); + let mut iter = HeapPStrIter::new(&self.heap, 0); let string = iter.to_string_mut(); - let at_terminator = iter.at_string_terminator(); - - self.heap.pop(); + let end_cell = iter.heap[iter.focus()]; // if the iteration doesn't terminate like a string // (i.e. with the [] atom or a CStr), it is not // "str_like" so return None. - if at_terminator { + if end_cell.is_string_terminator(iter.heap) { Some(AtomOrString::String(string)) } else { None @@ -1112,7 +1103,7 @@ impl MachineState { pub(crate) fn codes_to_string( &mut self, addrs: impl Iterator, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, ) -> Result { let mut string = String::new(); @@ -1275,7 +1266,7 @@ impl Machine { boip + extract_ptr!(hm.get(&key).cloned().unwrap()) } IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => { - boip + extract_ptr!(hm.get(&Literal::Atom(key.0)).cloned().unwrap()) + boip + extract_ptr!(hm.get(&atom_as_cell!(key.0)).cloned().unwrap()) } _ => boip, }; @@ -1398,8 +1389,12 @@ impl Machine { let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) .get_name_and_arity(); - (name, arity, if self.machine_st.heap.len() > s + arity + 1 { - get_structure_index(self.machine_st.heap[s + arity + 1]) + (name, arity, if self.machine_st.heap.cell_len() > s + arity + 1 { + if !self.machine_st.heap.pstr_at(s + arity + 1) { + get_structure_index(self.machine_st.heap[s + arity + 1]) + } else { + None + } } else { None }) @@ -1460,10 +1455,9 @@ impl Machine { } }; - // println!("(fast) calling {}/{}", name.as_str(), arity); - if let Some(code_index) = index_cell { if !code_index.is_undefined() { + // println!("(fast) calling {}/{}", name.as_str(), arity); load_registers(&mut self.machine_st, goal, goal_arity); self.machine_st.neck_cut(); return call_at_index(self, name, arity, code_index.get()); @@ -1516,9 +1510,7 @@ impl Machine { // disjoint from them. if they are not, the // expanded goal is not simple. - let post_supp_args = self.machine_st.heap[s+arity-supp_vars.len()+1 .. s+arity+1] - .iter() - .cloned(); + let post_supp_args = self.machine_st.heap.splice(s+arity-supp_vars.len()+1 .. s+arity+1); post_supp_args .zip(supp_vars.iter()) @@ -1544,16 +1536,20 @@ impl Machine { }; let goal = if is_simple_goal { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); let arity = arity - supp_vars.len(); - for idx in 0 .. arity + 1 { - let value = self.machine_st.heap[s + idx]; - self.machine_st.heap.push(value); - } + resource_error_call_result!( + self.machine_st, + self.machine_st.heap.copy_slice_to_end( + s .. s + arity + 1 + ) + ); self.machine_st.heap[h] = atom_as_cell!(name, arity); + // even if arity == 0, goal must be a Str cell, + // since an index is about to appended to it. str_loc_as_cell!(h) } else { goal @@ -1569,8 +1565,11 @@ impl Machine { (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(goal); + let h = self.machine_st.heap.cell_len(); + resource_error_call_result!( + self.machine_st, + self.machine_st.heap.push_cell(goal) + ); GoalAnalysisResult { is_simple_goal: true, @@ -1579,11 +1578,15 @@ impl Machine { supp_vars, } } + /* (HeapCellValueTag::Char, c) => { let name = AtomTable::build_with(&self.machine_st.atom_tbl,&c.to_string()); + let h = self.machine_st.heap.cell_len(); - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(atom_as_cell!(name)); + resource_error_call_result!( + self.machine_st, + self.machine_st.heap.push_cell(atom_as_cell!(name)) + ); GoalAnalysisResult { is_simple_goal: true, @@ -1592,6 +1595,7 @@ impl Machine { supp_vars, } } + */ _ => { self.machine_st.fail = true; return Ok(()); @@ -1605,9 +1609,14 @@ impl Machine { let expanded_term = if result.is_simple_goal { let idx = self.get_or_insert_qualified_code_index(module_name, result.key); - self.machine_st - .heap - .push(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))); + + resource_error_call_result!( + self.machine_st, + self.machine_st + .heap + .push_cell(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))) + ); + result.goal } else { let mut unexpanded_vars = IndexSet::with_hasher(FxBuildHasher::default()); @@ -1630,20 +1639,26 @@ impl Machine { Err(e) => { let err = self.machine_st.session_error(e); let stub = functor_stub(atom!("call"), result.key.1); - return Err(self.machine_st.error_form(err, stub)); } Ok(()) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); + let mut writer = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.reserve(unexpanded_vars.len() + 2) + ); - self.machine_st.heap.push(atom_as_cell!(atom!("$aux"), 0)); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("$aux"), 0)); - for value in unexpanded_vars.difference(&result.supp_vars).cloned() { - self.machine_st.heap.push(value); - } + for value in unexpanded_vars.difference(&result.supp_vars).cloned() { + section.push_cell(value); + } - let anon_str_arity = self.machine_st.heap.len() - h - 1; + section.push_cell(atom_as_cell!(atom!("[]"))); + }); + let anon_str_arity = self.machine_st.heap.cell_len() - h - 2; self.machine_st.heap[h] = atom_as_cell!(atom!("$aux"), anon_str_arity); let idx = CodeIndex::new( @@ -1651,9 +1666,9 @@ impl Machine { &mut self.machine_st.arena, ); - self.machine_st - .heap - .push(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))); + self.machine_st.heap.last_cell_mut().map(|cell| { + *cell = untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)); + }); str_loc_as_cell!(h) } @@ -1679,7 +1694,11 @@ impl Machine { return false; } - if self.machine_st.heap.len() > s + 1 + arity { + if self.machine_st.heap.cell_len() > s + 1 + arity { + if self.machine_st.heap.pstr_at(s + 1 + arity) { + return false; + } + let idx_cell = self.machine_st.heap[s + 1 + arity]; if HeapCellValueTag::Cons == idx_cell.get_tag() { @@ -1704,18 +1723,16 @@ impl Machine { let target_module_loc = self.machine_st.registers[2]; - let (functor_stub, ref_cell_tag) = module_quantification.to_functor(); + let functor_stub = module_quantification.to_functor(); + let mut functor_writer = Heap::functor_writer(functor_stub); - let h = self.machine_st.heap.len(); - let ref_cell = HeapCellValue::build_with(ref_cell_tag, h as u64); + let cell = functor_writer(&mut self.machine_st.heap).unwrap(); + unify_fn!(&mut self.machine_st, cell, target_module_loc); - self.machine_st.heap.extend(functor_stub); - - unify_fn!(&mut self.machine_st, ref_cell, target_module_loc); - - let target_qualified_goal = self.machine_st.registers[3]; - - unify_fn!(&mut self.machine_st, qualified_goal, target_qualified_goal); + if !self.machine_st.fail { + let target_qualified_goal = self.machine_st.registers[3]; + unify_fn!(&mut self.machine_st, qualified_goal, target_qualified_goal); + } } #[inline(always)] @@ -1735,21 +1752,24 @@ impl Machine { let target_goal = if arity == 0 { qualified_goal } else { - // if narity + arity > 0 { - let h = self.machine_st.heap.len(); - self.machine_st - .heap - .push(atom_as_cell!(name, narity + arity)); + let h = self.machine_st.heap.cell_len(); - for idx in 1..narity + 1 { - self.machine_st.heap.push(self.machine_st.heap[s + idx]); - } + let mut writer = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.reserve(1 + narity + arity) + ); - for idx in 1..arity + 1 { - self.machine_st - .heap - .push(self.machine_st.registers[2 + idx]); - } + writer.write_with(|section| { + section.push_cell(atom_as_cell!(name, narity + arity)); + + for idx in 1..narity + 1 { + section.push_cell(section[s + idx]); + } + + for idx in 1..arity + 1 { + section.push_cell(self.machine_st.registers[2 + idx]); + } + }); if narity + arity > 0 { str_loc_as_cell!(h) @@ -1759,9 +1779,7 @@ impl Machine { }; let target_qualified_goal = self.machine_st.registers[1]; - unify_fn!(&mut self.machine_st, target_goal, target_qualified_goal); - Ok(()) } @@ -1785,12 +1803,17 @@ impl Machine { module_name } _ => { - let h = self.machine_st.heap.len(); - let call_form = functor!(atom!(":"), [cell(module_name), cell(self.machine_st.registers[2])]); + let goal = self.machine_st.registers[2]; + let mut functor_writer = Heap::functor_writer( + functor!(atom!(":"), [cell(module_name), cell(goal)]), + ); - self.machine_st.heap.extend(call_form); + let goal = resource_error_call_result!( + self.machine_st, + functor_writer(&mut self.machine_st.heap) + ); - let err = self.machine_st.type_error(ValidType::Callable, str_loc_as_cell!(h)); + let err = self.machine_st.type_error(ValidType::Callable, goal); let stub = functor_stub(atom!("call"), narity + 1); return Err(self.machine_st.error_form(err, stub)); @@ -1967,9 +1990,12 @@ impl Machine { for entry in entries { if let Ok(entry) = entry { if let Some(name) = entry.file_name().to_str() { - let name = AtomTable::build_with(&self.machine_st.atom_tbl, name); - files.push(atom_as_cstr_cell!(name)); + let file_string_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(name) + ); + files.push(file_string_cell); continue; } } @@ -1981,12 +2007,20 @@ impl Machine { return Err(err); } - let files_list = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - files.into_iter() - )); + let files_list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + files.len(), + files.into_iter() + ) + ); - unify!(self.machine_st, self.machine_st.registers[2], files_list); + unify!( + self.machine_st, + self.machine_st.registers[2], + files_list_cell + ); return Ok(()); } } @@ -2073,11 +2107,14 @@ impl Machine { unreachable!() } } { - let chars_atom = self.systemtime_to_timestamp(time); + let chars_string = self.systemtime_to_timestamp(time); - self.machine_st - .unify_complete_string(chars_atom, self.machine_st.registers[3]); + let cstr_cell = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&chars_string) + ); + unify!(self.machine_st, cstr_cell, self.machine_st.registers[3]); return; } } @@ -2208,10 +2245,16 @@ impl Machine { } }; - let current_atom = AtomTable::build_with(&self.machine_st.atom_tbl, current); + let current_string = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(current) + ); - let a1 = self.deref_register(1); - self.machine_st.unify_complete_string(current_atom, a1); + unify!( + self.machine_st, + current_string, + self.machine_st.registers[1] + ); if self.machine_st.fail { return Ok(()); @@ -2248,11 +2291,14 @@ impl Machine { } }; - let canonical_atom = AtomTable::build_with(&self.machine_st.atom_tbl, cs); - - let a2 = self.deref_register(2); - self.machine_st.unify_complete_string(canonical_atom, a2); + let canonical_string = + resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(cs)); + unify!( + self.machine_st, + canonical_string, + self.machine_st.registers[2] + ); return Ok(()); } } @@ -2264,39 +2310,38 @@ impl Machine { #[inline(always)] pub(crate) fn atom_chars(&mut self) { let a1 = self.deref_register(1); - let a2 = self.deref_register(2); read_heap_cell!(a1, + /* (HeapCellValueTag::Char) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(a1); - self.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.reserve(2) + ); + + step_or_resource_error!( + self.machine_st, + writer.write_with(|section| { + section.push_cell(a1); + section.push_cell(empty_list_as_cell!()); + Ok::<(), usize>(()) + }) + ); unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h)); } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) - .get_name_and_arity(); - - if arity == 0 { - self.machine_st.unify_complete_string( - name, - a2, - ); - } else { - self.machine_st.fail = true; - } - } + */ (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - self.machine_st.unify_complete_string( - name, - a2, - ); - } else { - self.machine_st.fail = true; - } + debug_assert_eq!(arity, 0); + + let cell = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&*name.as_str()) + ); + + unify!(self.machine_st, self.machine_st.registers[2], cell); } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { let a2 = self.deref_register(2); @@ -2322,7 +2367,7 @@ impl Machine { self.machine_st.fail = true; } _ => { - unreachable!(); + self.machine_st.fail = true; } ); } @@ -2332,6 +2377,7 @@ impl Machine { let a1 = self.deref_register(1); read_heap_cell!(a1, + /* (HeapCellValueTag::Char, c) => { let h = self.machine_st.heap.len(); @@ -2340,33 +2386,50 @@ impl Machine { unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]); } + */ (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - let name = name.as_str(); - let iter = name.chars() - .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); + debug_assert_eq!(arity, 0); - let h = iter_to_heap_list(&mut self.machine_st.heap, iter); - unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]); - } else { - self.machine_st.fail = true; - } + let name = name.as_str(); + let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); + + let list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + (&*name).chars().count(), + iter, + ) + ); + + unify!(self.machine_st, list_cell, self.machine_st.registers[2]); } + /* (HeapCellValueTag::Str, s) => { + /* let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) .get_name_and_arity(); if arity == 0 { let name = name.as_str(); - let iter = name.chars() - .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); + let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); - let h = iter_to_heap_list(&mut self.machine_st.heap, iter); - unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]); + let list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + name.as_str().chars().count(), + iter, + ) + ); + + unify!(self.machine_st, list_cell, self.machine_st.registers[2]); } else { - self.machine_st.fail = true; - } + */ + self.machine_st.fail = true; + // } } + */ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { let stub_gen = || functor_stub(atom!("atom_codes"), 2); @@ -2414,9 +2477,11 @@ impl Machine { return; } } + /* (HeapCellValueTag::Char) => { 1 } + */ _ => { unreachable!() } @@ -2470,20 +2535,25 @@ impl Machine { return; } - let pstr_h = self.machine_st.heap.len(); + let pstr_h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(pstr_as_cell!(atom)); - self.machine_st.heap.push(heap_loc_as_cell!(pstr_h + 1)); - - unify!( + let pstr_loc_cell = step_or_resource_error!( self.machine_st, - self.machine_st.registers[2], - pstr_loc_as_cell!(pstr_h) + self.machine_st.allocate_pstr(&*atom.as_str()) ); + let tail_loc = Heap::neighboring_cell_offset(atom.as_str().len() + heap_index!(pstr_h)); + + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.push_cell(heap_loc_as_cell!(tail_loc)) + ); + + unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_cell); + if !self.machine_st.fail { let tail = self.machine_st.registers[3]; - unify!(self.machine_st, tail, heap_loc_as_cell!(pstr_h + 1)); + unify!(self.machine_st, tail, heap_loc_as_cell!(tail_loc)); } } @@ -2491,17 +2561,21 @@ impl Machine { pub(crate) fn is_partial_string(&mut self) { let value = self.deref_register(1); - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(value); + if value.is_constant() { + self.machine_st.fail = empty_list_as_cell!() != value; + } else { + self.machine_st.heap[0] = value; + let mut iter = HeapPStrIter::new(&self.machine_st.heap, 0); - let mut iter = HeapPStrIter::new(&self.machine_st.heap, h); + for _ in iter.by_ref() {} - for _ in iter.by_ref() {} + let focus = iter.focus(); + let end_cell = self.machine_st.heap[focus]; + let at_end_of_pstr = + end_cell.is_var() || end_cell.is_string_terminator(&self.machine_st.heap); - let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator(); - self.machine_st.fail = !at_end_of_pstr; - - self.machine_st.heap.pop(); + self.machine_st.fail = !at_end_of_pstr; + } } #[inline(always)] @@ -2511,26 +2585,8 @@ impl Machine { read_heap_cell!(pstr, (HeapCellValueTag::PStrLoc, h) => { - let (h, _) = pstr_loc_and_offset(&self.machine_st.heap, h); - - if HeapCellValueTag::CStr == self.machine_st.heap[h].get_tag() { - self.machine_st.unify_atom( - atom!("[]"), - a2 - ); - } else { - unify_fn!( - self.machine_st, - heap_loc_as_cell!(h+1), - a2 - ); - } - } - (HeapCellValueTag::CStr) => { - self.machine_st.unify_atom( - atom!("[]"), - a2 - ); + let (_, tail_loc) = self.machine_st.heap.scan_slice_to_str(h); + unify_fn!(self.machine_st, heap_loc_as_cell!(tail_loc), a2); } (HeapCellValueTag::Lis, h) => { unify_fn!( @@ -2672,9 +2728,11 @@ impl Machine { } let a2 = read_heap_cell!(a2, + /* (HeapCellValueTag::Char) => { a2 } + */ (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { if let Some(c) = name.as_char() { @@ -2854,8 +2912,12 @@ impl Machine { } }; - let chars_atom = AtomTable::build_with(&self.machine_st.atom_tbl, string.trim()); - self.machine_st.unify_complete_string(chars_atom, chs); + let cstr_cell = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(string.trim()) + ); + + unify!(self.machine_st, cstr_cell, chs); } #[inline(always)] @@ -2885,8 +2947,16 @@ impl Machine { .chars() .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); - let h = iter_to_heap_list(&mut self.machine_st.heap, codes); - unify!(self.machine_st, heap_loc_as_cell!(h), chs); + let list_cell = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + string.trim().chars().count(), + codes, + ) + ); + + unify!(self.machine_st, list_cell, chs); } #[inline(always)] @@ -2918,7 +2988,7 @@ impl Machine { #[inline(always)] pub(crate) fn lifted_heap_length(&mut self) { let a1 = self.machine_st.registers[1]; - let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.len() as i64); + let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.cell_len() as i64); self.machine_st.unify_fixnum(lh_len, a1); } @@ -2940,9 +3010,11 @@ impl Machine { debug_assert_eq!(arity, 0); name.as_char().unwrap() } + /* (HeapCellValueTag::Char, c) => { c } + */ _ => { match Number::try_from(a2) { Ok(Number::Integer(n)) => { @@ -2990,9 +3062,11 @@ impl Machine { let a2 = self.deref_register(2); let c = read_heap_cell!(a1, + /* (HeapCellValueTag::Char, c) => { c } + */ (HeapCellValueTag::Atom, (name, _arity)) => { name.as_char().unwrap() } @@ -3078,14 +3152,19 @@ impl Machine { match (name, arity) { (atom!("upper"), 1) => { let reg = self.machine_st.deref(self.machine_st.heap[s+1]); - let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_uppercase().to_string()); - let upper_str = string_as_cstr_cell!(atom); + let upper_str = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&c.to_uppercase().to_string()) + ); unify!(self.machine_st, reg, upper_str); } (atom!("lower"), 1) => { let reg = self.machine_st.deref(self.machine_st.heap[s+1]); - let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_lowercase().to_string()); - let lower_str = string_as_cstr_cell!(atom); + let lower_str = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&c.to_uppercase().to_string()) + ); + unify!(self.machine_st, reg, lower_str); } _ => { @@ -3133,10 +3212,10 @@ impl Machine { unify_fn!(self.machine_st, addr, *value_loc); } None if !ball.stub.is_empty() => { - let h = self.machine_st.heap.len(); - let stub = ball.copy_and_align(h); - - self.machine_st.heap.extend(stub); + let h = step_or_resource_error!( + self.machine_st, + ball.copy_and_align_to(&mut self.machine_st.heap) + ); unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h)); @@ -3234,10 +3313,12 @@ impl Machine { return Ok(()); } } + /* (HeapCellValueTag::Char, c) => { write!(&mut stream, "{}", c).unwrap(); return Ok(()); } + */ _ => { } ); @@ -3492,9 +3573,11 @@ impl Machine { (HeapCellValueTag::Atom, (atom, _arity)) => { char_as_cell!(atom.as_char().unwrap()) } + /* (HeapCellValueTag::Char) => { addr } + */ _ => { let err = self.machine_st.type_error(ValidType::InCharacter, addr); return Err(self.machine_st.error_form(err, stub_gen())); @@ -3594,9 +3677,12 @@ impl Machine { } Some(Err(e)) => { let stub = functor_stub(atom!("$get_n_chars"), 3); - let err = self.machine_st.session_error(SessionError::from( - ParserError::IO(e, ParserErrorSrc::default()), - )); + let err = + self.machine_st + .session_error(SessionError::from(ParserError::IO( + e, + ParserErrorSrc::default(), + ))); return Err(self.machine_st.error_form(err, stub)); } @@ -3608,9 +3694,10 @@ impl Machine { }; let output = self.deref_register(3); - let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &string); + let cstr_cell = + resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&string)); - self.machine_st.unify_complete_string(atom, output); + unify!(self.machine_st, cstr_cell, output); Ok(()) } @@ -3882,18 +3969,19 @@ impl Machine { #[inline(always)] pub(crate) fn copy_to_lifted_heap(&mut self) { let lh_offset = cell_as_fixnum!(self.deref_register(1)).get_num() as usize; - let copy_target = self.machine_st.registers[2]; + let old_threshold = step_or_resource_error!( + self.machine_st, + self.machine_st + .copy_findall_solution(lh_offset, copy_target) + ); - let old_threshold = self - .machine_st - .copy_findall_solution(lh_offset, copy_target); - let new_threshold = self.machine_st.lifted_heap.len() - lh_offset; + let new_threshold = self.machine_st.lifted_heap.cell_len() - lh_offset; self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold); - for addr in self.machine_st.lifted_heap[old_threshold + 1..].iter_mut() { - *addr -= self.machine_st.heap.len() + lh_offset; + for addr in &mut self.machine_st.lifted_heap.splice_mut(old_threshold + 1..) { + *addr -= self.machine_st.heap.cell_len() + lh_offset; } } @@ -3978,7 +4066,7 @@ impl Machine { } }; - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); let mut num_functors = 0; let code_dir = if module_name == atom!("user") { @@ -3998,51 +4086,47 @@ impl Machine { } }; - for (name, arity) in code_dir.keys() { - if self.indices.builtin_property((*name, *arity)) { + for (name, arity) in code_dir.keys().cloned() { + if self.indices.builtin_property((name, arity)) { continue; } - if name_match(pred_atom, *name) && arity_match(pred_arity, *arity) { - self.machine_st.heap.extend(functor!( - atom!("/"), - [cell(atom_as_cell!(name)), fixnum(*arity)] - )); + if name_match(pred_atom, name) && arity_match(pred_arity, arity) { + let functor = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]); // self.machine_st.heap.extend( + + let mut functor_writer = Heap::functor_writer(functor); + + step_or_resource_error!(self.machine_st, functor_writer(&mut self.machine_st.heap)); num_functors += 1; } } - if num_functors > 0 { - let h = iter_to_heap_list( + let functor_list_cell = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( &mut self.machine_st.heap, - (0..num_functors).map(|i| str_loc_as_cell!(h + 3 * i)), - ); + num_functors, + (0..num_functors).map(|i| str_loc_as_cell!(h + 3 * i)) + ) + ); - unify!( - self.machine_st, - heap_loc_as_cell!(h), - self.machine_st.registers[4] - ); - } else { - unify!( - self.machine_st, - empty_list_as_cell!(), - self.machine_st.registers[4] - ); - } + unify!( + self.machine_st, + functor_list_cell, + self.machine_st.registers[4] + ); } #[inline(always)] pub(crate) fn get_next_op_db_ref(&mut self) { let prec = self.deref_register(1); - - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); fn write_op_functors_to_heap( heap: &mut Heap, op_descs: impl Iterator, - ) -> usize { + ) -> Result { let mut num_functors = 0; for (name, op_desc) in op_descs { @@ -4055,19 +4139,21 @@ impl Machine { let spec_atom = op_desc.get_spec().get_spec(); - heap.extend(functor!( + let functor = functor!( atom!("op"), - [ - fixnum(prec), - cell(atom_as_cell!(spec_atom)), - cell(atom_as_cell!(name)) - ] - )); + [fixnum(prec), atom_as_cell(spec_atom), atom_as_cell(name)] + ); + + let mut functor_writer = Heap::functor_writer(functor); + + if let Err(e) = functor_writer(heap) { + return Err(e); + } num_functors += 1; } - num_functors + Ok(num_functors) } if prec.is_var() { @@ -4088,9 +4174,11 @@ impl Machine { (HeapCellValueTag::Str, s) => { cell_as_atom!(self.machine_st.heap[s]) } + /* (HeapCellValueTag::Char, c) => { AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_string()) } + */ _ => { unreachable!() } @@ -4113,17 +4201,23 @@ impl Machine { if number_of_keys == 0 { self.machine_st.fail = true; } else { - let num_functors = - write_op_functors_to_heap(&mut self.machine_st.heap, op_descs); + let num_functors = step_or_resource_error!( + self.machine_st, + write_op_functors_to_heap(&mut self.machine_st.heap, op_descs,) + ); - let h = iter_to_heap_list( - &mut self.machine_st.heap, - (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)), + let functor_list_cell = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + num_functors, + (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)) + ) ); unify!( self.machine_st, - heap_loc_as_cell!(h), + functor_list_cell, self.machine_st.registers[4] ); } @@ -4148,23 +4242,26 @@ impl Machine { Some((key.0, *op_desc)) }); - write_op_functors_to_heap(&mut self.machine_st.heap, op_descs) + step_or_resource_error!( + self.machine_st, + write_op_functors_to_heap(&mut self.machine_st.heap, op_descs,) + ) }; - if num_functors > 0 { - let h = iter_to_heap_list( + let functor_list_cell = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( &mut self.machine_st.heap, + num_functors, (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)), - ); + ) + ); - unify!( - self.machine_st, - heap_loc_as_cell!(h), - self.machine_st.registers[4] - ); - } else { - self.machine_st.fail = true; - } + unify!( + self.machine_st, + functor_list_cell, + self.machine_st.registers[4] + ); } else { let spec = cell_as_atom!(self.deref_register(2)); let op_atom = cell_as_atom!(self.deref_register(3)); @@ -4181,21 +4278,24 @@ impl Machine { match self.indices.op_dir.get(&(op_atom, fixity)).cloned() { Some(op_desc) => { - let num_functors = write_op_functors_to_heap( - &mut self.machine_st.heap, - std::iter::once((op_atom, op_desc)), - ); - - let h = iter_to_heap_list( - &mut self.machine_st.heap, - (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)), - ); - - unify!( + let num_functors = step_or_resource_error!( self.machine_st, - heap_loc_as_cell!(h), - self.machine_st.registers[4] + write_op_functors_to_heap( + &mut self.machine_st.heap, + std::iter::once((op_atom, op_desc)) + ) ); + + let functor_list = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + num_functors, + (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)), + ) + ); + + unify!(self.machine_st, functor_list, self.machine_st.registers[4]); } _ => { self.machine_st.fail = true; @@ -4310,17 +4410,18 @@ impl Machine { } }; - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - iter_to_heap_list( - &mut self.machine_st.heap, - (0..n).map(|i| heap_loc_as_cell!(h + 2 * i + 1)), + let list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + n, + (0..n).map(|i| heap_loc_as_cell!(h + 2 * i + 1)), + ) ); - let tail = self.deref_register(1); - self.machine_st - .bind(tail.as_var().unwrap(), heap_loc_as_cell!(h)); - + unify!(self.machine_st, self.deref_register(1), list_cell); Ok(()) } @@ -4397,34 +4498,45 @@ impl Machine { self.machine_st .unify_fixnum(Fixnum::build_with(status as i64), address_status); // headers - let headers: Vec = resp - .headers() - .iter() - .map(|(header_name, header_value)| { - let h = self.machine_st.heap.len(); + let mut headers: Vec = vec![]; - let header_term = functor!( - AtomTable::build_with( - &self.machine_st.atom_tbl, - header_name.as_str() - ), - [cell(string_as_cstr_cell!(AtomTable::build_with( - &self.machine_st.atom_tbl, - header_value.to_str().unwrap() - )))] - ); + for (header_name, header_value) in resp.headers().iter() { + let string_cell = resource_error_call_result!( + self.machine_st, + self.machine_st + .allocate_cstr(header_value.to_str().unwrap()) + ); - self.machine_st.heap.extend(header_term); - str_loc_as_cell!(h) - }) - .collect(); + let header_term = functor!( + AtomTable::build_with( + &self.machine_st.atom_tbl, + header_name.as_str() + ), + [cell(string_cell)] + ); - let headers_list = - iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter()); + let mut functor_writer = Heap::functor_writer(header_term); + + let functor_cell = resource_error_call_result!( + self.machine_st, + functor_writer(&mut self.machine_st.heap) + ); + + headers.push(functor_cell); + } + + let headers_list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + headers.len(), + headers.into_iter(), + ) + ); unify!( self.machine_st, - heap_loc_as_cell!(headers_list), + headers_list_cell, self.machine_st.registers[6] ); @@ -4451,7 +4563,9 @@ impl Machine { self.machine_st.fail = true; } } - }); + + Ok(()) + })?; } else { let err = self .machine_st @@ -4623,92 +4737,122 @@ impl Machine { (ArenaHeaderTag::HttpListener, http_listener) => { loop { match http_listener.incoming.recv_timeout(std::time::Duration::from_millis(200)) { - Ok(request) => { - let method_atom = match request.request_data.method { - Method::GET => atom!("get"), - Method::POST => atom!("post"), - Method::PUT => atom!("put"), - Method::DELETE => atom!("delete"), - Method::PATCH => atom!("patch"), - Method::HEAD => atom!("head"), - Method::OPTIONS => atom!("options"), - Method::TRACE => atom!("trace"), - Method::CONNECT => atom!("connect"), - _ => atom!("unsupported_extension"), - }; - let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path); - let path_cell = atom_as_cstr_cell!(path_atom); - let headers: Vec = request.request_data.headers.iter().map(|(header_name, header_value)| { - let h = self.machine_st.heap.len(); - let header_term = functor!(AtomTable::build_with(&self.machine_st.atom_tbl, header_name.as_str()), [cell(string_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, header_value.to_str().unwrap())))]); + Ok(request) => { + let method_atom = match request.request_data.method { + Method::GET => atom!("get"), + Method::POST => atom!("post"), + Method::PUT => atom!("put"), + Method::DELETE => atom!("delete"), + Method::PATCH => atom!("patch"), + Method::HEAD => atom!("head"), + Method::OPTIONS => atom!("options"), + Method::TRACE => atom!("trace"), + Method::CONNECT => atom!("connect"), + _ => atom!("unsupported_extension"), + }; - self.machine_st.heap.extend(header_term.into_iter()); - str_loc_as_cell!(h) - }).collect(); + let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path); + let path_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(&request.request_data.path) + ); - let headers_list = iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter()); + let mut headers = vec![]; - let query_str = request.request_data.query; - let query_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &query_str); - let query_cell = string_as_cstr_cell!(query_atom); + for (header_name, header_value) in request.request_data.headers { + let header_value = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(header_value.to_str().unwrap()) + ); - let mut stream = Stream::from_http_stream( - path_atom, - request.request_data.body, - &mut self.machine_st.arena - ); - *stream.options_mut() = StreamOptions::default(); - stream.options_mut().set_stream_type(StreamType::Binary); + let header_term = functor!( + AtomTable::build_with(&self.machine_st.atom_tbl, header_name.unwrap().as_str()), + [cell(header_value)] + ); - self.indices.add_stream(stream, atom!("http_accept"), 7) - .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + let mut functor_writer = Heap::functor_writer(header_term); - let stream: HeapCellValue = stream.into(); + let functor_cell = resource_error_call_result!( + self.machine_st, + functor_writer(&mut self.machine_st.heap) + ); - let handle: TypedArenaPtr = arena_alloc!(request.response, &mut self.machine_st.arena); + headers.push(functor_cell); + } - self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom)); - self.machine_st.bind(path.as_var().unwrap(), path_cell); - unify!(self.machine_st, heap_loc_as_cell!(headers_list), self.machine_st.registers[4]); - self.machine_st.bind(query.as_var().unwrap(), query_cell); - self.machine_st.bind(stream_addr.as_var().unwrap(), stream); - self.machine_st.bind(handle_addr.as_var().unwrap(), typed_arena_ptr_as_cell!(handle)); - break - } - Err(std::sync::mpsc::RecvTimeoutError::Timeout) => { - let interrupted = machine::INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); + let headers_list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + headers.len(), + headers.into_iter(), + ) + ); + + let query_str = request.request_data.query; + let query_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(&query_str) + ); + + let mut stream = Stream::from_http_stream( + path_atom, + request.request_data.body, + &mut self.machine_st.arena + ); + *stream.options_mut() = StreamOptions::default(); + stream.options_mut().set_stream_type(StreamType::Binary); + + self.indices.add_stream(stream, atom!("http_accept"), 7) + .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + + let stream = stream_as_cell!(stream); + + let handle = arena_alloc!(request.response, &mut self.machine_st.arena) + as TypedArenaPtr; + + self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom)); + self.machine_st.bind(path.as_var().unwrap(), path_cell); + unify!(self.machine_st, headers_list_cell, self.machine_st.registers[4]); + self.machine_st.bind(query.as_var().unwrap(), query_cell); + self.machine_st.bind(stream_addr.as_var().unwrap(), stream); + self.machine_st.bind(handle_addr.as_var().unwrap(), typed_arena_ptr_as_cell!(handle)); - match machine::INTERRUPT.compare_exchange( - interrupted, - false, - std::sync::atomic::Ordering::Relaxed, - std::sync::atomic::Ordering::Relaxed, - ) { - Ok(interruption) => { - if interruption { - self.machine_st.throw_interrupt_exception(); - self.machine_st.backtrack(); - // We have extracted controll over the Tokio runtime to the calling context for enabling library use case - // (see https://github.com/mthom/scryer-prolog/pull/1880) - // So we only have access to a runtime handle in here and can't shut it down. - // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880 - // was not merged, I'm only deactivating it for now. - //let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap()); - //old_runtime.shutdown_background(); break } - } - Err(_) => unreachable!(), - } + Err(std::sync::mpsc::RecvTimeoutError::Timeout) => { + let interrupted = machine::INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); - } - Err(_) => { - self.machine_st.fail = true; - } - } + match machine::INTERRUPT.compare_exchange( + interrupted, + false, + std::sync::atomic::Ordering::Relaxed, + std::sync::atomic::Ordering::Relaxed, + ) { + Ok(interruption) => { + if interruption { + self.machine_st.throw_interrupt_exception(); + self.machine_st.backtrack(); + // We have extracted controll over the Tokio runtime to the calling context for enabling library use case + // (see https://github.com/mthom/scryer-prolog/pull/1880) + // So we only have access to a runtime handle in here and can't shut it down. + // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880 + // was not merged, I'm only deactivating it for now. + //let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap()); + //old_runtime.shutdown_background(); + break + } + } + Err(_) => unreachable!(), + } } + Err(_) => { + self.machine_st.fail = true; + } } - _ => { + } + } + _ => { unreachable!(); } ); @@ -4906,15 +5050,20 @@ impl Machine { self.machine_st.unify_f64(n, return_value) } Value::Struct(name, args) => { - let struct_value = self.build_struct(&name, args); + let struct_value = resource_error_call_result!( + self.machine_st, + self.build_struct(&name, args) + ); + unify!(self.machine_st, return_value, struct_value); } Value::CString(cstr) => { - let cstr = AtomTable::build_with( - &self.machine_st.atom_tbl, - cstr.to_str().unwrap(), + let str_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(cstr.to_str().unwrap()) ); - self.machine_st.unify_complete_string(cstr, return_value); + + unify!(self.machine_st, str_cell, return_value); } } return Ok(()); @@ -4930,30 +5079,34 @@ impl Machine { Err(e) => return Err(e), } } + self.machine_st.fail = true; Ok(()) } #[cfg(feature = "ffi")] - fn build_struct(&mut self, name: &str, mut args: Vec) -> HeapCellValue { + fn build_struct(&mut self, name: &str, mut args: Vec) -> Result { args.insert(0, Value::CString(CString::new(name).unwrap())); - let cells: Vec<_> = args - .into_iter() - .map(|val| match val { + + let mut expanded_args = Vec::with_capacity(args.len()); + + for val in args { + expanded_args.push(match val { Value::Int(n) => fixnum_as_cell!(Fixnum::build_with(n)), Value::Float(n) => HeapCellValue::from(float_alloc!(n, self.machine_st.arena)), Value::CString(cstr) => atom_as_cell!(AtomTable::build_with( &self.machine_st.atom_tbl, &cstr.into_string().unwrap() )), - Value::Struct(name, struct_args) => self.build_struct(&name, struct_args), - }) - .collect(); + Value::Struct(name, struct_args) => self.build_struct(&name, struct_args)?, + }); + } - heap_loc_as_cell!(iter_to_heap_list( + sized_iter_to_heap_list( &mut self.machine_st.heap, - cells.into_iter() - )) + expanded_args.len(), + expanded_args.into_iter(), + ) } #[cfg(feature = "ffi")] @@ -5048,29 +5201,35 @@ impl Machine { #[inline(always)] pub(crate) fn argv(&mut self) -> CallResult { let args = self.deref_register(1); - let mut args_pstrs = vec![]; - for arg in env::args() { - args_pstrs.push(put_complete_string( - &mut self.machine_st.heap, - &arg, - &self.machine_st.atom_tbl, - )); - } - let cell = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - args_pstrs.into_iter() - )); - unify!(self.machine_st, args, cell); + for arg in env::args() { + let pstr_cell = + resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&arg)); + + args_pstrs.push(pstr_cell); + } + + let list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + args_pstrs.len(), + args_pstrs.into_iter(), + ) + ); + + unify!(self.machine_st, args, list_cell); Ok(()) } #[inline(always)] pub(crate) fn current_time(&mut self) { let timestamp = self.systemtime_to_timestamp(SystemTime::now()); - self.machine_st - .unify_complete_string(timestamp, self.machine_st.registers[1]); + let cstr_cell = + step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(×tamp)); + + unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]); } #[inline(always)] @@ -5130,9 +5289,11 @@ impl Machine { }; let op = read_heap_cell!(self.deref_register(3), + /* (HeapCellValueTag::Char, c) => { AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_string()) } + */ (HeapCellValueTag::Atom, (name, _arity)) => { name } @@ -5293,10 +5454,16 @@ impl Machine { }; if let Some(b) = b { - let iter = self.machine_st.gather_attr_vars_created_since(b); + let attr_vars = self.machine_st.gather_attr_vars_created_since(b); - let var_list_addr = - heap_loc_as_cell!(iter_to_heap_list(&mut self.machine_st.heap, iter)); + let var_list_addr = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + attr_vars.len(), + attr_vars.into_iter(), + ) + ); let list_addr = self.machine_st.registers[2]; unify!(self.machine_st, var_list_addr, list_addr); @@ -5354,7 +5521,10 @@ impl Machine { pub(crate) fn put_to_attributed_variable_list(&mut self) { let attr_var = self.deref_register(1); let attr = self.deref_register(3); - let attr_var_list = match self.machine_st.get_attr_var_list(attr_var) { + let attr_var_list_result = + step_or_resource_error!(self.machine_st, self.machine_st.get_attr_var_list(attr_var)); + + let attr_var_list = match attr_var_list_result { Some(h) => h, None => { self.machine_st.fail = true; @@ -5381,12 +5551,16 @@ impl Machine { * or str cells (> 0-arity). */ - let h = self.machine_st.heap.len(); + let module_functor = functor!(atom!(":"), [cell(module), cell(attr)]); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(str_loc_as_cell!(h + 1)); - self.machine_st - .heap - .extend(functor!(atom!(":"), [cell(module), cell(attr)])); + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.push_cell(str_loc_as_cell!(h + 1)) + ); + + let mut functor_writer = Heap::functor_writer(module_functor); + step_or_resource_error!(self.machine_st, functor_writer(&mut self.machine_st.heap)); match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) { Some(AttrListMatch { match_site, .. }) => { @@ -5396,8 +5570,16 @@ impl Machine { // at the end of the (non-empty) list here. self.machine_st.heap[match_site] = list_loc_as_cell!(h + 4); - self.machine_st.heap.push(heap_loc_as_cell!(h)); - self.machine_st.heap.push(heap_loc_as_cell!(h + 5)); + + let mut writer = step_or_resource_error!( + self.machine_st, + self.machine_st.heap.reserve(2) + ); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(h)); + section.push_cell(heap_loc_as_cell!(h + 5)); + }); (match_site, l) } @@ -5415,8 +5597,14 @@ impl Machine { None => { // the list is empty. self.machine_st.heap[attr_var_list] = list_loc_as_cell!(h + 4); - self.machine_st.heap.push(heap_loc_as_cell!(h)); - self.machine_st.heap.push(heap_loc_as_cell!(h + 5)); + + let mut writer = + step_or_resource_error!(self.machine_st, self.machine_st.heap.reserve(2)); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(h)); + section.push_cell(heap_loc_as_cell!(h + 5)); + }); self.machine_st .attr_var_init @@ -5514,10 +5702,54 @@ impl Machine { pub(crate) fn get_continuation_chunk(&mut self) { let e = self.deref_register(1); let e = cell_as_fixnum!(e).get_num() as usize; + let h = self.machine_st.heap.cell_len(); - let p_functor = self.deref_register(2); - + let p_functor_cell = self.deref_register(2); let num_cells = self.machine_st.stack.index_and_frame(e).prelude.num_cells; + + let mut writer = + step_or_resource_error!(self.machine_st, self.machine_st.heap.reserve(2 + num_cells)); + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); + section.push_cell(p_functor_cell); + + for idx in 1..=num_cells { + let mut stack_offset = stack_loc!(AndFrame, e, idx); + let mut addr = self.machine_st.stack[stack_offset]; + + while addr.get_tag() == HeapCellValueTag::StackVar { + stack_offset = addr.get_value() as usize; + + if self.machine_st.stack[stack_offset] == addr { + break; + } + + addr = self.machine_st.stack[stack_offset]; + } + + if addr.get_tag() == HeapCellValueTag::StackVar { + section.push_cell(heap_loc_as_cell!(h + 1 + idx)); + + self.machine_st.stack[stack_offset] = heap_loc_as_cell!(h + 1 + idx); + + // have to inline the TrailRef::Ref(RefTag::StackCell) case of MachineState::trail + // here to get around the borrow checker. + if stack_offset < self.machine_st.b { + self.machine_st.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedStackVar, + stack_offset as u64, + )); + + self.machine_st.tr += 1; + } + } else { + section.push_cell(addr); + } + } + }); + + /* let mut addrs = vec![]; for idx in 1..num_cells + 1 { @@ -5527,7 +5759,7 @@ impl Machine { // avoid pushing stack variables to the heap where they // must not go. if addr.is_stack_var() { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); self.machine_st.heap.push(heap_loc_as_cell!(h)); self.machine_st.bind(Ref::heap_cell(h), addr); @@ -5537,14 +5769,17 @@ impl Machine { addrs.push(addr); } } + */ - let chunk = str_loc_as_cell!(self.machine_st.heap.len()); + let chunk = str_loc_as_cell!(self.machine_st.heap.cell_len()); + /* self.machine_st .heap .push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); - self.machine_st.heap.push(p_functor); + self.machine_st.heap.push(p_functor_cell); self.machine_st.heap.extend(addrs); + */ unify!(self.machine_st, self.machine_st.registers[3], chunk); } @@ -5555,24 +5790,31 @@ impl Machine { let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))) .get_num() as usize; - if lh_offset >= self.machine_st.lifted_heap.len() { + if lh_offset >= self.machine_st.lifted_heap.cell_len() { let solutions = self.machine_st.registers[2]; let diff = self.machine_st.registers[3]; unify_fn!(self.machine_st, solutions, diff); } else { - let h = self.machine_st.heap.len(); - let mut last_index = h; + let h = self.machine_st.heap.cell_len(); - for value in self.machine_st.lifted_heap[lh_offset..].iter().cloned() { - last_index = self.machine_st.heap.len(); - self.machine_st.heap.push(value + h); + step_or_resource_error!( + self.machine_st, + self.machine_st + .heap + .append(self.machine_st.lifted_heap.splice(lh_offset..),) + ); + + for cell in &mut self.machine_st.heap.splice_mut(h..) { + *cell = *cell + h; } - if last_index < self.machine_st.heap.len() { - let diff = self.machine_st.registers[3]; - unify_fn!(self.machine_st, diff, self.machine_st.heap[last_index]); - } + let diff = self.machine_st.registers[3]; + unify_fn!( + self.machine_st, + diff, + self.machine_st.heap.last_cell().unwrap() + ); self.machine_st.lifted_heap.truncate(lh_offset); @@ -5587,14 +5829,21 @@ impl Machine { let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))) .get_num() as usize; - if lh_offset >= self.machine_st.lifted_heap.len() { + if lh_offset >= self.machine_st.lifted_heap.cell_len() { let solutions = self.machine_st.registers[2]; unify_fn!(self.machine_st, solutions, empty_list_as_cell!()); } else { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() { - self.machine_st.heap.push(addr + h); + step_or_resource_error!( + self.machine_st, + self.machine_st + .heap + .append(self.machine_st.lifted_heap.splice(lh_offset..),) + ); + + for cell in &mut self.machine_st.heap.splice_mut(h..) { + *cell = *cell + h; } self.machine_st.lifted_heap.truncate(lh_offset); @@ -5673,8 +5922,7 @@ impl Machine { // n has already been confirmed as an integer, and // internally, Rational is assumed reduced, so its // denominator must be 1. - let r = r.numerator().try_into().unwrap(); - r + r.numerator().try_into().unwrap() } _ => { unreachable!() @@ -5691,7 +5939,6 @@ impl Machine { let prev_block = self.machine_st.scc_block; self.machine_st.run_cleaners_fn = Machine::run_cleaners; - self.machine_st.scc_block = b; self.machine_st.cont_pts.push((addr, b, prev_block)); } @@ -5707,7 +5954,6 @@ impl Machine { Ok(Number::Integer(n)) => (*n).clone(), _ => { let stub = functor_stub(atom!("call_with_inference_limit"), 3); - let err = self.machine_st.type_error(ValidType::Integer, a2); return Err(self.machine_st.error_form(err, stub)); } @@ -5771,7 +6017,6 @@ impl Machine { #[inline(always)] pub(crate) fn no_such_predicate(&mut self) -> CallResult { let module_name = cell_as_atom!(self.deref_register(1)); - let head = self.deref_register(2); self.machine_st.fail = read_heap_cell!(head, @@ -6052,15 +6297,17 @@ impl Machine { #[inline(always)] pub(crate) fn get_ball(&mut self) { let addr = self.deref_register(1); - let h = self.machine_st.heap.len(); - - if !self.machine_st.ball.stub.is_empty() { - let stub = self.machine_st.ball.copy_and_align(h); - self.machine_st.heap.extend(stub); + let h = if !self.machine_st.ball.stub.is_empty() { + step_or_resource_error!( + self.machine_st, + self.machine_st + .ball + .copy_and_align_to(&mut self.machine_st.heap) + ) } else { self.machine_st.fail = true; return; - } + }; match addr.as_var() { Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]), @@ -6140,15 +6387,14 @@ impl Machine { let e = and_frame.prelude.e; let e = Fixnum::build_with(i64::try_from(e).unwrap()); - let p = str_loc_as_cell!(machine_st.heap.len()); + let mut writer = Heap::functor_writer(functor!(atom!("dir_entry"), [fixnum(cp)])); + + let p_functor_cell = step_or_resource_error!(machine_st, writer(&mut machine_st.heap)); - machine_st - .heap - .extend(functor!(atom!("dir_entry"), [fixnum(cp)])); machine_st.unify_fixnum(e, machine_st.registers[2]); if !machine_st.fail { - unify!(machine_st, p, machine_st.registers[3]); + unify!(machine_st, p_functor_cell, machine_st.registers[3]); } }; @@ -6175,15 +6421,18 @@ impl Machine { // it later. let and_frame = self.machine_st.stack.index_and_frame(e); let cp = and_frame.prelude.cp - 1; + let mut writer = Heap::functor_writer(functor!(atom!("dir_entry"), [fixnum(cp)])); - let p = str_loc_as_cell!(self.machine_st.heap.len()); - self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)])); + let p_functor_cell = step_or_resource_error!( + self.machine_st, + writer(&mut self.machine_st.heap) + ); let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap()); self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); if !self.machine_st.fail { - unify!(self.machine_st, p, self.machine_st.registers[3]); + unify!(self.machine_st, p_functor_cell, self.machine_st.registers[3]); } } _ => { @@ -6223,9 +6472,11 @@ impl Machine { None => true, }; } + /* (HeapCellValueTag::Char, c) => { self.machine_st.fail = non_quoted_token(once(c)); } + */ (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); self.machine_st.fail = non_quoted_token(name.as_str().chars()); @@ -6293,14 +6544,14 @@ impl Machine { 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(), }; let chars = CharReader::new(ByteStream::from_string(string)); - let mut parser = Parser::new(chars, &mut self.machine_st); + let mut parser = LexerParser::new(chars, &mut self.machine_st); let op_dir = CompositeOpDir::new(&self.indices.op_dir, None); let term = parser @@ -6331,14 +6582,8 @@ impl Machine { .value_to_str_like(self.machine_st.registers[1]) .unwrap(); - if let Some(mut term) = self.read_term_from_atom(atom_or_string)? { - let heap_len = self.machine_st.heap.len(); - - self.machine_st.heap.extend( - copy_and_align_iter(term.heap.drain(..), 0, heap_len as i64), - ); - - let result = heap_loc_as_cell!(heap_len + term.focus); + if let Some(term) = self.read_term_from_atom(atom_or_string)? { + let result = self.machine_st.heap[term.focus]; let var = self.deref_register(2).as_var().unwrap(); self.machine_st.bind(var, result); @@ -6360,8 +6605,10 @@ impl Machine { }; let chars = CharReader::new(ByteStream::from_string(string)); - let term_write_result = self.machine_st.read(chars, &self.indices.op_dir) - .map(|(term, _)| term.to_machine_heap(&mut self.machine_st)) + let term = self + .machine_st + .read(chars, &self.indices.op_dir) + .map(|(term, _)| term) .map_err(|e| { let e = self.machine_st.session_error(SessionError::from(e)); let stub = functor_stub(atom!("read_term_from_chars"), 3); @@ -6369,7 +6616,7 @@ impl Machine { self.machine_st.error_form(e, stub) })?; - self.machine_st.read_term_body(term_write_result) + self.machine_st.read_term_body(term) } #[inline(always)] @@ -6402,12 +6649,15 @@ impl Machine { #[inline(always)] pub(crate) fn reset_continuation_marker(&mut self) { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); self.machine_st.registers[3] = atom_as_cell!(atom!("none")); self.machine_st.registers[4] = heap_loc_as_cell!(h); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.push_cell(heap_loc_as_cell!(h)) + ); } #[inline(always)] @@ -6747,8 +6997,6 @@ impl Machine { .add_stream(stream, atom!("tls_client_negotiate"), 3) .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; - // FIXME: why are we pushing a random, unreferenced cell on the heap? - self.machine_st.heap.push(stream.into()); let stream_addr = self.deref_register(3); self.machine_st .bind(stream_addr.as_var().unwrap(), stream.into()); @@ -6924,18 +7172,20 @@ impl Machine { } atom!("position") => { if let Some((position, lines_read)) = stream.position() { - let h = self.machine_st.heap.len(); - let position_term = functor!( atom!("position_and_lines_read"), [ - integer(position, &mut self.machine_st.arena), - integer(lines_read, &mut self.machine_st.arena) + number(position, (&mut self.machine_st.arena)), + number(lines_read, (&mut self.machine_st.arena)) ] ); - self.machine_st.heap.extend(position_term); - str_loc_as_cell!(h) + let mut functor_writer = Heap::functor_writer(position_term); + + resource_error_call_result!( + self.machine_st, + functor_writer(&mut self.machine_st.heap) + ) } else { self.machine_st.fail = true; return Ok(()); @@ -6972,17 +7222,20 @@ impl Machine { let value = self.machine_st.registers[2]; let mut ball = Ball::new(); - ball.boundary = self.machine_st.heap.len(); + ball.boundary = self.machine_st.heap.cell_len(); - copy_term( - CopyBallTerm::new( - &mut self.machine_st.attr_var_init.attr_var_queue, - &mut self.machine_st.stack, - &mut self.machine_st.heap, - &mut ball.stub, - ), - value, - AttrVarPolicy::DeepCopy, + step_or_resource_error!( + self.machine_st, + copy_term( + CopyBallTerm::new( + &mut self.machine_st.attr_var_init.attr_var_queue, + &mut self.machine_st.stack, + &mut self.machine_st.heap, + &mut ball.stub, + ), + value, + AttrVarPolicy::DeepCopy, + ) ); self.indices.global_variables.insert(key, (ball, None)); @@ -7026,10 +7279,15 @@ impl Machine { let seen_vars = self .machine_st .attr_vars_of_term(self.machine_st.registers[1]); - let outcome = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - seen_vars.into_iter() - )); + + let outcome = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + seen_vars.len(), + seen_vars.into_iter(), + ) + ); unify_fn!(self.machine_st, self.machine_st.registers[2], outcome); } @@ -7045,24 +7303,30 @@ impl Machine { } let stored_v = if stored_v.is_stack_var() { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); + + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.push_cell(heap_loc_as_cell!(h)) + ); - self.machine_st.heap.push(heap_loc_as_cell!(h)); self.machine_st.bind(Ref::heap_cell(h), stored_v); - heap_loc_as_cell!(h) } else { stored_v }; let mut seen_set = IndexSet::with_hasher(FxBuildHasher::default()); - self.machine_st.variable_set(&mut seen_set, stored_v); - let outcome = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - seen_set.into_iter() - )); + let outcome = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + seen_set.len(), + seen_set.into_iter(), + ) + ); unify_fn!(self.machine_st, a2, outcome); } @@ -7117,18 +7381,18 @@ impl Machine { false } - fn walk_code_at_ptr(&mut self, index_ptr: usize) -> HeapCellValue { - let mut h = self.machine_st.heap.len(); + fn walk_code_at_ptr(&mut self, index_ptr: usize) -> Result { + let orig_h = self.machine_st.heap.cell_len(); + let mut h = orig_h; let mut functors = vec![]; let mut functor_list = vec![]; walk_code(&self.code, index_ptr, |instr| { let old_len = functors.len(); - instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors); + instr.enqueue_functors(&mut self.machine_st.arena, &mut functors); let new_len = functors.len(); - #[allow(clippy::needless_range_loop)] for index in old_len..new_len { let functor_len = functors[index].len(); @@ -7136,24 +7400,30 @@ impl Machine { 0 => {} 1 => { functor_list.push(heap_loc_as_cell!(h)); - h += functor_len; + h += cell_index!(Heap::compute_functor_byte_size(&functors[index])); } _ => { functor_list.push(str_loc_as_cell!(h)); - h += functor_len; + h += cell_index!(Heap::compute_functor_byte_size(&functors[index])); } - } + }; } }); - for functor in functors { - self.machine_st.heap.extend(functor.into_iter()); - } + let mut writer = self.machine_st.heap.reserve(h - orig_h)?; - heap_loc_as_cell!(iter_to_heap_list( + writer.write_with(|section| { + for functor in functors { + let mut functor_writer = ReservedHeapSection::functor_writer(functor); + functor_writer(section); + } + }); + + sized_iter_to_heap_list( &mut self.machine_st.heap, - functor_list.into_iter() - )) + functor_list.len(), + functor_list.into_iter(), + ) } #[inline(always)] @@ -7208,7 +7478,9 @@ impl Machine { } }; - let listing = self.walk_code_at_ptr(first_idx); + let listing = + resource_error_call_result!(self.machine_st, self.walk_code_at_ptr(first_idx)); + let listing_var = self.machine_st.registers[4]; unify!(self.machine_st, listing, listing_var); @@ -7229,7 +7501,8 @@ impl Machine { } }; - let listing = self.walk_code_at_ptr(index_ptr); + let listing = step_or_resource_error!(self.machine_st, self.walk_code_at_ptr(index_ptr)); + let listing_var = self.machine_st.registers[2]; unify!(self.machine_st, listing, listing_var); @@ -7317,19 +7590,13 @@ impl Machine { }; let result = printer.print().result(); - let chars = put_complete_string( - &mut self.machine_st.heap, - &result, - &self.machine_st.atom_tbl, - ); + let chars = + resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&result)); let result_addr = self.deref_register(1); + let var = result_addr.as_var().unwrap(); - if let Some(var) = result_addr.as_var() { - self.machine_st.bind(var, chars); - } else { - unreachable!() - } + self.machine_st.bind(var, chars); Ok(()) } @@ -7339,10 +7606,10 @@ impl Machine { use git_version::git_version; let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); - let buffer_atom = AtomTable::build_with(&self.machine_st.atom_tbl, buffer); + let cstr_cell = + step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer)); - let a1 = self.deref_register(1); - self.machine_st.unify_complete_string(buffer_atom, a1); + unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]); } #[inline(always)] @@ -7377,84 +7644,121 @@ impl Machine { let mut context = Sha3_224::new(); context.update(&bytes); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); + + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } atom!("sha3_256") => { let mut context = Sha3_256::new(); context.update(&bytes); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); + + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } atom!("sha3_384") => { let mut context = Sha3_384::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } atom!("sha3_512") => { let mut context = Sha3_512::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) } atom!("blake2s256") => { let mut context = Blake2s256::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) } atom!("blake2b512") => { let mut context = Blake2b512::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) } atom!("ripemd160") => { let mut context = Ripemd160::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } _ => { let ints = digest::digest( @@ -7470,12 +7774,16 @@ impl Machine { &bytes, ); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - ints.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + ints.as_ref().len(), + ints.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } }; @@ -7506,12 +7814,16 @@ impl Machine { let rkey = hmac::Key::new(ralg, key.as_ref()); let tag = hmac::sign(&rkey, &data); - let ints_list = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - tag.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )); + let ints_list = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + tag.as_ref().len(), + tag.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ); unify!(self.machine_st, self.machine_st.registers[4], ints_list); } @@ -7573,12 +7885,16 @@ impl Machine { } } - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - bytes - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + bytes.len(), + bytes + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) }; unify!(self.machine_st, self.machine_st.registers[7], ints_list); @@ -7625,12 +7941,16 @@ impl Machine { &mut bytes, ); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - bytes - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + bytes.len(), + bytes + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) }; unify!(self.machine_st, self.machine_st.registers[4], ints_list); @@ -7668,14 +7988,18 @@ impl Machine { } }; - let tag_list = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - tag.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )); + let tag_list = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + tag.as_ref().len(), + tag.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ); - let complete_string = self.u8s_to_string(&in_out); + let complete_string = step_or_resource_error!(self.machine_st, self.u8s_to_string(&in_out)); unify!(self.machine_st, self.machine_st.registers[6], tag_list); unify!( @@ -7734,7 +8058,7 @@ impl Machine { if buffer.is_empty() { empty_list_as_cell!() } else { - atom_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, &buffer)) + step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer)) } }; @@ -7759,7 +8083,10 @@ impl Machine { let scalar = secp256k1::Scalar::decode_reduce(&scalar_bytes); point *= scalar; - let uncompressed = self.u8s_to_string(&point.encode_uncompressed()); + let uncompressed = step_or_resource_error!( + self.machine_st, + self.u8s_to_string(&point.encode_uncompressed()) + ); unify!(self.machine_st, self.machine_st.registers[4], uncompressed); } @@ -7773,7 +8100,10 @@ impl Machine { let skey = ed25519::PrivateKey::from_seed(&seed_bytes); - let complete_string = self.u8s_to_string(skey.public_key.encoded.as_ref()); + let complete_string = step_or_resource_error!( + self.machine_st, + self.u8s_to_string(skey.public_key.encoded.as_ref()) + ); unify!( self.machine_st, @@ -7795,13 +8125,16 @@ impl Machine { let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); let sig = skey.sign_raw(&data); - - let sig_list = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - sig.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )); + let sig_list = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + sig.as_ref().len(), + sig.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ); unify!(self.machine_st, self.machine_st.registers[4], sig_list); } @@ -7839,7 +8172,7 @@ impl Machine { &<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap(), ); - let string = self.u8s_to_string(&result[..]); + let string = step_or_resource_error!(self.machine_st, self.u8s_to_string(&result[..])); unify!(self.machine_st, self.machine_st.registers[3], string); } @@ -7864,29 +8197,31 @@ impl Machine { } #[inline(always)] - pub(crate) fn load_html(&mut self) { + pub(crate) fn load_html(&mut self) -> Result<(), usize> { if let Some(string) = self .machine_st .value_to_str_like(self.machine_st.registers[1]) { let document = scraper::Html::parse_document(&string.as_str()); - let result = self.html_node_to_term(document.tree.root().first_child().unwrap()); + let result = self.html_node_to_term(document.tree.root().first_child().unwrap())?; unify!(self.machine_st, self.machine_st.registers[2], result); } else { self.machine_st.fail = true; } + + Ok(()) } #[inline(always)] - pub(crate) fn load_xml(&mut self) { + pub(crate) fn load_xml(&mut self) -> Result<(), usize> { if let Some(string) = self .machine_st .value_to_str_like(self.machine_st.registers[1]) { match roxmltree::Document::parse(&string.as_str()) { Ok(doc) => { - let result = self.xml_node_to_term(doc.root_element()); + let result = self.xml_node_to_term(doc.root_element())?; unify!(self.machine_st, self.machine_st.registers[2], result); } _ => { @@ -7896,6 +8231,8 @@ impl Machine { } else { self.machine_st.fail = true; } + + Ok(()) } #[inline(always)] @@ -7906,10 +8243,9 @@ impl Machine { { match env::var(&*key.as_str()) { Ok(value) => { - let cstr = put_complete_string( - &mut self.machine_st.heap, - &value, - &self.machine_st.atom_tbl, + let cstr = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&value) ); unify!(self.machine_st, self.machine_st.registers[2], cstr); @@ -8040,7 +8376,8 @@ impl Machine { match bytes { Ok(bs) => { - let string = self.u8s_to_string(&bs); + let string = + resource_error_call_result!(self.machine_st, self.u8s_to_string(&bs)); unify!(self.machine_st, self.machine_st.registers[1], string); } @@ -8062,7 +8399,8 @@ impl Machine { } let b64 = b64_engine.encode(bytes); - let string = self.u8s_to_string(b64.as_bytes()); + let string = + resource_error_call_result!(self.machine_st, self.u8s_to_string(b64.as_bytes())); unify!(self.machine_st, self.machine_st.registers[2], string); } @@ -8120,12 +8458,12 @@ impl Machine { 1, )?; - let mut parser = Parser::new(stream, &mut self.machine_st); + let mut lexer_parser = LexerParser::new(stream, &mut self.machine_st); - match devour_whitespace(&mut parser) { + match devour_whitespace(&mut lexer_parser) { Ok(false) => { // not at EOF ... - stream.add_lines_read(parser.lines_read()); + stream.add_lines_read(lexer_parser.line_num()); // ... unless we are. if stream.at_end_of_stream() { @@ -8133,7 +8471,7 @@ impl Machine { } } Ok(true) => { - stream.add_lines_read(parser.lines_read()); + stream.add_lines_read(lexer_parser.line_num()); self.machine_st.fail = true; } Err(err) => { @@ -8194,7 +8532,7 @@ impl Machine { if path.is_dir() { if let Some(path) = path.to_str() { let path_string = - put_complete_string(&mut self.machine_st.heap, path, &self.machine_st.atom_tbl); + step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(path)); unify!(self.machine_st, self.machine_st.registers[1], path_string); return; @@ -8229,7 +8567,7 @@ impl Machine { unify!(self.machine_st, self.machine_st.registers[2], pop_count); } - pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom { + pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> String { let datetime: DateTime = system_time.into(); let mut fstr = "[".to_string(); @@ -8243,9 +8581,7 @@ impl Machine { } fstr.push_str("finis]."); - let s = datetime.format(&fstr).to_string(); - - AtomTable::build_with(&self.machine_st.atom_tbl, &s) + datetime.format(&fstr).to_string() } pub(super) fn string_encoding_bytes( @@ -8264,128 +8600,124 @@ impl Machine { } } - pub(super) fn xml_node_to_term(&mut self, node: roxmltree::Node) -> HeapCellValue { + pub(super) fn xml_node_to_term( + &mut self, + node: roxmltree::Node, + ) -> Result { if node.is_text() { - put_complete_string( - &mut self.machine_st.heap, - node.text().unwrap(), - &self.machine_st.atom_tbl, - ) + self.machine_st.allocate_cstr(node.text().unwrap()) } else { let mut avec = Vec::new(); for attr in node.attributes() { let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.name()); - let value = put_complete_string( - &mut self.machine_st.heap, - attr.value(), - &self.machine_st.atom_tbl, - ); + let value = self.machine_st.allocate_cstr(attr.value())?; - avec.push(str_loc_as_cell!(self.machine_st.heap.len())); + avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len())); - self.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - self.machine_st.heap.push(atom_as_cell!(name)); - self.machine_st.heap.push(value); + let mut writer = self.machine_st.heap.reserve(3)?; + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(name)); + section.push_cell(value); + }); } - let attrs = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - avec.into_iter() - )); + let attrs = + sized_iter_to_heap_list(&mut self.machine_st.heap, avec.len(), avec.into_iter())?; let mut cvec = Vec::new(); for child in node.children() { - cvec.push(self.xml_node_to_term(child)); + cvec.push(self.xml_node_to_term(child)?); } - let children = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - cvec.into_iter() - )); + let children = + sized_iter_to_heap_list(&mut self.machine_st.heap, cvec.len(), cvec.into_iter())?; let tag = AtomTable::build_with(&self.machine_st.atom_tbl, node.tag_name().name()); + let result = str_loc_as_cell!(self.machine_st.heap.cell_len()); + let mut writer = self.machine_st.heap.reserve(4)?; - let result = str_loc_as_cell!(self.machine_st.heap.len()); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("element"), 3)); + section.push_cell(atom_as_cell!(tag)); + section.push_cell(attrs); + section.push_cell(children); + }); - self.machine_st - .heap - .push(atom_as_cell!(atom!("element"), 3)); - self.machine_st.heap.push(atom_as_cell!(tag)); - self.machine_st.heap.push(attrs); - self.machine_st.heap.push(children); - - result + Ok(result) } } pub(super) fn html_node_to_term( &mut self, node: ego_tree::NodeRef<'_, scraper::Node>, - ) -> HeapCellValue { + ) -> Result { match node.value().as_element() { - None => put_complete_string( - &mut self.machine_st.heap, - &node.value().as_text().unwrap().text, - &self.machine_st.atom_tbl, - ), + None => self + .machine_st + .allocate_cstr(&node.value().as_text().unwrap().text), Some(element) => { let mut avec = Vec::new(); for attr in element.attrs() { let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.0); - let value = put_complete_string( - &mut self.machine_st.heap, - attr.1, - &self.machine_st.atom_tbl, - ); + let value = self.machine_st.allocate_cstr(attr.1)?; - avec.push(str_loc_as_cell!(self.machine_st.heap.len())); + avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len())); - self.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - self.machine_st.heap.push(atom_as_cell!(name)); - self.machine_st.heap.push(value); + let mut writer = self.machine_st.heap.reserve(3)?; + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(name)); + section.push_cell(value); + }); } - let attrs = heap_loc_as_cell!(iter_to_heap_list( + let attrs = sized_iter_to_heap_list( &mut self.machine_st.heap, - avec.into_iter() - )); + avec.len(), + avec.into_iter(), + )?; let mut cvec = Vec::new(); for child in node.children() { - cvec.push(self.html_node_to_term(child)); + cvec.push(self.html_node_to_term(child)?); } - let children = heap_loc_as_cell!(iter_to_heap_list( + let children = sized_iter_to_heap_list( &mut self.machine_st.heap, - cvec.into_iter() - )); + cvec.len(), + cvec.into_iter(), + )?; let tag = AtomTable::build_with(&self.machine_st.atom_tbl, element.name()); - let result = str_loc_as_cell!(self.machine_st.heap.len()); + let result = str_loc_as_cell!(self.machine_st.heap.cell_len()); + let mut writer = self.machine_st.heap.reserve(4)?; - self.machine_st - .heap - .push(atom_as_cell!(atom!("element"), 3)); - self.machine_st.heap.push(atom_as_cell!(tag)); - self.machine_st.heap.push(attrs); - self.machine_st.heap.push(children); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("element"), 3)); + section.push_cell(atom_as_cell!(tag)); + section.push_cell(attrs); + section.push_cell(children); + }); - result + Ok(result) } } } - pub(super) fn u8s_to_string(&mut self, data: &[u8]) -> HeapCellValue { + pub(super) fn u8s_to_string(&mut self, data: &[u8]) -> Result { let buffer = String::from_iter(data.iter().map(|b| *b as char)); if buffer.is_empty() { - empty_list_as_cell!() + Ok(empty_list_as_cell!()) } else { - atom_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, &buffer)) + self.machine_st.allocate_cstr(&buffer) } } } diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs index 58c6e2c8..9a1f9fa6 100644 --- a/src/machine/term_stream.rs +++ b/src/machine/term_stream.rs @@ -4,6 +4,7 @@ use crate::machine::loader::*; use crate::machine::machine_errors::*; use crate::machine::*; use crate::parser::ast::*; +use crate::parser::lexer::*; use crate::parser::parser::*; use crate::read::devour_whitespace; @@ -20,11 +21,11 @@ pub struct LoadStatePayload { pub(super) module_op_exports: ModuleOpExports, pub(super) non_counted_bt_preds: IndexSet, pub(super) predicates: PredicateQueue, - pub(super) clause_clauses: Vec, + 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; } @@ -32,7 +33,7 @@ pub trait TermStream: Sized { #[derive(Debug)] pub struct BootstrappingTermStream<'a> { listing_src: ListingSource, - pub(super) parser: Parser<'a, Stream>, + pub(super) lexer_parser: LexerParser<'a, Stream>, } impl<'a> BootstrappingTermStream<'a> { @@ -42,26 +43,23 @@ impl<'a> BootstrappingTermStream<'a> { machine_st: &'a mut MachineState, listing_src: ListingSource, ) -> Self { - let parser = Parser::new(stream, machine_st); - Self { - parser, - listing_src, - } + let lexer_parser = LexerParser::new(stream, machine_st); + Self { lexer_parser, listing_src } } } impl<'a> TermStream for BootstrappingTermStream<'a> { #[inline] - fn next(&mut self, op_dir: &CompositeOpDir) -> Result { - self.parser.reset(); - self.parser - .read_term(op_dir, Tokens::Default) - .map_err(CompilationError::from) + fn next(&mut self, op_dir: &CompositeOpDir) -> Result { + let result = self.lexer_parser.read_term(op_dir, Tokens::Default) + .map_err(CompilationError::from); + + result } #[inline] fn eof(&mut self) -> Result { - devour_whitespace(&mut self.parser) // eliminate dangling comments before checking for EOF. + devour_whitespace(&mut self.lexer_parser) // eliminate dangling comments before checking for EOF. .map_err(CompilationError::from) } @@ -72,7 +70,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> { } pub struct LiveTermStream { - pub(super) term_queue: VecDeque, + pub(super) term_queue: VecDeque, pub(super) listing_src: ListingSource, } @@ -108,7 +106,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,7 +124,7 @@ impl TermStream for LiveTermStream { pub struct InlineTermStream {} impl TermStream for InlineTermStream { - fn next(&mut self, _: &CompositeOpDir) -> Result { + fn next(&mut self, _: &CompositeOpDir) -> Result { Err(CompilationError::from(ParserError::unexpected_eof(ParserErrorSrc::default()))) } diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 05ba4749..5b7c23e8 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -2,11 +2,9 @@ use crate::arena::*; use crate::forms::*; use crate::heap_iter::{stackful_preorder_iter, NonListElider}; use crate::machine::machine_state::*; -use crate::machine::partial_string::*; use crate::machine::*; use crate::types::*; -use std::cmp::Ordering; use std::ops::{Deref, DerefMut}; use derive_more::*; @@ -14,6 +12,18 @@ use fxhash::FxBuildHasher; use indexmap::IndexSet; use num_order::NumOrd; +impl MachineState { + pub(crate) fn partial_string_to_pdl(&mut self, pstr_loc: usize, l: usize) { + let (c, succ_cell) = self.heap.last_str_char_and_tail(pstr_loc); + + self.pdl.push(heap_loc_as_cell!(l + 1)); + self.pdl.push(succ_cell); + + self.pdl.push(heap_loc_as_cell!(l)); + self.pdl.push(char_as_cell!(c)); + } +} + pub(crate) trait Unifier: DerefMut { fn unify_structure(&mut self, s1: usize, value: HeapCellValue) { // s1 is the value of a STR cell. @@ -82,8 +92,8 @@ pub(crate) trait Unifier: DerefMut { self.fail = true; } } - (HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => { - Self::unify_partial_string(self, list_loc_as_cell!(l1), value) + (HeapCellValueTag::PStrLoc, l) => { + Self::unify_partial_string(self, l, list_loc_as_cell!(l1)) } (HeapCellValueTag::AttrVar, h) => { Self::bind(self, Ref::attr_var(h), list_loc_as_cell!(l1)); @@ -100,261 +110,40 @@ pub(crate) trait Unifier: DerefMut { ); } - fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) { + fn unify_partial_string(&mut self, pstr_loc: usize, value: HeapCellValue) { if let Some(r) = value.as_var() { - if atom == atom!("") { - Self::bind(self, r, atom_as_cell!(atom!("[]"))); - } else { - Self::bind(self, r, atom_as_cstr_cell!(atom)); - } - - return; - } - - read_heap_cell!(value, - (HeapCellValueTag::Atom, (cstr_atom, arity)) if atom == atom!("") => { - debug_assert_eq!(arity, 0); - self.fail = cstr_atom != atom!("[]"); - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.heap[s]) - .get_name_and_arity(); - - if arity == 0 { - self.fail = atom == atom!("") && name != atom!("[]"); - } else { - // this is intentionally the same policy for - // value.tag() == Lis and PStrLoc. they're not - // grouped together to allow for arity == 0. - Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value); - - if !self.pdl.is_empty() { - Self::unify_internal(self); - } - } - } - (HeapCellValueTag::CStr, cstr_atom) => { - self.fail = atom != cstr_atom; - } - (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { - Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value); - - if !self.pdl.is_empty() { - Self::unify_internal(self); - } - } - _ => { - self.fail = true; - } - ); - } - - // the return value of unify_partial_string is interpreted as - // follows: - // - // Some(None) -- the strings are equal, nothing to unify - // Some(Some(f2,f1)) -- prefixes equal, try to unify focus values f2, f1 - // None -- prefixes not equal, unification fails - // - // d1's tag is assumed to be one of LIS, STR or PSTRLOC. - fn unify_partial_string(&mut self, value_1: HeapCellValue, value_2: HeapCellValue) { - if let Some(r) = value_2.as_var() { - Self::bind(self, r, value_1); + Self::bind(self, r, pstr_loc_as_cell!(pstr_loc)); return; } let machine_st = self.deref_mut(); - let s1 = machine_st.heap.len(); + read_heap_cell!(value, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) + .get_name_and_arity(); - machine_st.heap.push(value_1); - machine_st.heap.push(value_2); - - let mut pstr_iter1 = HeapPStrIter::new(&machine_st.heap, s1); - let mut pstr_iter2 = HeapPStrIter::new(&machine_st.heap, s1 + 1); - - fn unify_sequence( - machine_st: &mut MachineState, - iter: PStrIteratee, - source_cell: HeapCellValue, - ) -> bool { - match iter { - PStrIteratee::Char(focus, _) => { - machine_st.pdl.push(machine_st.heap[focus]); - machine_st.pdl.push(source_cell); - } - PStrIteratee::PStrSegment(focus, _, n) => { - read_heap_cell!(machine_st.heap[focus], - (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => { - if focus < machine_st.heap.len() - 2 { - machine_st.heap.pop(); - machine_st.heap.pop(); - } - - if n == 0 { - let target_cell = match machine_st.heap[focus].get_tag() { - HeapCellValueTag::CStr => { - atom_as_cstr_cell!(pstr_atom) - } - HeapCellValueTag::PStr => { - pstr_loc_as_cell!(focus) - } - _ => { - unreachable!() - } - }; - - machine_st.pdl.push(target_cell); - machine_st.pdl.push(source_cell); - } else { - let h_len = machine_st.heap.len(); - - machine_st.heap.push(pstr_offset_as_cell!(focus)); - machine_st.heap.push(fixnum_as_cell!( - Fixnum::build_with(n as i64) - )); - - machine_st.pdl.push(pstr_loc_as_cell!(h_len)); - machine_st.pdl.push(source_cell); - } - - return true; - } - (HeapCellValueTag::PStrOffset, pstr_loc) => { - let n0 = cell_as_fixnum!(machine_st.heap[focus+1]) - .get_num() as usize; - - if pstr_loc < machine_st.heap.len() - 2 { - machine_st.heap.pop(); - machine_st.heap.pop(); - } - - if n == n0 { - machine_st.pdl.push(pstr_loc_as_cell!(focus)); - machine_st.pdl.push(source_cell); - } else { - let h_len = machine_st.heap.len(); - - machine_st.heap.push(pstr_offset_as_cell!(pstr_loc)); - machine_st.heap.push(fixnum_as_cell!( - Fixnum::build_with(n as i64) - )); - - machine_st.pdl.push(pstr_loc_as_cell!(h_len)); - machine_st.pdl.push(source_cell); - } - - return true; - } - _ => { - } - ); - - if focus < machine_st.heap.len() - 2 { - machine_st.heap.pop(); - machine_st.heap.pop(); - } - - machine_st.pdl.push(machine_st.heap[focus]); - machine_st.pdl.push(source_cell); - - return true; - } - } - - false - } - - match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { - PStrCmpResult::Ordered(Ordering::Equal) => {} - PStrCmpResult::Ordered(Ordering::Less) => { - if pstr_iter2.focus.as_var().is_none() { - machine_st.fail = true; + if name == atom!(".") && arity == 2 { + machine_st.partial_string_to_pdl(pstr_loc, s+1); } else { - machine_st.pdl.push(empty_list_as_cell!()); - machine_st.pdl.push(pstr_iter2.focus); - } - } - PStrCmpResult::Ordered(Ordering::Greater) => { - if pstr_iter1.focus.as_var().is_none() { machine_st.fail = true; - } else { - machine_st.pdl.push(empty_list_as_cell!()); - machine_st.pdl.push(pstr_iter1.focus); } } - continuable @ PStrCmpResult::FirstIterContinuable(iteratee) - | continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { - if continuable.is_second_iter() { - std::mem::swap(&mut pstr_iter1, &mut pstr_iter2); - } + (HeapCellValueTag::Lis, l) => { + machine_st.partial_string_to_pdl(pstr_loc, l); + } + (HeapCellValueTag::PStrLoc, other_pstr_loc) => { + let cmp_result = machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc); - let mut chars_iter = PStrCharsIter { - iter: pstr_iter1, - item: Some(iteratee), - }; - - let mut focus = pstr_iter2.focus; - - 'outer: { - while let Some(c) = chars_iter.peek() { - read_heap_cell!(focus, - (HeapCellValueTag::Lis, l) => { - let val = pstr_iter2.heap[l]; - - machine_st.pdl.push(val); - machine_st.pdl.push(char_as_cell!(c)); - - focus = pstr_iter2.heap[l+1]; - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s]) - .get_name_and_arity(); - - if name == atom!(".") && arity == 2 { - machine_st.pdl.push(pstr_iter2.heap[s+1]); - machine_st.pdl.push(char_as_cell!(c)); - - focus = pstr_iter2.heap[s+2]; - } else { - machine_st.fail = true; - break 'outer; - } - } - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - unify_sequence(machine_st, chars_iter.item.unwrap(), focus); - return; - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if unify_sequence(machine_st, chars_iter.item.unwrap(), heap_loc_as_cell!(h)) { - return; - } - - break 'outer; - } - _ => { - machine_st.fail = true; - break 'outer; - } - ); - - chars_iter.next(); - } - - chars_iter.iter.next(); - - machine_st.pdl.push(focus); - machine_st.pdl.push(chars_iter.iter.focus); + if cmp_result.continue_pstr_compare(&mut machine_st.pdl).is_some() { + debug_assert!(matches!(cmp_result, PStrSegmentCmpResult::Mismatch { .. })); + machine_st.fail = true; } } - PStrCmpResult::Unordered => { - machine_st.pdl.push(pstr_iter1.focus); - machine_st.pdl.push(pstr_iter2.focus); + _ => { + machine_st.fail = true; } - } - - machine_st.heap.pop(); - machine_st.heap.pop(); + ); } fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) { @@ -368,6 +157,7 @@ pub(crate) trait Unifier: DerefMut { self.fail = !(arity == 0 && name == atom); } + /* (HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => { self.fail = cstr_atom != atom!(""); } @@ -378,6 +168,7 @@ pub(crate) trait Unifier: DerefMut { self.fail = true; } } + */ (HeapCellValueTag::AttrVar, h) => { Self::bind(self, Ref::attr_var(h), atom_as_cell!(atom)); } @@ -412,11 +203,13 @@ pub(crate) trait Unifier: DerefMut { self.fail = true; } } + /* (HeapCellValueTag::Char, c2) => { if c != c2 { self.fail = true; } } + */ (HeapCellValueTag::AttrVar, h) => { Self::bind(self, Ref::attr_var(h), char_as_cell!(c)); } @@ -610,7 +403,7 @@ pub(crate) trait Unifier: DerefMut { tabu_list.insert((d1, d2)); } } - (HeapCellValueTag::PStrLoc) => { + (HeapCellValueTag::PStrLoc, l) => { read_heap_cell!(d2, (HeapCellValueTag::PStrLoc | HeapCellValueTag::Lis | @@ -619,8 +412,7 @@ pub(crate) trait Unifier: DerefMut { continue; } } - (HeapCellValueTag::CStr | - HeapCellValueTag::AttrVar | + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { } @@ -630,13 +422,14 @@ pub(crate) trait Unifier: DerefMut { } ); - Self::unify_partial_string(self, d1, d2); + Self::unify_partial_string(self, l, d2); if !self.fail && !d2.is_constant() { let d2 = self.store(d2); tabu_list.insert((d1, d2)); } } + /* (HeapCellValueTag::CStr) => { read_heap_cell!(d2, (HeapCellValueTag::AttrVar, h) => { @@ -667,15 +460,18 @@ pub(crate) trait Unifier: DerefMut { Self::unify_partial_string(self, d2, d1); } + */ (HeapCellValueTag::F64, f1) => { Self::unify_f64(self, f1, d2); } (HeapCellValueTag::Fixnum, n1) => { Self::unify_fixnum(self, n1, d2); } + /* (HeapCellValueTag::Char, c1) => { Self::unify_char(self, c1, d2); } + */ (HeapCellValueTag::Cons, ptr_1) => { Self::unify_constant(self, ptr_1, d2); } @@ -709,12 +505,12 @@ fn bind_with_occurs_check(unifier: &mut U, r: Ref, value: HeapCellVa let value = machine_st.store(MachineState::deref(machine_st, value)); if value.is_ref() && !value.is_stack_var() { - let root_loc = value.get_value() as usize; + machine_st.heap[0] = value; for cell in stackful_preorder_iter::( &mut machine_st.heap, &mut machine_st.stack, - root_loc, // value, + 0, ) { let cell = unmark_cell_bits!(cell); diff --git a/src/macros.rs b/src/macros.rs index d78a9fea..4869e402 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,15 +1,10 @@ /* A simple macro to count the arguments in a variadic list * of token trees. */ -macro_rules! count_tt { - () => { 0 }; - ($odd:tt $($a:tt $b:tt)*) => { (count_tt!($($a)*) << 1) | 1 }; - ($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 }; -} macro_rules! char_as_cell { ($c: expr) => { - HeapCellValue::build_with(HeapCellValueTag::Char, $c as u64) + HeapCellValue::from_bytes(AtomCell::new_char_inlined($c).into_bytes()) }; } @@ -45,31 +40,17 @@ macro_rules! empty_list_as_cell { macro_rules! atom_as_cell { ($atom:expr) => { - HeapCellValue::from_bytes( - AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::Atom).into_bytes(), - ) + HeapCellValue::from_bytes(AtomCell::build_with($atom.index, 0).into_bytes()) }; ($atom:expr, $arity:expr) => { - HeapCellValue::from_bytes( - AtomCell::build_with($atom.flat_index(), $arity as u16, HeapCellValueTag::Atom) - .into_bytes(), - ) - }; -} - -macro_rules! cell_as_string { - ($cell:expr) => { - PartialString::from(cell_as_atom!($cell)) + HeapCellValue::from_bytes(AtomCell::build_with($atom.index, $arity as u8).into_bytes()) }; } macro_rules! cell_as_atom { - ($cell:expr) => {{ - let cell = AtomCell::from_bytes($cell.into_bytes()); - let name = (cell.get_index() as u64) << 3; - - Atom::from(name) - }}; + ($cell:expr) => { + AtomCell::from_bytes($cell.into_bytes()).get_name() + }; } macro_rules! cell_as_atom_cell { @@ -91,26 +72,12 @@ macro_rules! cell_as_untyped_arena_ptr { }; } -macro_rules! pstr_as_cell { - ($atom:expr) => { - HeapCellValue::from_bytes( - AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::PStr).into_bytes(), - ) - }; -} - macro_rules! pstr_loc_as_cell { ($h:expr) => { HeapCellValue::build_with(HeapCellValueTag::PStrLoc, $h as u64) }; } -macro_rules! pstr_offset_as_cell { - ($h:expr) => { - HeapCellValue::build_with(HeapCellValueTag::PStrOffset, $h as u64) - }; -} - macro_rules! list_loc_as_cell { ($h:expr) => { HeapCellValue::build_with(HeapCellValueTag::Lis, $h as u64) @@ -186,36 +153,10 @@ macro_rules! untyped_arena_ptr_as_cell { }; } -macro_rules! atom_as_cstr_cell { - ($atom:expr) => {{ - let offset = $atom.flat_index(); - - HeapCellValue::from_bytes( - AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(), - ) - }}; -} - -macro_rules! string_as_cstr_cell { - ($ptr:expr) => {{ - let atom: Atom = $ptr.into(); - let offset = atom.flat_index(); - - HeapCellValue::from_bytes( - AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(), - ) - }}; -} - -macro_rules! string_as_pstr_cell { - ($ptr:expr) => {{ - let atom: Atom = $ptr.into(); - let offset = atom.flat_index(); - - HeapCellValue::from_bytes( - AtomCell::build_with(offset as u64, 0, HeapCellValueTag::PStr).into_bytes(), - ) - }}; +macro_rules! stream_as_cell { + ($ptr:expr) => { + raw_ptr_as_cell!($ptr.as_ptr()) + }; } macro_rules! cell_as_stream { @@ -351,6 +292,7 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; + /* ($cell:ident, PStr, $atom:ident, $code:expr) => {{ let $atom = cell_as_atom!($cell); #[allow(unused_braces)] @@ -371,6 +313,7 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; + */ ($cell:ident, Fixnum, $value:ident, $code:expr) => {{ let $value = Fixnum::from_bytes($cell.into_bytes()); #[allow(unused_braces)] @@ -437,119 +380,6 @@ macro_rules! read_heap_cell { }); } -macro_rules! functor { - ($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({ - { - #[allow(unused_variables, unused_mut)] - let mut addendum = Heap::new(); - let arity: usize = count_tt!($($dt) +); - - #[allow(unused_variables)] - let aux_lens: [usize; count_tt!($($aux) *)] = [$($aux.len()),*]; - - let mut result = - vec![ atom_as_cell!($name, arity as u16), - $(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ]; - - $( - result.extend($aux.iter()); - )* - - result.extend(addendum.into_iter()); - result - } - }); - ($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({ - { - let arity: usize = count_tt!($($dt) +); - - #[allow(unused_variables, unused_mut)] - let mut addendum = Heap::new(); - - let mut result = - vec![ atom_as_cell!($name, arity as u16), - $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]; - - result.extend(addendum.into_iter()); - result - } - }); - ($name:expr) => ({ - vec![ atom_as_cell!($name) ] - }); -} - -macro_rules! functor_term { - (str(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - str_loc_as_cell!($arity + 1) - }); - (str($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - let len: usize = $aux_lens[0 .. $e].iter().sum(); - str_loc_as_cell!($arity + 1 + len) - }); - (str($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - str_loc_as_cell!($arity + $h + 1) - }); - (str($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - let len: usize = $aux_lens[0 .. $e].iter().sum(); - str_loc_as_cell!($arity + $h + 1 + len) - }); - (literal($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::from($e) - ); - (integer($e:expr, $arena:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::arena_from(Number::arena_from($e, $arena), $arena) - ); - (fixnum($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - fixnum_as_cell!(Fixnum::build_with($e as i64)) - ); - (indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - let stub = - match $e { - IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]), - IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]), - IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]), - IndexingCodePtr::Fail => { - vec![atom_as_cell!(atom!("fail"))] - }, - }; - - let len: usize = $aux_lens.iter().sum(); - let h = len + $arity + 1 + $addendum.len() + $h; - - $addendum.extend(stub.into_iter()); - - str_loc_as_cell!(h) - }); - (number($arena:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::from(($e, $arena)) - ); - (atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - atom_as_cell!($e) - ); - (string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({ - let len: usize = $aux_lens.iter().sum(); - let h = len + $arity + 1 + $addendum.len() + $h; - - let cell = string_as_pstr_cell!($e); - - $addendum.push(cell); - $addendum.push(empty_list_as_cell!()); - - heap_loc_as_cell!(h) - }); - (boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({ - if $e { - functor_term!(atom(atom!("true")), $arity, $aux_lens, $addendum) - } else { - functor_term!(atom(atom!("false")), $arity, $aux_lens, $addendum) - } - }); - (cell($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - $e - ); -} - macro_rules! compare_number_instr { ($cmp: expr, $at_1: expr, $at_2: expr) => {{ $cmp.set_terms($at_1, $at_2); @@ -634,3 +464,44 @@ macro_rules! compare_term_test { $machine_st.compare_term_test($var_comparison) }}; } + +macro_rules! step_or_resource_error { + ($machine_st:expr, $val:expr) => {{ + match $val { + Ok(r) => r, + Err(err_loc) => { + $machine_st.throw_resource_error(err_loc); + return; + } + } + }}; + ($machine_st:expr, $val:expr, $fail:block) => {{ + match $val { + Ok(r) => r, + Err(err_loc) => { + $machine_st.throw_resource_error(err_loc); + $fail + } + } + }}; +} + +macro_rules! resource_error_call_result { + ($machine_st:expr, $val:expr) => { + step_or_resource_error!($machine_st, $val, { + return Err(vec![]); // TODO: return Ok(()); + }) + }; +} + +macro_rules! heap_index { + ($idx:expr) => { + ($idx) * std::mem::size_of::() + }; +} + +macro_rules! cell_index { + ($idx:expr) => { + (($idx) / std::mem::size_of::()) + }; +} diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 727e9b78..52aff1c0 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -3,10 +3,8 @@ use crate::arena::*; use crate::atom_table::*; use crate::forms::PredicateKey; -use crate::machine::copier::*; use crate::machine::heap::*; use crate::machine::machine_indices::*; -use crate::machine::machine_state::*; use crate::types::*; use std::fmt; @@ -14,11 +12,8 @@ use std::hash::Hash; use std::io::{Error as IOError, ErrorKind}; use std::ops::Neg; use std::rc::Rc; -use std::sync::Arc; use std::vec::Vec; -use crate::parser::dashu::{Integer, Rational}; - use fxhash::FxBuildHasher; use indexmap::IndexMap; use scryer_modular_bitfield::error::OutOfBounds; @@ -26,7 +21,7 @@ use scryer_modular_bitfield::prelude::*; pub type Specifier = u32; -pub const MAX_ARITY: usize = 1023; +pub const MAX_ARITY: usize = 255; #[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -143,7 +138,12 @@ pub const BTERM: u32 = 0x11000; pub const NEGATIVE_SIGN: u32 = 0x0200; macro_rules! fixnum { - ($wrapper:tt, $n:expr, $arena:expr) => { + ($n:expr, $arena:expr) => { + Fixnum::build_with_checked($n) + .map(|n| fixnum_as_cell!(n)) + .unwrap_or_else(|_| typed_arena_ptr_as_cell!(arena_alloc!(Integer::from($n), $arena) as TypedArenaPtr)) + }; + ($wrapper:ty, $n:expr, $arena:expr) => { Fixnum::build_with_checked($n) .map(<$wrapper>::Fixnum) .unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena))) @@ -272,50 +272,12 @@ impl fmt::Display for RegType { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum VarReg { - ArgAndNorm(RegType, usize), - Norm(RegType), -} - -impl VarReg { - pub fn norm(self) -> RegType { - match self { - VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg, - } - } -} - -impl fmt::Display for VarReg { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), - VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), - VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg), - VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg), - } - } -} - -impl Default for VarReg { - fn default() -> Self { - VarReg::Norm(RegType::default()) - } -} - macro_rules! temp_v { ($x:expr) => { $crate::parser::ast::RegType::Temp($x) }; } -#[macro_export] -macro_rules! perm_v { - ($x:expr) => { - $crate::parser::ast::RegType::Perm($x) - }; -} - #[bitfield] #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct OpDesc { @@ -410,7 +372,6 @@ pub fn default_op_dir() -> OpDir { #[derive(Debug, Clone)] pub enum ArithmeticError { NonEvaluableFunctor(HeapCellValue, usize), - UninstantiatedVar, } #[derive(Debug, Copy, Clone, Default)] @@ -430,6 +391,7 @@ pub enum ParserError { MissingQuote(ParserErrorSrc), NonPrologChar(ParserErrorSrc), ParseBigInt(ParserErrorSrc), + ResourceError(ParserErrorSrc), UnexpectedChar(char, ParserErrorSrc), // UnexpectedEOF, Utf8Error(ParserErrorSrc), @@ -447,6 +409,7 @@ impl ParserError { | &ParserError::MissingQuote(err_src) | &ParserError::NonPrologChar(err_src) | &ParserError::ParseBigInt(err_src) + | &ParserError::ResourceError(err_src) | &ParserError::UnexpectedChar(_, err_src) | &ParserError::Utf8Error(err_src) => err_src, } @@ -475,6 +438,7 @@ impl ParserError { ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"), ParserError::UnexpectedChar(..) => atom!("unexpected_char"), ParserError::Utf8Error(..) => atom!("utf8_conversion_error"), + ParserError::ResourceError(..) => atom!("resource_error"), } } @@ -492,29 +456,13 @@ impl ParserError { } } } -/* -impl From for ParserError { - fn from((e, err_src): (lexical::Error, ParserErrorSrc)) -> ParserError { - ParserError::LexicalError(e, err_src) + +impl From for ParserError { + fn from(err_src: ParserErrorSrc) -> ParserError { + ParserError::LexicalError(err_src) } } -impl From for ParserError { - fn from(e: IOError) -> ParserError { - ParserError::IO(e) - } -} - -impl From<&IOError> for ParserError { - fn from(error: &IOError) -> ParserError { - if error.get_ref().filter(|e| e.is::()).is_some() { - ParserError::Utf8Error(0, 0) - } else { - ParserError::IO(error.kind().into()) - } - } -} -*/ #[derive(Debug, Clone, Copy)] pub struct CompositeOpDir<'a, 'b> { pub primary_op_dir: Option<&'b OpDir>, @@ -623,16 +571,16 @@ impl Neg for Fixnum { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +/* +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Literal { Atom(Atom), - Char(char), CodeIndex(CodeIndex), Fixnum(Fixnum), Integer(TypedArenaPtr), Rational(TypedArenaPtr), Float(F64Offset), - String(Atom), + String(Rc), } impl From for Literal { @@ -648,7 +596,7 @@ impl fmt::Display for Literal { Literal::Atom(ref atom) => { write!(f, "{}", atom.flat_index()) } - Literal::Char(c) => write!(f, "'{}'", *c as u32), + // Literal::Char(c) => write!(f, "'{}'", *c as u32), Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64), Literal::Fixnum(n) => write!(f, "{}", n.get_num()), Literal::Integer(ref n) => write!(f, "{}", n), @@ -667,10 +615,14 @@ impl Literal { } } } +*/ pub type Var = Rc; -pub(crate) fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) { +pub(crate) fn subterm_index( + heap: &impl SizedHeap, + subterm_loc: usize, +) -> (usize, HeapCellValue) { let subterm = heap[subterm_loc]; if subterm.is_ref() { @@ -696,11 +648,12 @@ pub enum Term { AnonVar, Clause(Cell, Atom, Vec), Cons(Cell, Box, Box), - Literal(Cell, Literal), + Literal(Cell, HeapCellValue), + // Literal(Cell, Literal), // PartialString wraps a String in anticipation of it absorbing // other PartialString variants in as_partial_string. - PartialString(Cell, String, Box), - CompleteString(Cell, Atom), + PartialString(Cell, Rc, Box), + CompleteString(Cell, Rc), Var(Cell, VarPtr), } @@ -714,8 +667,11 @@ impl Term { pub fn name(&self) -> Option { match self { - &Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => { - Some(*atom) + Term::Literal(_, cell) => { + cell.to_atom() + } + &Term::Clause(_, atom, ..) => { + Some(atom) } _ => None, } @@ -760,11 +716,11 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec { */ pub(crate) fn fetch_index_ptr( - heap: &[HeapCellValue], + heap: &impl SizedHeap, arity: usize, term_loc: usize, ) -> Option { - if term_loc + arity + 1 >= heap.len() { + if term_loc + arity + 1 >= heap.cell_len() || heap.pstr_at(term_loc + arity + 1) { return None; } @@ -784,7 +740,7 @@ pub(crate) fn fetch_index_ptr( } pub(crate) fn blunt_index_ptr( - heap: &mut [HeapCellValue], + heap: &mut impl SizedHeapMut, key: PredicateKey, term_loc: usize, ) -> bool { @@ -797,7 +753,7 @@ pub(crate) fn blunt_index_ptr( } pub(crate) fn unfold_by_str_once( - heap: &mut [HeapCellValue], + heap: &mut impl SizedHeapMut, start_term: HeapCellValue, atom: Atom, ) -> Option { @@ -821,7 +777,7 @@ pub(crate) fn unfold_by_str_once( } pub fn unfold_by_str( - heap: &mut [HeapCellValue], + heap: &mut impl SizedHeapMut, mut start_term: HeapCellValue, atom: Atom, ) -> Vec { @@ -862,7 +818,7 @@ pub fn unfold_by_str_locs( */ pub fn unfold_by_str_locs( - heap: &mut [HeapCellValue], + heap: &mut impl SizedHeapMut, mut term_loc: usize, atom: Atom, ) -> Vec<(HeapCellValue, usize)> { @@ -880,11 +836,14 @@ pub fn unfold_by_str_locs( terms } -pub fn term_name(heap: &[HeapCellValue], mut term_loc: usize) -> Option { +pub fn term_predicate_key( + heap: &impl SizedHeap, + mut term_loc: usize, +) -> Option { loop { read_heap_cell!(heap[term_loc], - (HeapCellValueTag::Atom, (name, _arity)) => { - return Some(name); + (HeapCellValueTag::Atom, (name, arity)) => { + return Some((name, arity)); } (HeapCellValueTag::Str, s) => { term_loc = s; @@ -903,32 +862,6 @@ pub fn term_name(heap: &[HeapCellValue], mut term_loc: usize) -> Option { } } -pub fn term_arity(heap: &[HeapCellValue], mut term_loc: usize) -> usize { - loop { - read_heap_cell!(heap[term_loc], - (HeapCellValueTag::Atom, (_name, arity)) => { - return arity; - } - (HeapCellValueTag::Str, s) => { - term_loc = s; - } - (HeapCellValueTag::Lis) => { - return 2; - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h != term_loc { - term_loc = h; - } else { - return 0; - } - } - _ => { - return 0; - } - ); - } -} - pub fn inverse_var_locs_from_iter>(iter: I) -> InverseVarLocs { let mut occurrence_set: IndexMap = IndexMap::with_hasher(FxBuildHasher::default()); @@ -975,7 +908,7 @@ pub fn term_deref(heap: &[HeapCellValue], mut term_loc: usize) -> HeapCellValue } */ -pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Option { +pub fn term_nth_arg(heap: &impl SizedHeap, mut term_loc: usize, n: usize) -> Option { loop { read_heap_cell!(heap[term_loc], (HeapCellValueTag::Str, s) => { @@ -1015,108 +948,55 @@ pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Op } } -pub type VarLocs = IndexMap; -pub type InverseVarLocs = IndexMap; - #[derive(Debug)] -pub struct FocusedHeap { - pub heap: Vec, +pub struct TermWriteResult { pub focus: usize, pub inverse_var_locs: InverseVarLocs, } -impl FocusedHeap { - pub fn empty() -> Self { - Self { - heap: vec![], - focus: 0, - inverse_var_locs: InverseVarLocs::default(), - } - } - - pub fn copy_term_from_machine_heap( - &mut self, - machine_st: &mut MachineState, - cell: HeapCellValue, - ) { - let hb = machine_st.heap.len(); - - copy_term( - CopyBallTerm::new( - &mut machine_st.attr_var_init.attr_var_queue, - &mut machine_st.stack, - &mut machine_st.heap, - &mut self.heap, - ), - cell, - AttrVarPolicy::DeepCopy, - ); - - for cell in self.heap.iter_mut() { - *cell = *cell - hb; - } - } - - pub fn as_ref_mut(&mut self, focus: usize) -> FocusedHeapRefMut { - FocusedHeapRefMut { - heap: &mut self.heap, - focus, - } - } - - pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue { - use crate::machine::heap::*; - - let cell = self.heap[term_loc]; - heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell)) - } - - pub fn name(&self, term_loc: usize) -> Option { - 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 type VarLocs = IndexMap; +pub type InverseVarLocs = IndexMap; +#[derive(Debug)] pub struct FocusedHeapRefMut<'a> { - pub heap: &'a mut Vec, + pub heap: &'a mut Heap, pub focus: usize, } impl<'a> FocusedHeapRefMut<'a> { - pub fn name(&self, term_loc: usize) -> Option { - term_name(&self.heap, term_loc) + #[inline] + pub fn from(heap: &'a mut Heap, focus: usize) -> Self { + Self { heap, focus } + } + + pub fn predicate_key(&self, term_loc: usize) -> Option { + term_predicate_key(self.heap, term_loc) } pub fn arity(&self, term_loc: usize) -> usize { - term_arity(&self.heap, term_loc) + self.predicate_key(term_loc) + .map(|(_, arity)| arity) + .unwrap_or(0) } pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue { - use crate::machine::heap::*; - let cell = self.heap[term_loc]; - heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell)) + heap_bound_store(self.heap, heap_bound_deref(self.heap, cell)) } pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option { term_nth_arg(self.heap, term_loc, n) } - pub fn from_cell(heap: &'a mut Vec, cell: HeapCellValue) -> Self { + /* + pub fn from_cell(heap: &'a mut Heap, cell: HeapCellValue) -> Self { let focus = read_heap_cell!(cell, (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { h } _ => { let h = heap.len(); - heap.push(cell); + heap.push_cell(cell).unwrap(); h } @@ -1124,4 +1004,5 @@ impl<'a> FocusedHeapRefMut<'a> { Self { heap, focus } } + */ } diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 556f69ed..615b00ca 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -1,13 +1,15 @@ use crate::arena::F64Ptr; use crate::arena::TypedArenaPtr; -use lexical::{FromLexicalLossy, parse_lossy}; +use lexical::{FromLexical, parse}; -use crate::arena::ArenaAllocated; +use crate::arena::*; use crate::atom_table::*; +use crate::machine::heap::*; pub use crate::machine::machine_state::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::dashu::Integer; +use crate::types::*; use std::convert::TryFrom; use std::fmt; @@ -33,8 +35,9 @@ struct LayoutInfo { #[derive(Debug, PartialEq)] pub enum Token { - Literal(Literal), + Literal(HeapCellValue), Var(String), + String(String), Open, // '(' OpenCT, // '(' Close, // ')' @@ -48,6 +51,30 @@ pub enum Token { } impl Token { + pub(super) fn byte_size(&self, flags: MachineFlags) -> usize { + match self { + Token::String(string) if flags.double_quotes.is_codes() => { + 2 * string.chars().count() + 1 + } + Token::String(string) => { + Heap::compute_pstr_size(&string) + } + Token::Literal(_) | + Token::Comma | + Token::HeadTailSeparator | + Token::Open | + Token::OpenCT | + Token::OpenCurly | + Token::OpenList | + Token::Var(_) => { + heap_index!(1) + } + _ => { + 0 + } + } + } + #[inline] pub(super) fn is_end(&self) -> bool { matches!(self, Token::End) @@ -103,16 +130,16 @@ macro_rules! try_nt { }}; } -pub struct Lexer<'a, R> { +pub(crate) struct LexerParser<'a, R> { pub(crate) reader: R, pub(crate) machine_st: &'a mut MachineState, pub(crate) line_num: usize, pub(crate) col_num: usize, } -impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> { +impl<'a, R: fmt::Debug> fmt::Debug for LexerParser<'a, R> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lexer") + f.debug_struct("LexerParser") .field("reader", &"&'a mut R") // Hacky solution. .field("line_num", &self.line_num) .field("col_num", &self.col_num) @@ -120,9 +147,9 @@ impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> { } } -impl<'a, R: CharRead> Lexer<'a, R> { +impl<'a, R: CharRead> LexerParser<'a, R> { pub fn new(src: R, machine_st: &'a mut MachineState) -> Self { - Lexer { + LexerParser { reader: src, machine_st, line_num: 0, @@ -144,11 +171,6 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } - #[inline] - pub fn loc_to_err_src(&self) -> ParserErrorSrc { - ParserErrorSrc { line_num: self.line_num, col_num: self.col_num } - } - #[inline(always)] fn return_char(&mut self, c: char) { self.reader.put_back_char(c); @@ -631,11 +653,11 @@ impl<'a, R: CharRead> Lexer<'a, R> { if !token.is_empty() && token.chars().nth(1).is_none() { if let Some(c) = token.chars().next() { - return Ok(Token::Literal(Literal::Char(c))); + return Ok(Token::Literal(char_as_cell!(c))); } } } else { - return Err(ParserError::InvalidSingleQuotedCharacter(c, self.loc_to_err_src())); + return Err(ParserError::InvalidSingleQuotedCharacter(self.loc_to_err_src())); } } else { match self.get_back_quoted_string() { @@ -645,26 +667,29 @@ impl<'a, R: CharRead> Lexer<'a, R> { } if token.as_str() == "[]" { - Ok(Token::Literal(Literal::Atom(atom!("[]")))) + Ok(Token::Literal(empty_list_as_cell!())) } else { - Ok(Token::Literal(Literal::Atom(AtomTable::build_with( + Ok(Token::Literal(atom_as_cell!(AtomTable::build_with( &self.machine_st.atom_tbl, &token, )))) } } - fn parse_lossy_wrapper(&self, token: String) -> Result { - match parse_lossy::(token.as_bytes()) { + fn parse_lossy_wrapper(&self, token: &str) -> Result { + match parse::(token.as_bytes()) { Ok(n) => Ok(n), - Err(e) => return Err(ParserError::LexicalError(e, self.loc_to_err_src())), + Err(_) => return Err(ParserError::LexicalError(self.loc_to_err_src())), } } fn vacate_with_float(&mut self, mut token: String) -> Result { self.return_char(token.pop().unwrap()); - let n = self.parse_lossy_wrapper::(token)?; - Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena)))) + let n = self.parse_lossy_wrapper::(&token)?; + Ok(Token::Literal(HeapCellValue::from(float_alloc!( + n, + self.machine_st.arena + )))) } fn skip_underscore_in_number(&mut self) -> Result { @@ -790,8 +815,8 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } - let n = parse_float_lossy(&token)?; - Ok(NumberToken::Number(Number::Float(float_alloc!( + let n = self.parse_lossy_wrapper::(&token)?; + Ok(Token::Literal(HeapCellValue::from(float_alloc!( n, self.machine_st.arena )))) @@ -799,8 +824,8 @@ impl<'a, R: CharRead> Lexer<'a, R> { return self.vacate_with_float(token).map(NumberToken::Number); } } else { - let n = parse_float_lossy(&token)?; - Ok(NumberToken::Number(Number::Float(float_alloc!( + let n = self.parse_lossy_wrapper::(&token)?; + Ok(Token::Literal(HeapCellValue::from(float_alloc!( n, self.machine_st.arena )))) @@ -1034,12 +1059,12 @@ impl<'a, R: CharRead> Lexer<'a, R> { if c == '"' { let s = self.char_code_list_token(c)?; - let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s); return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes { - Ok(Token::Literal(Literal::Atom(atom))) + let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s); + Ok(Token::Literal(atom_as_cell!(atom))) } else { - Ok(Token::Literal(Literal::String(atom))) + Ok(Token::String(s)) }; } @@ -1053,13 +1078,3 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } } - -fn parse_float_lossy(token: &str) -> Result { - const FORMAT: u128 = lexical::format::STANDARD; - let options = lexical::ParseFloatOptions::builder() - .lossy(true) - .build() - .unwrap(); - let n = lexical::parse_with_options::(token.as_bytes(), &options)?; - Ok(n) -} diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 7eead62c..9313e9e9 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -3,14 +3,13 @@ use dashu::Rational; use crate::arena::*; use crate::atom_table::*; -use crate::machine::heap::{heap_bound_deref, heap_bound_store}; -use crate::machine::partial_string::*; +use crate::forms::Number; +use crate::machine::heap::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::lexer::*; use crate::types::*; -use std::mem; use std::ops::Neg; use std::rc::Rc; @@ -53,7 +52,7 @@ provided via the Provided variant. #[derive(Debug)] pub enum Tokens { Default, - Provided(Vec), + Provided(Vec, usize), } impl TokenType { @@ -176,22 +175,27 @@ pub struct CompositeOpDesc { } #[derive(Debug)] -pub struct Parser<'a, R> { - pub lexer: Lexer<'a, R>, +struct Parser<'a> { tokens: Vec, stack: Vec, - terms: Vec, + terms: HeapWriter<'a>, + arena: &'a mut Arena, + flags: MachineFlags, + line_num: &'a mut usize, + col_num: &'a mut usize, var_locs: VarLocs, inverse_var_locs: InverseVarLocs, } -fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> { +pub fn read_tokens(lexer: &mut LexerParser) -> Result<(Vec, usize), ParserError> { let mut tokens = vec![]; + let mut term_size = 0; loop { match lexer.next_token() { Ok(token) => { let at_end = token.is_end(); + term_size += token.byte_size(lexer.machine_st.flags); tokens.push(token); if at_end { @@ -209,19 +213,11 @@ fn read_tokens(lexer: &mut Lexer) -> Result, ParserEr tokens.reverse(); - Ok(tokens) -} - -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())), - _ => None, - } + Ok((tokens, term_size)) } pub(crate) fn as_partial_string( - heap: &[HeapCellValue], + heap: &impl SizedHeap, head: HeapCellValue, tail: HeapCellValue, ) -> Option<(String, Option)> { @@ -240,9 +236,6 @@ pub(crate) fn as_partial_string( return None; } } - (HeapCellValueTag::Char, c) => { - c.to_string() - } _ => { return None; } @@ -263,9 +256,6 @@ pub(crate) fn as_partial_string( break; } } - (HeapCellValueTag::Char, c) => { - string.push(c); - } _ => { return None; } @@ -274,16 +264,9 @@ pub(crate) fn as_partial_string( tail = heap[l+1]; } (HeapCellValueTag::PStrLoc, l) => { - let (index, n) = pstr_loc_and_offset(&heap, l); - let n = n.get_num() as usize; - - string += &*cell_as_string!(heap[index]).as_str_from(n); - tail = heap[l+1]; - } - (HeapCellValueTag::CStr, cstr_atom) => { - string += &*cstr_atom.as_str(); - tail = empty_list_as_cell!(); - break; + let (pstr, tail_loc) = heap.scan_slice_to_str(l); + string += pstr; + tail = heap[tail_loc]; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if heap[h] != tail { @@ -316,36 +299,15 @@ pub(crate) fn as_partial_string( ) } -impl<'a, R: CharRead> Parser<'a, R> { - pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self { - Parser { - lexer: Lexer::new(stream, machine_st), - tokens: vec![], - stack: vec![], - terms: vec![], - var_locs: VarLocs::default(), - inverse_var_locs: InverseVarLocs::default(), - } - } - - pub fn from_lexer(lexer: Lexer<'a, R>) -> Self { - Parser { - lexer, - tokens: vec![], - stack: vec![], - terms: vec![], - var_locs: VarLocs::default(), - inverse_var_locs: InverseVarLocs::default(), - } - } - +impl<'a> Parser<'a> { fn get_term_name(&self, td: TokenDesc) -> Option { match td.tt { TokenType::HeadTailSeparator => Some(atom!("|")), TokenType::Comma => Some(atom!(",")), TokenType::Term { heap_loc } => { if heap_loc.is_ref() { - term_name(&self.terms, heap_loc.get_value() as usize) + term_predicate_key(&self.terms, heap_loc.get_value() as usize) + .map(|key| key.0) } else { None } @@ -354,16 +316,6 @@ impl<'a, R: CharRead> Parser<'a, R> { } } - #[inline] - pub fn line_num(&self) -> usize { - self.lexer.line_num - } - - #[inline] - pub fn col_num(&self) -> usize { - self.lexer.col_num - } - fn push_binary_op( &mut self, op: TokenDesc, @@ -382,13 +334,15 @@ impl<'a, R: CharRead> Parser<'a, R> { } = operand_1 { if let Some(name) = self.get_term_name(op) { - let str_loc = self.terms.len(); + let str_loc = self.terms.cell_len(); - self.terms.push(atom_as_cell!(name, 2)); - self.terms.push(arg1); - self.terms.push(arg2); + self.terms.write_with(|section| { + section.push_cell(atom_as_cell!(name, 2)); + section.push_cell(arg1); + section.push_cell(arg2); - self.terms.push(str_loc_as_cell!(str_loc)); + section.push_cell(str_loc_as_cell!(str_loc)); + }); self.stack.push(TokenDesc { tt: TokenType::Term { @@ -404,10 +358,6 @@ impl<'a, R: CharRead> Parser<'a, R> { } fn push_unary_op(&mut self, op: TokenDesc, operand: TokenDesc, spec: Specifier) { - // if is_postfix!(assoc) { - // mem::swap(&mut op, &mut operand); - // } - if let TokenDesc { tt: TokenType::Term { heap_loc: arg1 }, .. @@ -419,11 +369,13 @@ impl<'a, R: CharRead> Parser<'a, R> { } = op { if let Some(name) = self.get_term_name(op) { - let str_loc = self.terms.len(); + let str_loc = self.terms.cell_len(); - self.terms.push(atom_as_cell!(name, 1)); - self.terms.push(arg1); - self.terms.push(str_loc_as_cell!(str_loc)); + self.terms.write_with(|section| { + section.push_cell(atom_as_cell!(name, 1)); + section.push_cell(arg1); + section.push_cell(str_loc_as_cell!(str_loc)); + }); self.stack.push(TokenDesc { tt: TokenType::Term { @@ -439,8 +391,8 @@ impl<'a, R: CharRead> Parser<'a, R> { } fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) { - let h = self.terms.len(); - self.terms.push(atom_as_cell!(atom)); + let h = self.terms.cell_len(); + self.terms.write_with(|section| section.push_cell(atom_as_cell!(atom))); self.stack.push(TokenDesc { tt: TokenType::Term { heap_loc: heap_loc_as_cell!(h), @@ -452,51 +404,61 @@ impl<'a, R: CharRead> Parser<'a, R> { } fn shift(&mut self, token: Token, priority: usize, spec: Specifier) { - let heap_loc = heap_loc_as_cell!(self.terms.len()); + let heap_loc = heap_loc_as_cell!(self.terms.cell_len()); let tt = match token { - Token::Literal(Literal::String(s)) - if self.lexer.machine_st.flags.double_quotes.is_codes() => - { + Token::String(s) if self.flags.double_quotes.is_codes() => { let mut list = empty_list_as_cell!(); - for c in s.as_str().chars().rev() { - let h = self.terms.len(); + self.terms.write_with(|section| { + for c in s.as_str().chars().rev() { + let h = section.cell_len(); - self.terms - .push(fixnum_as_cell!(Fixnum::build_with(c as i64))); - self.terms.push(list); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(c as i64))); + section.push_cell(list); - list = list_loc_as_cell!(h); - } + list = list_loc_as_cell!(h); + } - self.terms.push(list); + section.push_cell(list); + }); TokenType::Term { heap_loc: list } } - Token::Literal(Literal::String(s)) - if self.lexer.machine_st.flags.double_quotes.is_chars() => - { - if s.is_empty() { - self.terms.push(empty_list_as_cell!()); + Token::String(s) => { + debug_assert!(self.flags.double_quotes.is_chars()); + let mut pstr_cell = heap_loc; + + if s == "\u{0}" { + let h = self.terms.cell_len(); + + self.terms.write_with(|section| { + section.push_cell(char_as_cell!('\u{0}')); + section.push_cell(empty_list_as_cell!()); + section.push_cell(list_loc_as_cell!(h)); + }); + + TokenType::Term { heap_loc: heap_loc_as_cell!(h + 2) } } else { - self.terms.push(string_as_cstr_cell!(s)); + self.terms.write_with(|section| { + match section.push_pstr(&s) { + Some(pstr_loc_cell) => { + section.push_cell(empty_list_as_cell!()); + let h = section.cell_len(); + section.push_cell(pstr_loc_cell); + pstr_cell = heap_loc_as_cell!(h); + } + None => { + section.push_cell(empty_list_as_cell!()); + } + } + }); + + TokenType::Term { heap_loc: pstr_cell } } - - 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(HeapCellValue::from(c)); + self.terms.write_with(|section| section.push_cell(c)); TokenType::Term { heap_loc } } Token::Var(var_string) => { @@ -504,11 +466,11 @@ impl<'a, R: CharRead> Parser<'a, R> { match self.var_locs.get(&var).cloned() { Some(heap_loc) => { - self.terms.push(heap_loc); + self.terms.write_with(|section| section.push_cell(heap_loc)); TokenType::Term { heap_loc } } None => { - self.terms.push(heap_loc); + self.terms.write_with(|section| section.push_cell(heap_loc)); // if var_string == "_", it not being present // as a key of self.var_locs means it is @@ -649,23 +611,23 @@ impl<'a, R: CharRead> Parser<'a, R> { return false; } - if self.terms.len() < arity { + if self.terms.cell_len() < arity { return false; } let stack_len = self.stack.len() - 2 * arity - 1; - let term_idx = self.terms.len(); + let term_idx = self.terms.cell_len(); let push_structure = |parser: &mut Self, name: Atom| -> TokenType { - parser.terms.push(atom_as_cell!(name, arity)); + parser.terms.write_with(|section| section.push_cell(atom_as_cell!(name, arity))); for idx in (stack_len + 2..parser.stack.len()).step_by(2) { let subterm = parser.term_from_stack(idx).unwrap(); - parser.terms.push(subterm); + parser.terms.write_with(|section| section.push_cell(subterm)); } - let str_loc_idx = parser.terms.len(); - parser.terms.push(str_loc_as_cell!(term_idx)); + let str_loc_idx = parser.terms.cell_len(); + parser.terms.write_with(|section| section.push_cell(str_loc_as_cell!(term_idx))); TokenType::Term { heap_loc: heap_loc_as_cell!(str_loc_idx), @@ -679,39 +641,38 @@ impl<'a, R: CharRead> Parser<'a, R> { { let idx = heap_loc.get_value() as usize; - if let Some(name) = term_name(&self.terms, idx) { + if let Some((name, arity)) = term_predicate_key(&self.terms, idx) { // reduce the '.' functor to a cons cell if it applies. let new_tt = if name == atom!(".") && arity == 2 { let head = self.term_from_stack(stack_len + 2).unwrap(); let tail = self.term_from_stack(stack_len + 4).unwrap(); + let cell_len = self.terms.cell_len(); match as_partial_string(&self.terms, head, tail) { - Some((string_buf, Some(tail))) => { - let atom = - AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); + Some((string_buf, tail_opt)) => { + let bytes_written = self.terms.write_with(|section| { + let pstr_cell = section.push_pstr(&string_buf).unwrap(); + section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); + section.push_cell(pstr_cell); + }); - self.terms.push(string_as_pstr_cell!(atom)); - self.terms.push(tail); - self.terms.push(pstr_loc_as_cell!(term_idx)); + let heap_loc = cell_index!(bytes_written) - 1 + cell_len; TokenType::Term { - heap_loc: heap_loc_as_cell!(term_idx + 2), - } - } - Some((string_buf, None)) => { - let atom = - AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); - TokenType::Term { - heap_loc: string_as_cstr_cell!(atom), + heap_loc: heap_loc_as_cell!(heap_loc), } } None => { - self.terms.push(head); - self.terms.push(tail); - self.terms.push(list_loc_as_cell!(term_idx)); + let bytes_written = self.terms.write_with(|section| { + section.push_cell(head); + section.push_cell(tail); + section.push_cell(list_loc_as_cell!(term_idx)); + }); TokenType::Term { - heap_loc: heap_loc_as_cell!(term_idx + 2), + heap_loc: heap_loc_as_cell!( + cell_len + cell_index!(bytes_written) - 1 + ), } } } @@ -747,9 +708,8 @@ impl<'a, R: CharRead> Parser<'a, R> { false } - pub fn reset(&mut self) { - self.stack.clear(); - self.var_locs.clear(); + fn loc_to_err_src(&self) -> ParserErrorSrc { + ParserErrorSrc { line_num: *self.line_num, col_num: *self.col_num } } fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { @@ -764,17 +724,17 @@ impl<'a, R: CharRead> Parser<'a, R> { ); if term.is_ref() && - 0 < op_desc.priority && op_desc.priority < self.stack[index].priority + 0 < op_desc.priority && + op_desc.priority < self.stack[index].priority { /* '|' is a head-tail separator here, not * an operator, so expand the * terms it compacted out again. */ let focus = term.get_value() as usize; - let name_opt = term_name(&self.terms, focus); - let arity = term_arity(&self.terms, focus); + let key_opt = term_predicate_key(&self.terms, focus); - if name_opt == Some(atom!(",")) && arity == 2 { + if key_opt == Some((atom!(","), 2)) { let terms = if op_desc.unfold_bounds == 0 { unfold_by_str(&mut self.terms, term, atom!(",")) } else { @@ -855,8 +815,8 @@ impl<'a, R: CharRead> Parser<'a, R> { if let Some(ref mut td) = self.stack.last_mut() { // parsed an empty list token if td.tt == TokenType::OpenList { - let h = self.terms.len(); - self.terms.push(empty_list_as_cell!()); + let h = self.terms.cell_len(); + self.terms.write_with(|section| section.push_cell(empty_list_as_cell!())); td.spec = TERM; td.tt = TokenType::Term { @@ -886,7 +846,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Some(term) => term, None => { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } }; @@ -902,13 +862,13 @@ impl<'a, R: CharRead> Parser<'a, R> { tail_term }; - if arity > self.terms.len() { + if arity > self.terms.cell_len() { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } - let pre_terms_len = self.terms.len(); + let pre_terms_len = self.terms.cell_len(); while let Some(token_desc) = self.stack.pop() { let subterm = match token_desc.tt { @@ -922,11 +882,13 @@ impl<'a, R: CharRead> Parser<'a, R> { arity -= 1; - let link_cell = list_loc_as_cell!(self.terms.len() + 1); + let link_cell = list_loc_as_cell!(self.terms.cell_len() + 1); - self.terms.push(link_cell); - self.terms.push(subterm); - self.terms.push(tail_term); + self.terms.write_with(|section| { + section.push_cell(link_cell); + section.push_cell(subterm); + section.push_cell(tail_term); + }); tail_term = link_cell; @@ -939,29 +901,22 @@ impl<'a, R: CharRead> Parser<'a, R> { self.stack.truncate(list_start_idx); - let list_loc = self.terms.len() - 3; + let list_loc = self.terms.cell_len() - 3; let head_term = self.terms[list_loc + 1]; let tail_term = self.terms[list_loc + 2]; let heap_loc = match as_partial_string(&self.terms, head_term, tail_term) { - Some((string_buf, Some(tail))) => { + Some((string_buf, tail_opt)) => { self.terms.truncate(pre_terms_len); - let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); + let bytes_written = self.terms.write_with(|section| { + let pstr_cell = section.push_pstr(&string_buf).unwrap(); + section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); + section.push_cell(pstr_cell); + }); - self.terms.push(string_as_pstr_cell!(atom)); - self.terms.push(tail); - self.terms.push(pstr_loc_as_cell!(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) + heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1) } None => { heap_loc_as_cell!(list_loc) // head_term @@ -975,22 +930,6 @@ impl<'a, R: CharRead> Parser<'a, R> { unfold_bounds: 0, }); - /* - self.terms.push(match list { - Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) { - Ok((string_buf, Some(tail))) => { - Term::PartialString(Cell::default(), string_buf, tail) - } - Ok((string_buf, None)) => { - let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); - Term::CompleteString(Cell::default(), atom) - } - Err(term) => term, - }, - term => term, - }); - */ - Ok(true) } @@ -1001,8 +940,9 @@ impl<'a, R: CharRead> Parser<'a, R> { if let Some(ref mut td) = self.stack.last_mut() { if td.tt == TokenType::OpenCurly { - let h = self.terms.len(); - self.terms.push(atom_as_cell!(atom!("{}"))); + let h = self.terms.cell_len(); + + self.terms.write_with(|section| section.push_cell(atom_as_cell!(atom!("{}")))); td.tt = TokenType::Term { heap_loc: heap_loc_as_cell!(h), @@ -1025,7 +965,7 @@ impl<'a, R: CharRead> Parser<'a, R> { if oc.tt == TokenType::OpenCurly { if let TokenType::Term { heap_loc } = td.tt { - let curly_idx = self.terms.len(); + let curly_idx = self.terms.cell_len(); oc.tt = TokenType::Term { heap_loc: heap_loc_as_cell!(curly_idx + 2), @@ -1033,9 +973,11 @@ impl<'a, R: CharRead> Parser<'a, R> { oc.priority = 0; oc.spec = TERM; - self.terms.push(atom_as_cell!(atom!("{}"), 1)); - self.terms.push(heap_loc); - self.terms.push(str_loc_as_cell!(curly_idx)); + self.terms.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("{}"), 1)); + section.push_cell(heap_loc); + section.push_cell(str_loc_as_cell!(curly_idx)); + }); /* let term = match self.terms.pop() { @@ -1089,8 +1031,6 @@ impl<'a, R: CharRead> Parser<'a, R> { let term = if self.stack[idx].tt.sep_to_atom().is_some() { atom_as_cell!(atom!("|")) - // self.terms - // .push(Term::Literal(Cell::default(), Literal::Atom(atom))); } else { self.term_from_stack(idx).unwrap() }; @@ -1117,7 +1057,7 @@ impl<'a, R: CharRead> Parser<'a, R> { match self .tokens .last() - .ok_or(ParserError::unexpected_eof(self.lexer.loc_to_err_src()))? + .ok_or(ParserError::unexpected_eof(self.loc_to_err_src()))? { // do this when layout hasn't been inserted, // ie. why we don't match on Token::Open. @@ -1173,7 +1113,7 @@ impl<'a, R: CharRead> Parser<'a, R> { fn negate_number(&mut self, n: N, negator: Negator, constr: ToLiteral) where Negator: Fn(N, &mut Arena) -> N, - ToLiteral: Fn(N, &mut Arena) -> Literal, + ToLiteral: Fn(N, &mut Arena) -> HeapCellValue, { match self.stack.last().cloned() { Some( @@ -1187,7 +1127,7 @@ impl<'a, R: CharRead> Parser<'a, R> { if name == atom!("-") && (is_prefix!(spec) || is_negate!(spec)) { self.stack.pop(); - let arena = &mut self.lexer.machine_st.arena; + let arena = &mut self.arena; let literal = constr(negator(n, arena), arena); self.shift(Token::Literal(literal), 0, TERM); @@ -1199,7 +1139,7 @@ impl<'a, R: CharRead> Parser<'a, R> { _ => {} } - let literal = constr(n, &mut self.lexer.machine_st.arena); + let literal = constr(n, &mut self.arena); self.shift(Token::Literal(literal), 0, TERM); } @@ -1217,34 +1157,43 @@ impl<'a, R: CharRead> Parser<'a, R> { } match token { - Token::Literal(Literal::Fixnum(n)) => { - self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n)) + Token::String(string) => { + self.shift(Token::String(string), 0, TERM); } - Token::Literal(Literal::Integer(n)) => { - self.negate_number(n, negate_int_rc, |n, _| Literal::Integer(n)) - } - Token::Literal(Literal::Rational(n)) => { - self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r)) - } - Token::Literal(Literal::Float(n)) if F64Ptr::from_offset(n).is_infinite() => { - return Err(ParserError::InfiniteFloat( - self.lexer.loc_to_err_src(), - )); - } - Token::Literal(Literal::Float(n)) => self.negate_number( - **n.as_ptr(), - |n, _| -n, - |n, arena| Literal::from(float_alloc!(n, arena)), - ), Token::Literal(c) => { - let atomized = atomize_literal(&self.lexer.machine_st.atom_tbl, c); - - if let Some(name) = atomized { - if !self.shift_op(name, op_dir)? { - self.shift(Token::Literal(c), 0, TERM); + match Number::try_from(c) { + Ok(Number::Integer(n)) => { + self.negate_number(n, negate_int_rc, |n, _| typed_arena_ptr_as_cell!(n)) + } + Ok(Number::Rational(n)) => { + self.negate_number(n, negate_rat_rc, |r, _| typed_arena_ptr_as_cell!(r)) + } + Ok(Number::Float(n)) if n.is_infinite() => { + return Err(ParserError::InfiniteFloat( + self.lexer.loc_to_err_src(), + )); + } + Ok(Number::Float(n)) => { + use ordered_float::OrderedFloat; + + self.negate_number( + n, + |n, _| -n, + |OrderedFloat(n), arena| HeapCellValue::from(float_alloc!(n, arena)), + ) + } + Ok(Number::Fixnum(n)) => { + self.negate_number(n, |n, _| -n, |n, _| fixnum_as_cell!(n)) + } + Err(_) => { + if let Some(name) = c.to_atom() { + if !self.shift_op(name, op_dir)? { + self.shift(Token::Literal(c), 0, TERM); + } + } else { + self.shift(Token::Literal(c), 0, TERM); + } } - } else { - self.shift(Token::Literal(c), 0, TERM); } } Token::Var(v) => self.shift(Token::Var(v), 0, TERM), @@ -1253,7 +1202,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::Close => { if !self.reduce_term() && !self.reduce_brackets() { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } } @@ -1261,7 +1210,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::CloseList => { if !self.reduce_list()? { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } } @@ -1269,7 +1218,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::CloseCurly => { if !self.reduce_curly()? { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } } @@ -1305,7 +1254,7 @@ impl<'a, R: CharRead> Parser<'a, R> { | Some(TokenType::HeadTailSeparator) | Some(TokenType::Comma) => { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )) } _ => {} @@ -1314,10 +1263,16 @@ impl<'a, R: CharRead> Parser<'a, R> { Ok(()) } +} +impl<'a, R: CharRead> LexerParser<'a, R> { #[inline] - pub fn lines_read(&self) -> usize { - self.lexer.line_num + pub fn line_num(&self) -> usize { + self.line_num + } + + pub fn loc_to_err_src(&self) -> ParserErrorSrc { + ParserErrorSrc { line_num: self.line_num, col_num: self.col_num } } // on success, returns the parsed term and the number of lines read. @@ -1325,35 +1280,62 @@ impl<'a, R: CharRead> Parser<'a, R> { &mut self, op_dir: &CompositeOpDir, tokens: Tokens, - ) -> Result { - self.tokens = match tokens { - Tokens::Default => read_tokens(&mut self.lexer)?, - Tokens::Provided(tokens) => tokens, + ) -> Result { + let (tokens, term_byte_size) = match tokens { + Tokens::Default => read_tokens(self)?, + Tokens::Provided(tokens, size) => (tokens, size), }; - while let Some(token) = self.tokens.pop() { - self.shift_token(token, op_dir)?; + // the parser uses conditional indirection in many places so + // the reserved size should be at least 3 * term_byte_size + // so all cells are accounted for. + let writer = match self.machine_st.heap.reserve(cell_index!(3 * term_byte_size)) { + Ok(term) => term, + Err(_err_loc) => { + return Err(ParserError::ResourceError(self.loc_to_err_src())); + } + }; + + let before_len = writer.cell_len(); + + let mut parser_impl = Parser { + tokens, + stack: vec![], + terms: writer, + arena: &mut self.machine_st.arena, + flags: self.machine_st.flags, + line_num: &mut self.line_num, + col_num: &mut self.col_num, + var_locs: VarLocs::default(), + inverse_var_locs: InverseVarLocs::default(), + }; + + while let Some(token) = parser_impl.tokens.pop() { + parser_impl.shift_token(token, op_dir)?; } - self.reduce_op(1400); + parser_impl.reduce_op(1400); - if self.stack.len() > 1 || self.terms.is_empty() { + let after_len = parser_impl.terms.cell_len(); + + debug_assert!(after_len - before_len <= cell_index!(4 * term_byte_size)); + + if parser_impl.stack.len() > 1 || parser_impl.terms.is_empty() { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + parser_impl.loc_to_err_src(), )); } - match self.stack.pop() { + match parser_impl.stack.pop() { Some(TokenDesc { tt: TokenType::Term { heap_loc }, .. - }) => Ok(FocusedHeap { - heap: mem::replace(&mut self.terms, vec![]), + }) => Ok(TermWriteResult { focus: heap_loc.get_value() as usize, - inverse_var_locs: mem::replace(&mut self.inverse_var_locs, InverseVarLocs::default()), + inverse_var_locs: parser_impl.inverse_var_locs, }), _ => Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + parser_impl.loc_to_err_src(), )), } } diff --git a/src/read.rs b/src/read.rs index e2fcfa0c..e0b5d7d9 100644 --- a/src/read.rs +++ b/src/read.rs @@ -3,9 +3,10 @@ use crate::parser::parser::*; use crate::atom_table::*; use crate::machine::machine_errors::*; -use crate::machine::machine_state::{MachineState, copy_and_align_iter}; +use crate::machine::machine_state::MachineState; use crate::machine::streams::*; use crate::parser::char_reader::*; +use crate::parser::lexer::LexerParser; #[cfg(feature = "repl")] use crate::repl_helper::Helper; @@ -22,9 +23,9 @@ use std::io::{Error, ErrorKind}; use std::sync::Arc; pub(crate) fn devour_whitespace( - parser: &mut Parser<'_, R>, + lexer: &mut LexerParser<'_, R>, ) -> Result { - match parser.lexer.scan_for_layout() { + match lexer.scan_for_layout() { Err(e) if e.is_unexpected_eof() => Ok(true), Err(e) => Err(e), Ok(_) => Ok(false), @@ -47,35 +48,17 @@ pub(crate) fn error_after_read_term( CompilationError::from(err) } -impl FocusedHeap { - pub fn to_machine_heap(mut self, machine_st: &mut MachineState) -> TermWriteResult { - let heap_len = machine_st.heap.len(); - machine_st.heap.extend(copy_and_align_iter(self.heap.drain(..), 0, heap_len as i64)); - - let mut inverse_var_locs = InverseVarLocs::default(); - - for (var_loc, var_name) in self.inverse_var_locs.drain(..) { - inverse_var_locs.insert(var_loc + heap_len, var_name); - } - - TermWriteResult { - heap_loc: self.focus + heap_len, - inverse_var_locs, - } - } -} - impl MachineState { pub(crate) fn read( &mut self, inner: R, op_dir: &OpDir, - ) -> Result<(FocusedHeap, usize), ParserError> { - let mut parser = Parser::new(inner, self); + ) -> Result<(TermWriteResult, usize), ParserError> { + let mut lexer_parser = LexerParser::new(inner, self); let op_dir = CompositeOpDir::new(op_dir, None); - let term_result = parser.read_term(&op_dir, Tokens::Default); - let lines_read = parser.lines_read(); + let term_result = lexer_parser.read_term(&op_dir, Tokens::Default); + let lines_read = lexer_parser.line_num(); term_result.map(|term| (term, lines_read)) } @@ -96,7 +79,7 @@ impl MachineState { } }; - Ok(term.to_machine_heap(self)) + Ok(term) } } @@ -305,9 +288,3 @@ impl CharRead for ReadlineStream { self.pending_input.put_back_char(c); } } - -#[derive(Debug)] -pub struct TermWriteResult { - pub heap_loc: usize, - pub inverse_var_locs: InverseVarLocs, -} diff --git a/src/repl_helper.rs b/src/repl_helper.rs index afec4fd2..26199c22 100644 --- a/src/repl_helper.rs +++ b/src/repl_helper.rs @@ -6,7 +6,7 @@ use rustyline::{Context, Helper as RlHelper, Result}; use std::sync::Weak; -use crate::atom_table::{AtomString, AtomTable, STATIC_ATOMS_MAP}; +use crate::atom_table::{AtomString, AtomTable}; //, STATIC_ATOMS_MAP}; // TODO: Maybe add validation to the helper pub struct Helper { @@ -74,7 +74,7 @@ impl Completer for Helper { let mut matching = index_set .iter() - .chain(STATIC_ATOMS_MAP.values()) + // .chain(STATIC_ATOMS_MAP.values()) .map(|a| a.as_str()) .filter(|a| a.starts_with(sub_str)) .collect::>(); diff --git a/src/targets.rs b/src/targets.rs index c2d7cde9..bea12f5c 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -5,22 +5,24 @@ use crate::forms::*; use crate::instructions::*; use crate::types::*; +use std::rc::Rc; + pub(crate) struct FactInstruction; pub(crate) struct QueryInstruction; pub(crate) trait CompilationTarget<'a> { - fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction; + fn to_constant(lvl: Level, cell: HeapCellValue, r: RegType) -> Instruction; fn to_list(lvl: Level, r: RegType) -> Instruction; fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction; fn to_void(num_subterms: usize) -> Instruction; fn is_void_instr(instr: &Instruction) -> bool; - fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction; + fn to_pstr(lvl: Level, string: Rc, r: RegType) -> Instruction; fn incr_void_instr(instr: &mut Instruction); - fn constant_subterm(literal: Literal) -> Instruction; + fn constant_subterm(literal: HeapCellValue) -> Instruction; fn argument_to_variable(r: RegType, r: usize) -> Instruction; fn argument_to_value(r: RegType, val: usize) -> Instruction; @@ -36,8 +38,8 @@ pub(crate) trait CompilationTarget<'a> { } impl<'a> CompilationTarget<'a> for FactInstruction { - fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { - Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg) + fn to_constant(lvl: Level, cell: HeapCellValue, reg: RegType) -> Instruction { + Instruction::GetConstant(lvl, cell, reg) } fn to_structure(lvl: Level, name: Atom, arity: usize, reg: RegType) -> Instruction { @@ -56,8 +58,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { matches!(instr, &Instruction::UnifyVoid(_)) } - fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction { - Instruction::GetPartialString(lvl, string, r, has_tail) + fn to_pstr(lvl: Level, string: Rc, r: RegType) -> Instruction { + Instruction::GetPartialString(lvl, string, r) } fn incr_void_instr(instr: &mut Instruction) { @@ -66,8 +68,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } } - fn constant_subterm(constant: Literal) -> Instruction { - Instruction::UnifyConstant(HeapCellValue::from(constant)) + fn constant_subterm(constant: HeapCellValue) -> Instruction { + Instruction::UnifyConstant(constant) } fn argument_to_variable(arg: RegType, val: usize) -> Instruction { @@ -104,20 +106,20 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } impl<'a> CompilationTarget<'a> for QueryInstruction { - fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction { - Instruction::PutStructure(name, arity, r) + fn to_constant(lvl: Level, constant: HeapCellValue, reg: RegType) -> Instruction { + Instruction::PutConstant(lvl, constant, reg) } - fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { - Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg) + fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction { + Instruction::PutStructure(name, arity, r) } fn to_list(lvl: Level, reg: RegType) -> Instruction { Instruction::PutList(lvl, reg) } - fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction { - Instruction::PutPartialString(lvl, string, r, has_tail) + fn to_pstr(lvl: Level, string: Rc, r: RegType) -> Instruction { + Instruction::PutPartialString(lvl, string, r) } fn to_void(subterms: usize) -> Instruction { @@ -134,8 +136,8 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { } } - fn constant_subterm(constant: Literal) -> Instruction { - Instruction::SetConstant(HeapCellValue::from(constant)) + fn constant_subterm(constant: HeapCellValue) -> Instruction { + Instruction::SetConstant(constant) } fn argument_to_variable(arg: RegType, val: usize) -> Instruction { diff --git a/src/tests/call_with_inference_limit.pl b/src/tests/call_with_inference_limit.pl index 84b78a75..7a093019 100644 --- a/src/tests/call_with_inference_limit.pl +++ b/src/tests/call_with_inference_limit.pl @@ -14,7 +14,7 @@ test_queries_on_call_with_inference_limit :- error, true), \+ call_with_inference_limit(g(X), 5, R), - maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), % TODO this line fails! + maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), findall([R,X], call_with_inference_limit(g(X), 11, R), [[true, 1], diff --git a/src/types.rs b/src/types.rs index d68daac7..47c7b137 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,8 +3,8 @@ use crate::arena::*; use crate::atom_table::*; use crate::forms::*; +use crate::machine::heap::*; use crate::machine::machine_indices::*; -use crate::machine::partial_string::PartialString; use crate::machine::streams::*; use crate::parser::ast::Fixnum; @@ -15,59 +15,64 @@ use std::mem; use std::ops::{Add, Sub, SubAssign}; #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[repr(u8)] #[bits = 6] pub enum HeapCellValueTag { - Str = 0b000011, + Str = 0b000001, Lis = 0b000101, - Var = 0b000111, - StackVar = 0b001001, - AttrVar = 0b001011, - PStrLoc = 0b001101, - PStrOffset = 0b001111, + Var = 0b001011, + StackVar = 0b001101, + AttrVar = 0b010001, + PStrLoc = 0b010011, // constants. Cons = 0b0, - F64 = 0b010001, - Fixnum = 0b010011, - Char = 0b010101, - Atom = 0b010111, - PStr = 0b011001, - CStr = 0b011011, - CutPoint = 0b011111, + F64 = 0b010101, + Fixnum = 0b011001, + // Char = 0b011011, + Atom = 0b011111, + CutPoint = 0b011101, + // trail elements. + TrailedHeapVar = 0b100001, + TrailedStackVar = 0b100011, + TrailedAttrVar = 0b100101, + TrailedAttrVarListLink = 0b101001, + TrailedAttachedValue = 0b101011, + TrailedBlackboardEntry = 0b101101, + TrailedBlackboardOffset = 0b110001, } #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[repr(u8)] #[bits = 6] pub enum HeapCellValueView { - Str = 0b000011, + Str = 0b000001, Lis = 0b000101, - Var = 0b000111, - StackVar = 0b001001, - AttrVar = 0b001011, - PStrLoc = 0b001101, - PStrOffset = 0b001111, + Var = 0b001011, + StackVar = 0b001101, + AttrVar = 0b010001, + PStrLoc = 0b010011, // constants. Cons = 0b0, - F64 = 0b010001, - Fixnum = 0b010011, - Char = 0b010101, - Atom = 0b010111, - PStr = 0b011001, - CStr = 0b011011, - CutPoint = 0b011111, + F64 = 0b010101, + Fixnum = 0b011001, + Char = 0b011011, + Atom = 0b011111, + CutPoint = 0b011101, // trail elements. - TrailedHeapVar = 0b101111, - TrailedStackVar = 0b101011, - TrailedAttrVar = 0b100001, - TrailedAttrVarListLink = 0b100011, - TrailedAttachedValue = 0b100101, - TrailedBlackboardEntry = 0b100111, - TrailedBlackboardOffset = 0b110011, + TrailedHeapVar = 0b100001, + TrailedStackVar = 0b100011, + TrailedAttrVar = 0b100101, + TrailedAttrVarListLink = 0b101001, + TrailedAttachedValue = 0b101011, + TrailedBlackboardEntry = 0b101101, + TrailedBlackboardOffset = 0b110001, } #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[bits = 1] pub enum ConsPtrMaskTag { Cons = 0b0, + Atom = 0b1, } #[bitfield] @@ -105,9 +110,9 @@ impl ConsPtr { #[derive(BitfieldSpecifier, Copy, Clone, Debug)] #[bits = 6] pub(crate) enum RefTag { - HeapCell = 0b000111, - StackCell = 0b001001, - AttrVar = 0b001011, + HeapCell = 0b001011, + StackCell = 0b001101, + AttrVar = 0b010001, } #[bitfield] @@ -245,6 +250,7 @@ pub struct HeapCellValue { val: B56, f: bool, m: bool, + #[allow(dead_code)] tag: HeapCellValueTag, } @@ -279,6 +285,7 @@ impl fmt::Debug for HeapCellValue { .field("f", &self.f()) .finish() } + /* HeapCellValueTag::PStr => { let (name, _) = cell_as_atom_cell!(self).get_name_and_arity(); @@ -289,6 +296,7 @@ impl fmt::Debug for HeapCellValue { .field("f", &self.f()) .finish() } + */ tag => f .debug_struct("HeapCellValue") .field("tag", &tag) @@ -354,19 +362,15 @@ impl HeapCellValue { } #[inline] - pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool { - use crate::machine::heap::*; - + pub fn is_string_terminator(mut self, heap: &impl SizedHeap) -> bool { loop { return read_heap_cell!(self, (HeapCellValueTag::Atom, (name, arity)) => { name == atom!("[]") && arity == 0 } - (HeapCellValueTag::CStr) => { - true - } (HeapCellValueTag::PStrLoc, h) => { - self = heap[h]; + let (_s, tail_loc) = heap.scan_slice_to_str(h); + self = heap[tail_loc]; continue; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { @@ -379,9 +383,6 @@ impl HeapCellValue { self = cell; continue; } - (HeapCellValueTag::PStrOffset, pstr_offset) => { - heap[pstr_offset].get_tag() == HeapCellValueTag::CStr - } _ => { false } @@ -399,16 +400,13 @@ impl HeapCellValue { | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc - | HeapCellValueTag::PStrOffset + // | HeapCellValueTag::PStrOffset ) } #[inline] pub fn as_char(self) -> Option { read_heap_cell!(self, - (HeapCellValueTag::Char, c) => { - Some(c) - } (HeapCellValueTag::Atom, (name, arity)) => { if arity > 0 { return None; @@ -428,9 +426,7 @@ impl HeapCellValue { HeapCellValueTag::Cons | HeapCellValueTag::F64 | HeapCellValueTag::Fixnum - | HeapCellValueTag::CutPoint - | HeapCellValueTag::Char - | HeapCellValueTag::CStr => true, + | HeapCellValueTag::CutPoint => true, HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0, _ => false, } @@ -442,16 +438,12 @@ impl HeapCellValue { } #[inline] - pub fn is_compound(self, heap: &[HeapCellValue]) -> bool { + pub fn is_compound(self, heap: &Heap) -> bool { match self.get_tag() { HeapCellValueTag::Str => { cell_as_atom_cell!(heap[self.get_value() as usize]).get_arity() > 0 } - HeapCellValueTag::Lis - | HeapCellValueTag::CStr - | HeapCellValueTag::PStr - | HeapCellValueTag::PStrLoc - | HeapCellValueTag::PStrOffset => true, + HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => true, HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() > 0, _ => false, } @@ -502,6 +494,7 @@ impl HeapCellValue { match self.tag_or_err() { Ok(tag) => tag, Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() { + ConsPtrMaskTag::Atom => HeapCellValueTag::Atom, ConsPtrMaskTag::Cons => HeapCellValueTag::Cons, }, } @@ -509,16 +502,10 @@ impl HeapCellValue { #[inline] pub fn to_atom(self) -> Option { - match self.tag() { - HeapCellValueTag::Atom => Some(Atom::from(self.val() << 3)), - _ => None, - } - } - - #[inline] - pub fn to_pstr(self) -> Option { - match self.tag() { - HeapCellValueTag::PStr => Some(PartialString::from(Atom::from(self.val() << 3))), + match self.get_tag() { + HeapCellValueTag::Atom => { + Some(AtomCell::from_bytes(self.into_bytes()).get_name()) + } _ => None, } } @@ -593,7 +580,7 @@ impl HeapCellValue { } } - pub fn order_category(self, heap: &[HeapCellValue]) -> Option { + pub fn order_category(self, heap: &Heap) -> Option { match Number::try_from(self).ok() { Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => { Some(TermOrderCategory::Integer) @@ -603,13 +590,14 @@ impl HeapCellValue { HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => { Some(TermOrderCategory::Variable) } - HeapCellValueTag::Char => Some(TermOrderCategory::Atom), + // HeapCellValueTag::Char => Some(TermOrderCategory::Atom), HeapCellValueTag::Atom => Some(if cell_as_atom_cell!(self).get_arity() > 0 { TermOrderCategory::Compound } else { TermOrderCategory::Atom }), - HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr => { + HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => { + // | HeapCellValueTag::CStr => { Some(TermOrderCategory::Compound) } HeapCellValueTag::Str => { @@ -734,12 +722,14 @@ impl Add for HeapCellValue { match self.get_tag() { tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Lis - | tag @ HeapCellValueTag::PStrOffset - | tag @ HeapCellValueTag::PStrLoc | tag @ HeapCellValueTag::Var | tag @ HeapCellValueTag::AttrVar => { HeapCellValue::build_with(tag, (self.get_value() as usize + rhs) as u64) } + tag @ HeapCellValueTag::PStrLoc => { + let value = (self.get_value() as usize + heap_index!(rhs)) as u64; + HeapCellValue::build_with(tag, value) + } _ => self, } } @@ -752,12 +742,14 @@ impl Sub for HeapCellValue { match self.get_tag() { tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Lis - | tag @ HeapCellValueTag::PStrOffset - | tag @ HeapCellValueTag::PStrLoc | tag @ HeapCellValueTag::Var | tag @ HeapCellValueTag::AttrVar => { HeapCellValue::build_with(tag, (self.get_value() as usize - rhs) as u64) } + tag @ HeapCellValueTag::PStrLoc => { + let value = self.get_value() as usize - heap_index!(rhs); + HeapCellValue::build_with(tag, value as u64) + } _ => self, } } @@ -778,12 +770,14 @@ impl Sub for HeapCellValue { match self.get_tag() { tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Lis - | tag @ HeapCellValueTag::PStrOffset - | tag @ HeapCellValueTag::PStrLoc | tag @ HeapCellValueTag::Var | tag @ HeapCellValueTag::AttrVar => { HeapCellValue::build_with(tag, self.get_value() + rhs.unsigned_abs()) } + tag @ HeapCellValueTag::PStrLoc => { + let value = self.get_value() as usize + heap_index!(rhs.unsigned_abs() as usize); + HeapCellValue::build_with(tag, value as u64) + } _ => self, } } else { diff --git a/tests-pl/invalid_decl11.pl b/tests-pl/invalid_decl11.pl index 9d4c6193..d099faff 100644 --- a/tests-pl/invalid_decl11.pl +++ b/tests-pl/invalid_decl11.pl @@ -1 +1 @@ -:- op(10, xf, [example, Var]). \ No newline at end of file +:- op(10, xf, [example, Var]). diff --git a/tests-pl/issue2588.pl b/tests-pl/issue2588.pl index 4e87a39a..dbea342e 100644 --- a/tests-pl/issue2588.pl +++ b/tests-pl/issue2588.pl @@ -2,4 +2,4 @@ test :- load_html("Hello!", Es, []), write(Es). -:- initialization(test). \ No newline at end of file +:- initialization(test). From 79be0c06254b948f02f4a47407a5bf3bac587400 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 31 Oct 2024 22:58:29 -0600 Subject: [PATCH 005/122] unmark_cell_bits! in push_literal (#2645) --- src/arithmetic.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/arithmetic.rs b/src/arithmetic.rs index f1256b66..8cb11743 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -62,6 +62,8 @@ pub(crate) struct ArithmeticEvaluator<'a> { } fn push_literal(interm: &mut Vec, c: HeapCellValue) -> Result<(), ArithmeticError> { + let c = unmark_cell_bits!(c); + read_heap_cell!(c, (HeapCellValueTag::Fixnum, n) => { interm.push(ArithmeticTerm::Number(Number::Fixnum(n))) From c0cd37105624138b60ef555666699b22f7cd4366 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 14 Nov 2024 22:04:09 -0700 Subject: [PATCH 006/122] dereference clause_clause value, reserve more parser space (#2579) --- src/machine/loader.rs | 2 +- src/parser/parser.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 18a4c973..34499ced 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -2462,7 +2462,7 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> { } let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); - let value = machine_st.store(MachineState::deref(&machine_st, machine_st[term_reg])); + let value = machine_st.store(MachineState::deref(machine_st, machine_st[term_reg])); self.add_clause_clause_if_dynamic(value)?; diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 9313e9e9..a9240f22 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1287,9 +1287,9 @@ impl<'a, R: CharRead> LexerParser<'a, R> { }; // the parser uses conditional indirection in many places so - // the reserved size should be at least 3 * term_byte_size + // the reserved size should be at least 4 * term_byte_size // so all cells are accounted for. - let writer = match self.machine_st.heap.reserve(cell_index!(3 * term_byte_size)) { + let writer = match self.machine_st.heap.reserve(cell_index!(4 * term_byte_size)) { Ok(term) => term, Err(_err_loc) => { return Err(ParserError::ResourceError(self.loc_to_err_src())); From 7b357ba84dabdcd424c0c57c3328239c620bc47e Mon Sep 17 00:00:00 2001 From: Emilie Burgun Date: Sun, 29 Dec 2024 22:04:40 +0100 Subject: [PATCH 007/122] Fix Heap::drop not accounting for null-initialized HeapInner --- src/machine/heap.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 5dd33a9b..61614dab 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -24,17 +24,29 @@ pub struct Heap { impl Drop for Heap { fn drop(&mut self) { - unsafe { - let layout = alloc::Layout::array::(self.inner.byte_cap).unwrap(); - alloc::dealloc(self.inner.ptr, layout); + if !self.inner.ptr.is_null() { + unsafe { + let layout = alloc::Layout::array::(self.inner.byte_cap).unwrap(); + alloc::dealloc(self.inner.ptr, layout); + } } } } +// TODO: verify the soundness of the various accesses to `ptr`, +// or rely on a Vec-like library with fallible allocations. #[derive(Debug)] struct InnerHeap { ptr: *mut u8, + + /// # Safety + /// + /// Must be equal to zero when `ptr.is_null()`. byte_len: usize, + + /// # Safety + /// + /// Must be equal to zero when `ptr.is_null()`. byte_cap: usize, } From 15f1320d055e96296046cdf2f82bfcf77d83e093 Mon Sep 17 00:00:00 2001 From: Emilie Burgun Date: Sun, 29 Dec 2024 23:54:03 +0100 Subject: [PATCH 008/122] Fix allocate_pstr randomly refusing to properly allocate memory This one was a toughie: it turns out that using `ptr::align_of()`` was a bad idea, since the buffer in `Heap` itself is not aligned to `Heap::heap_cell_alignment()`, so `ptr::align_of()` would sometimes return lower values than expected. That made for an heisenbug: if the alignment of the heap happened to be 4, then the bug wouldn't trigger. --- src/heap_iter.rs | 17 +++++++++++++++ src/machine/heap.rs | 52 ++++++++++++++++++++++++--------------------- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/heap_iter.rs b/src/heap_iter.rs index 89f39281..62e02f9f 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -2979,6 +2979,19 @@ mod tests { wam.machine_st.heap.clear(); + } + + #[test] + fn heap_stackless_post_order_iter_pstr() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + // clear the heap of resource error data etc + wam.machine_st.heap.clear(); + // first a 'dangling' partial string, later modified to be a // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. @@ -3004,9 +3017,13 @@ mod tests { } wam.machine_st.heap[2] = heap_loc_as_cell!(2); + assert_eq!(wam.machine_st.heap.cell_len(), 3); + wam.machine_st.allocate_pstr("def").unwrap(); + assert_eq!(wam.machine_st.heap.cell_len(), 4); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); + assert_eq!(wam.machine_st.heap.cell_len(), 5); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4); diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 61614dab..cb3cdea8 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -353,15 +353,7 @@ impl<'a> ReservedHeapSection<'a> { let zero_region_idx = heap_index!(self.heap_cell_len) + str_byte_len; - let align_offset = self.heap_ptr - .add(zero_region_idx) - .align_offset(ALIGN_CELL); - - let align_offset = if align_offset == 0 { - ALIGN_CELL - } else { - align_offset - }; + let align_offset = pstr_sentinel_length(zero_region_idx); ptr::write_bytes( self.heap_ptr.add(zero_region_idx), @@ -481,6 +473,22 @@ impl<'a> Index for ReservedHeapSection<'a> { } } +/// Computes the number of bytes required to pad a string of length `chunk_len` +/// with zeroes, such that `chunk_len + pstr_sentinel_length(chunk_len)` is a +/// multiple of `Heap::heap_cell_alignement()`. +fn pstr_sentinel_length(chunk_len: usize) -> usize { + const ALIGN: usize = Heap::heap_cell_alignment(); + + let res = chunk_len.next_multiple_of(ALIGN) - chunk_len; + + // No bytes available in last chunk + if res == 0 { + ALIGN + } else { + res + } +} + #[must_use] #[derive(Debug)] pub struct HeapWriter<'a> { @@ -635,7 +643,7 @@ impl Heap { if self.free_space() >= len { section = ReservedHeapSection { heap_ptr: self.inner.ptr, - heap_cell_len: cell_index!(self.inner.byte_len), + heap_cell_len: self.cell_len(), pstr_vec: &mut self.pstr_vec, }; break; @@ -810,6 +818,11 @@ impl Heap { } } + // SAFETY: + // - Postcondition: from `self.grow()`, `self.inner.byte_len + size_of::()` + // is strictly less than `self.inner.byte_cap`. + // - Asserted: `self.cell_len() * size_of::() <= self.inner.byte_cap`. + // - Invariant: from `InnerHeap`, `self.inner.byte_cap < isize::MAX`. let cell_ptr = (self.inner.ptr as *mut HeapCellValue).add(self.cell_len()); cell_ptr.write(cell); self.pstr_vec.push(false); @@ -967,17 +980,7 @@ impl Heap { const ALIGN_CELL: usize = Heap::heap_cell_alignment(); - let align_offset = unsafe { - self.inner.ptr - .add(self.inner.byte_len + s_len) - .align_offset(ALIGN_CELL) - }; - - let align_offset = if align_offset == 0 { - ALIGN_CELL - } else { - align_offset - }; + let align_offset = pstr_sentinel_length(s_len); let copy_size = s_len + align_offset; @@ -1040,8 +1043,9 @@ impl Heap { Ok(()) } - // assumes the string will be allocated on a ALIGN_CELL-byte boundary - pub(crate) const fn compute_pstr_size(src: &str) -> usize { + /// Returns the number of bytes needed to store `src` as a `PStr`. + /// Assumes the string will be allocated on a ALIGN_CELL-byte boundary. + pub(crate) fn compute_pstr_size(src: &str) -> usize { const ALIGN_CELL: usize = Heap::heap_cell_alignment(); if src.is_empty() { @@ -1062,7 +1066,7 @@ impl Heap { null_idx += 1; } - byte_size += (null_idx & !(ALIGN_CELL - 1)) + ALIGN_CELL; + byte_size += null_idx.next_multiple_of(ALIGN_CELL); if (null_idx + 1) % ALIGN_CELL == 0 { byte_size += 2 * mem::size_of::(); From 3c85ef27245f26bcc90a2d3aae85417892ec2155 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 24 Feb 2025 19:54:35 -0800 Subject: [PATCH 009/122] globalize ALIGN_CELL/ALIGN, fix compute_pstr_size --- src/machine/heap.rs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index cb3cdea8..8f4d4a6c 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -15,6 +15,8 @@ use super::MachineState; use bitvec::prelude::*; use bitvec::slice::BitSlice; +const ALIGN: usize = Heap::heap_cell_alignment(); + #[derive(Debug)] pub struct Heap { inner: InnerHeap, @@ -94,10 +96,9 @@ static RESOURCE_ERROR_OFFSET_INIT: Once = Once::new(); fn scan_slice_to_str(orig_ptr: *const u8, pstr_vec: &BitSlice) -> (&str, usize) { unsafe { debug_assert_eq!(pstr_vec[0], true); - const ALIGN_CELL: usize = Heap::heap_cell_alignment(); let tail_cell_offset = pstr_vec[0..].first_zero().unwrap(); - let offset = (ALIGN_CELL - orig_ptr.align_offset(ALIGN_CELL)) % 8; + let offset = (ALIGN - orig_ptr.align_offset(ALIGN)) % 8; let buf_len = heap_index!(tail_cell_offset) - offset; let slice = std::slice::from_raw_parts(orig_ptr, buf_len); @@ -342,8 +343,6 @@ impl<'a> ReservedHeapSection<'a> { let cells_written; let str_byte_len = src.len(); - const ALIGN_CELL: usize = Heap::heap_cell_alignment(); - unsafe { ptr::copy_nonoverlapping( src.as_ptr(), @@ -477,8 +476,6 @@ impl<'a> Index for ReservedHeapSection<'a> { /// with zeroes, such that `chunk_len + pstr_sentinel_length(chunk_len)` is a /// multiple of `Heap::heap_cell_alignement()`. fn pstr_sentinel_length(chunk_len: usize) -> usize { - const ALIGN: usize = Heap::heap_cell_alignment(); - let res = chunk_len.next_multiple_of(ALIGN) - chunk_len; // No bytes available in last chunk @@ -924,8 +921,7 @@ impl Heap { // takes a byte offset into the Heap ptr. #[inline(always)] pub(crate) const fn neighboring_cell_offset(offset: usize) -> usize { - const ALIGN_CELL: usize = Heap::heap_cell_alignment(); - cell_index!((offset & !(ALIGN_CELL - 1)) + ALIGN_CELL) + cell_index!((offset & !(ALIGN - 1)) + ALIGN) } #[inline] @@ -978,10 +974,7 @@ impl Heap { let (s, tail_loc) = self.scan_slice_to_str(pstr_loc); let s_len = s.len(); - const ALIGN_CELL: usize = Heap::heap_cell_alignment(); - let align_offset = pstr_sentinel_length(s_len); - let copy_size = s_len + align_offset; unsafe { @@ -1044,10 +1037,8 @@ impl Heap { } /// Returns the number of bytes needed to store `src` as a `PStr`. - /// Assumes the string will be allocated on a ALIGN_CELL-byte boundary. + /// Assumes the string will be allocated on a ALIGN-byte boundary. pub(crate) fn compute_pstr_size(src: &str) -> usize { - const ALIGN_CELL: usize = Heap::heap_cell_alignment(); - if src.is_empty() { return 0; } @@ -1066,9 +1057,9 @@ impl Heap { null_idx += 1; } - byte_size += null_idx.next_multiple_of(ALIGN_CELL); + byte_size += null_idx + pstr_sentinel_length(null_idx); - if (null_idx + 1) % ALIGN_CELL == 0 { + if (null_idx + 1) % ALIGN == 0 { byte_size += 2 * mem::size_of::(); } else { byte_size += mem::size_of::(); From ae4d12a12391ed8567dd9ba643a4bc4dffc6d8df Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 6 Dec 2024 21:47:36 -0800 Subject: [PATCH 010/122] remove pstr_vec --- build/static_string_indexing.rs | 30 +- src/arithmetic.rs | 2 - src/atom_table.rs | 21 +- src/codegen.rs | 164 ++++--- src/debray_allocator.rs | 71 ++-- src/forms.rs | 18 +- src/functor_macro.rs | 314 ++++++++++---- src/heap_iter.rs | 159 ++++--- src/heap_print.rs | 95 ++--- src/indexing.rs | 11 +- src/iterators.rs | 56 +-- src/lib/builtins.pl | 1 + src/machine/arithmetic_ops.rs | 5 +- src/machine/attributed_variables.pl | 1 - src/machine/attributed_variables.rs | 4 +- src/machine/compile.rs | 29 +- src/machine/copier.rs | 524 ++++++++++++++++++----- src/machine/cycle_detection.rs | 12 +- src/machine/disjuncts.rs | 62 +-- src/machine/dispatch.rs | 21 +- src/machine/gc.rs | 628 +++++++++++++++------------ src/machine/heap.rs | 637 +++++++++++----------------- src/machine/lib_machine/mod.rs | 9 +- src/machine/loader.rs | 56 +-- src/machine/machine_errors.rs | 94 ++-- src/machine/machine_state.rs | 135 +++--- src/machine/machine_state_impl.rs | 31 +- src/machine/mock_wam.rs | 151 +++---- src/machine/mod.rs | 4 +- src/machine/partial_string.rs | 109 ++++- src/machine/preprocessor.rs | 122 +++--- src/machine/system_calls.rs | 266 +++++------- src/machine/term_stream.rs | 13 +- src/machine/unify.rs | 8 +- src/parser/ast.rs | 44 +- src/parser/lexer.rs | 33 +- src/parser/parser.rs | 185 ++++---- src/read.rs | 2 +- src/types.rs | 14 +- src/variable_records.rs | 12 +- 40 files changed, 2262 insertions(+), 1891 deletions(-) diff --git a/build/static_string_indexing.rs b/build/static_string_indexing.rs index 62e06f46..5135ab77 100644 --- a/build/static_string_indexing.rs +++ b/build/static_string_indexing.rs @@ -89,7 +89,7 @@ const INLINED_ATOM_MAX_LEN: usize = 6; fn static_string_index(string: &str, index: usize) -> u64 { if 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN { let mut string_buf: [u8; 8] = [0u8; 8]; - string_buf[.. string.len()].copy_from_slice(string.as_bytes()); + string_buf[..string.len()].copy_from_slice(string.as_bytes()); (u64::from_le_bytes(string_buf) << 1) | 1 } else { (index << 1) as u64 @@ -165,22 +165,26 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea let mut static_strs = vec![]; let mut static_str_indices = vec![]; - let indices: Vec = visitor.static_strs.iter().map(|string| { - let index = static_string_index(string, static_strs.len()); + let indices: Vec = visitor + .static_strs + .iter() + .map(|string| { + let index = static_string_index(string, static_strs.len()); - static_str_keys.push(string); + static_str_keys.push(string); - if index & 1 == 1 { - index - } else { - static_str_indices.push(index); - static_strs.push(string); - index - } - }).collect(); + if index & 1 == 1 { + index + } else { + static_str_indices.push(index); + static_strs.push(string); + index + } + }) + .collect(); let static_strs_len = static_strs.len(); // visitor.static_strs.len(); - //let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect(); + //let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect(); quote! { static STRINGS: [&str; #static_strs_len] = [ diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 8cb11743..dc03c8db 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -479,7 +479,6 @@ impl Div for Number { } } - impl PartialEq for Number { fn eq(&self, rhs: &Self) -> bool { match (self, rhs) { @@ -563,7 +562,6 @@ impl PartialOrd for Number { } } - impl Ord for Number { fn cmp(&self, rhs: &Number) -> Ordering { match (self, rhs) { diff --git a/src/atom_table.rs b/src/atom_table.rs index 7c23349d..67aaa966 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -66,7 +66,7 @@ impl AtomCell { debug_assert!(string.len() <= INLINED_ATOM_MAX_LEN); let mut string_buf: [u8; 8] = [0u8; 8]; - string_buf[.. string.len()].copy_from_slice(string.as_bytes()); + string_buf[..string.len()].copy_from_slice(string.as_bytes()); let encoding = u64::from_le_bytes(string_buf); AtomCell::new() @@ -80,7 +80,7 @@ impl AtomCell { #[inline] pub fn new_char_inlined(c: char) -> Self { - let mut char_buf = [0u8;8]; + let mut char_buf = [0u8; 8]; c.encode_utf8(&mut char_buf); let encoding = u64::from_le_bytes(char_buf); @@ -109,7 +109,9 @@ impl AtomCell { #[inline] pub fn get_name(self) -> Atom { - Atom { index: (self.name() << 1) | self.is_inlined() as u64 } + Atom { + index: (self.name() << 1) | self.is_inlined() as u64, + } } #[inline] @@ -216,21 +218,22 @@ impl Hash for Atom { pub enum AtomString<'a> { Static(&'a str), - Inlined([u8;8]), + Inlined([u8; 8]), Dynamic(AtomTableRef), } -fn inlined_to_str<'a>(bytes: &'a [u8;8]) -> &'a str { +fn inlined_to_str<'a>(bytes: &'a [u8; 8]) -> &'a str { // allow the '\0\' atom to be represented as the 0-valued inlined atom let slice_len = if bytes[0] == 0 { 1 } else { - bytes.iter().position(|&b| b == 0u8).unwrap_or(INLINED_ATOM_MAX_LEN) + bytes + .iter() + .position(|&b| b == 0u8) + .unwrap_or(INLINED_ATOM_MAX_LEN) }; - unsafe { - str::from_utf8_unchecked(&bytes[..slice_len]) - } + unsafe { str::from_utf8_unchecked(&bytes[..slice_len]) } } impl std::fmt::Debug for AtomString<'_> { diff --git a/src/codegen.rs b/src/codegen.rs index 4b27e448..3118d649 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -295,8 +295,10 @@ impl DebrayAllocator { self.mark_var::(var_num, Level::Shallow, context, code); temp_v!(arg) } else { - if let VarAlloc::Perm { allocation: PermVarAllocation::Pending, .. } = - &self.var_data.records[var_num].allocation + if let VarAlloc::Perm { + allocation: PermVarAllocation::Pending, + .. + } = &self.var_data.records[var_num].allocation { self.mark_var::(var_num, Level::Shallow, context, code); } else { @@ -337,22 +339,16 @@ impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator { fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>( index_ptrs: &IndexMap, heap: &Heap, - arity: usize, heap_loc: usize, ) -> Option { - match fetch_index_ptr(heap, arity, heap_loc) { - Some(index_ptr) => { + if let Some(index_ptr) = index_ptrs.get(&heap_loc) { + let subterm = HeapCellValue::from(*index_ptr); + return Some(Target::constant_subterm(subterm)); + } else if !heap[heap_loc.saturating_sub(1)].get_mark_bit() { + if let Some(index_ptr) = fetch_index_ptr(heap, heap_loc) { let subterm = HeapCellValue::from(index_ptr); return Some(Target::constant_subterm(subterm)); } - None => { - // if Level::Shallow == lvl { - if let Some(index_ptr) = index_ptrs.get(&heap_loc) { - let subterm = HeapCellValue::from(*index_ptr); - return Some(Target::constant_subterm(subterm)); - } - // } - } } None @@ -495,23 +491,28 @@ impl CodeGenerator { 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) { + if let Some(instr) = add_index_ptr::(index_ptrs, &iter, 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); + target.push_back(Target::to_structure(lvl, name, 0, r)); } 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, atom_as_cell!(name), r)); } } else { let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(Target::to_structure(lvl, name, arity, r)); >::add_term_to_free_list( self, r, ); + if let Some(instr) = add_index_ptr::(index_ptrs, &iter, heap_loc) { + target.push_back(instr); + } + + target.push_back(Target::to_structure(lvl, name, arity, 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); @@ -522,10 +523,6 @@ impl CodeGenerator { }) .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 { >::add_subterm_to_free_list( @@ -583,11 +580,11 @@ impl CodeGenerator { 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); - let (pstr_str, tail_loc) = iter.scan_slice_to_str(pstr_loc); + let HeapStringScan { string, tail_idx } = iter.scan_slice_to_str(pstr_loc); - target.push_back(Target::to_pstr(lvl, Rc::new(pstr_str.to_owned()), r)); + target.push_back(Target::to_pstr(lvl, Rc::new(string.to_owned()), r)); - let (tail_loc, tail) = subterm_index(iter.deref(), tail_loc); + let (tail_loc, tail) = subterm_index(iter.deref(), tail_idx); self.subterm_to_instr::( tail, tail_loc, context, index_ptrs, &mut target, ); @@ -676,12 +673,11 @@ impl CodeGenerator { &InlinedClauseType::CompareNumber(mut cmp) => { self.marker.reset_arg(2); - let (mut lcode, at_1) = - if let Some(r) = variable_marker(&mut self.marker) { - (CodeDeque::default(), Some(ArithmeticTerm::Reg(r))) - } else { - self.compile_arith_expr(terms, first_arg_loc, 1, context, 1)? - }; + let (mut lcode, at_1) = if let Some(r) = variable_marker(&mut self.marker) { + (CodeDeque::default(), Some(ArithmeticTerm::Reg(r))) + } else { + self.compile_arith_expr(terms, first_arg_loc, 1, context, 1)? + }; let (mut rcode, at_2) = self.compile_arith_expr(terms, first_arg_loc + 1, 2, context, 2)?; @@ -720,41 +716,41 @@ impl CodeGenerator { if let Some(r) = variable_marker(&mut self.marker) { instr!("atomic", r) } else { - read_heap_cell!(first_arg, - (HeapCellValueTag::Fixnum | - HeapCellValueTag::F64) => { - instr!("$succeed") - } - (HeapCellValueTag::Cons, cons_ptr) => { - match cons_ptr.get_tag() { - ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => { - instr!("$succeed") - } - _ => { - instr!("$fail") - } - } - } - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity == 0 { - instr!("$succeed") - } else { - instr!("$fail") - } - } - (HeapCellValueTag::Lis - | HeapCellValueTag::Str - | HeapCellValueTag::PStrLoc) => { - instr!("$fail") - } - _ => { - if first_arg.is_constant() { - instr!("$succeed") - } else { - instr!("$fail") - } - } - ) + read_heap_cell!(first_arg, + (HeapCellValueTag::Fixnum | + HeapCellValueTag::F64) => { + instr!("$succeed") + } + (HeapCellValueTag::Cons, cons_ptr) => { + match cons_ptr.get_tag() { + ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => { + instr!("$succeed") + } + _ => { + instr!("$fail") + } + } + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + instr!("$succeed") + } else { + instr!("$fail") + } + } + (HeapCellValueTag::Lis + | HeapCellValueTag::Str + | HeapCellValueTag::PStrLoc) => { + instr!("$fail") + } + _ => { + if first_arg.is_constant() { + instr!("$succeed") + } else { + instr!("$fail") + } + } + ) } } InlinedClauseType::IsCompound(..) => { @@ -860,7 +856,7 @@ impl CodeGenerator { } } } - }, + } InlinedClauseType::IsVar(..) => { self.marker.reset_arg(1); @@ -871,7 +867,7 @@ impl CodeGenerator { } else { instr!("$fail") } - }, + } }; // inlined predicates are never counted, so this overrides nothing. @@ -901,8 +897,7 @@ impl CodeGenerator { ) -> Result<(), CompilationError> { macro_rules! compile_expr { ($self:expr, $terms:expr, $context:expr, $code:expr) => {{ - let (acode, at) = - $self.compile_arith_expr($terms, term_loc + 2, 1, $context, 2)?; + let (acode, at) = $self.compile_arith_expr($terms, term_loc + 2, 1, $context, 2)?; $code.extend(acode.into_iter()); at }}; @@ -1067,13 +1062,11 @@ impl CodeGenerator { code.push_back(instr!("deallocate")); } - code.push_back( - if self.marker.in_tail_position { - instr!("$succeed").into_execute() - } else { - instr!("$succeed") - }, - ); + code.push_back(if self.marker.in_tail_position { + instr!("$succeed").into_execute() + } else { + instr!("$succeed") + }); } QueryTerm::Clause(clause) => { self.compile_query_line( @@ -1145,7 +1138,10 @@ impl CodeGenerator { self.marker.var_data = var_data; - let term = FocusedHeapRefMut { heap, focus: *term_loc }; + let term = FocusedHeapRefMut { + heap, + focus: *term_loc, + }; let mut code = VecDeque::new(); let head_loc = term.nth_arg(term.focus, 1).unwrap(); @@ -1216,11 +1212,7 @@ impl CodeGenerator { let mut stack = Stack::uninitialized(); let iter = query_iterator::(&mut term.heap, &mut stack, clause.term_loc()); - let query = self.compile_target::( - iter, - &clause.code_indices, - context, - ); + let query = self.compile_target::(iter, &clause.code_indices, context); code.extend(query); self.add_call(code, clause.ct.to_instr(), clause.call_policy); @@ -1342,20 +1334,14 @@ impl CodeGenerator { skip_stub_try_me_else = !self.settings.is_dynamic(); } - let arg = clause.args(heap) - .map(|r| heap[r.start() + optimal_index]); + let arg = clause.args(heap).map(|r| heap[r.start() + optimal_index]); if let Some(arg) = arg { let index = code.len(); if clauses_len > 1 || self.settings.is_extensible { let arg = heap_bound_store(heap, heap_bound_deref(heap, arg)); - code_offsets.index_term( - heap, - arg, - index, - &mut clause_index_info, - ); + code_offsets.index_term(heap, arg, index, &mut clause_index_info); } } diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index d1d01aa8..7c86bb88 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -172,7 +172,9 @@ 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, @@ -233,7 +235,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, @@ -514,10 +516,12 @@ impl DebrayAllocator { self.perm_free_list.pop_front(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { reg: p, allocation: PermVarAllocation::Pending } - if *p > 0 => { - 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 { @@ -543,11 +547,12 @@ impl DebrayAllocator { match &mut self.var_data.records[var_num].allocation { VarAlloc::Perm { - allocation: PermVarAllocation::Done { - deep_safety, - shallow_safety, - .. - }, + allocation: + PermVarAllocation::Done { + deep_safety, + shallow_safety, + .. + }, .. } => { *deep_safety = VarSafetyStatus::unneeded(branch_designator); @@ -568,11 +573,12 @@ impl DebrayAllocator { match &mut self.var_data.records[var_num].allocation { VarAlloc::Perm { - allocation: PermVarAllocation::Done { - deep_safety, - shallow_safety, - .. - }, + allocation: + PermVarAllocation::Done { + deep_safety, + shallow_safety, + .. + }, .. } => { // GetVariable in head chunk is considered safe. @@ -612,10 +618,11 @@ impl DebrayAllocator { match &mut self.var_data.records[var_num].allocation { VarAlloc::Perm { - allocation: PermVarAllocation::Done { - ref mut shallow_safety, - .. - }, + allocation: + PermVarAllocation::Done { + ref mut shallow_safety, + .. + }, .. } => { if !self.in_tail_position @@ -648,10 +655,11 @@ impl DebrayAllocator { match &mut self.var_data.records[var_num].allocation { VarAlloc::Perm { - allocation: PermVarAllocation::Done { - ref mut deep_safety, - .. - }, + allocation: + PermVarAllocation::Done { + ref mut deep_safety, + .. + }, .. } => { if self @@ -921,10 +929,7 @@ impl Allocator for DebrayAllocator { } fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize) { - let head_cell = heap_bound_store( - heap, - heap_bound_deref(heap, heap_loc_as_cell!(head_loc)), - ); + let head_cell = heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(head_loc))); read_heap_cell!(head_cell, (HeapCellValueTag::Str, s) => { @@ -933,7 +938,9 @@ impl Allocator for DebrayAllocator { self.reset_arg(arity); self.arity = arity; - for (idx, arg) in heap.splice(s+1 ..= s+arity).enumerate() { + for (c_idx, heap_idx) in (s+1 ..= s+arity).enumerate() { + let arg = heap[heap_idx]; + if arg.is_var() { let var = heap_bound_store( heap, @@ -953,11 +960,11 @@ impl Allocator for DebrayAllocator { 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.in_use.insert(c_idx + 1); + self.shallow_temp_mappings.insert(c_idx + 1, var_num); self.var_data.records[var_num] .allocation - .set_register(idx + 1); + .set_register(c_idx + 1); } } VarPtr::Anon => {} diff --git a/src/forms.rs b/src/forms.rs index 4053b5a9..6e9608df 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -1,7 +1,7 @@ use crate::arena::*; use crate::atom_table::*; -use crate::instructions::*; use crate::functor_macro::*; +use crate::instructions::*; use crate::machine::disjuncts::VarData; use crate::machine::heap::*; // use crate::machine::loader::PredicateQueue; @@ -80,8 +80,8 @@ impl GenContext { #[inline] pub fn chunk_type(&self) -> ChunkType { match self { - GenContext::Head => ChunkType::Head, - GenContext::Mid(_) => ChunkType::Mid, + GenContext::Head => ChunkType::Head, + GenContext::Mid(_) => ChunkType::Mid, GenContext::Last(_) => ChunkType::Last, } } @@ -118,7 +118,10 @@ impl ChunkType { #[derive(Debug)] pub enum ChunkedTerms { Branch(Vec>), - Chunk { chunk_num: usize, terms: VecDeque }, + Chunk { + chunk_num: usize, + terms: VecDeque, + }, } #[derive(Debug)] @@ -190,7 +193,8 @@ impl ChunkedTermVec { } pub fn current_gen_context(&self) -> GenContext { - self.current_chunk_type.to_gen_context(self.current_chunk_num) + self.current_chunk_type + .to_gen_context(self.current_chunk_num) } pub fn push_chunk_term(&mut self, term: QueryTerm) { @@ -290,9 +294,7 @@ pub fn clause_predicate_key(heap: &impl SizedHeap, term_loc: usize) -> Option), @@ -190,19 +193,19 @@ pub(crate) fn variadic_functor( let num_items = key_value_pairs.len(); for (idx, _) in key_value_pairs.iter().enumerate() { - arg_vec.push(FunctorElement::Cell(str_loc_as_cell!(2 + num_items * 2 + idx))); + arg_vec.push(FunctorElement::Cell(str_loc_as_cell!( + 2 + num_items * 2 + idx + ))); arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(5 + idx))); } arg_vec.pop(); arg_vec.push(FunctorElement::Cell(empty_list_as_cell!())); - arg_vec.extend(key_value_pairs - .into_iter() - .map(|kv_func| { - let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&kv_func)); - FunctorElement::InnerFunctor(inner_functor_size as u64, kv_func) - })); + arg_vec.extend(key_value_pairs.into_iter().map(|kv_func| { + let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&kv_func)); + FunctorElement::InnerFunctor(inner_functor_size as u64, kv_func) + })); arg_vec } @@ -211,13 +214,15 @@ pub(crate) fn variadic_functor( #[allow(unused_parens)] mod tests { use super::*; - use FunctorElement::*; use std::string::String; + use FunctorElement::*; #[test] fn basic_terms() { - let functor = functor!(atom!("first"), [atom_as_cell((atom!("a"))), - char_as_cell('c')]); + let functor = functor!( + atom!("first"), + [atom_as_cell((atom!("a"))), char_as_cell('c')] + ); assert_eq!(functor.len(), 3); @@ -225,10 +230,14 @@ mod tests { assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a")))); assert_eq!(functor[2], Cell(char_as_cell!('c'))); - let functor = functor!(atom!("second"), [atom_as_cell((atom!("a"))), - functor((atom!("b")), [fixnum(1), - fixnum(2)]), - char_as_cell('c')]); + let functor = functor!( + atom!("second"), + [ + atom_as_cell((atom!("a"))), + functor((atom!("b")), [fixnum(1), fixnum(2)]), + char_as_cell('c') + ] + ); assert_eq!(functor.len(), 5); @@ -236,13 +245,20 @@ mod tests { assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a")))); assert_eq!(functor[2], Cell(str_loc_as_cell!(4))); assert_eq!(functor[3], Cell(char_as_cell!('c'))); - assert_eq!(functor[4], InnerFunctor(3, functor!(atom!("b"), [fixnum(1), - fixnum(2)]))); + assert_eq!( + functor[4], + InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)])) + ); - let functor = functor!(atom!("third"), [atom_as_cell((atom!("a"))), - functor((atom!("b")), [fixnum(1), fixnum(2)]), - functor((atom!("c")), [fixnum(1), fixnum(2)]), - char_as_cell('c')]); + let functor = functor!( + atom!("third"), + [ + atom_as_cell((atom!("a"))), + functor((atom!("b")), [fixnum(1), fixnum(2)]), + functor((atom!("c")), [fixnum(1), fixnum(2)]), + char_as_cell('c') + ] + ); assert_eq!(functor.len(), 7); @@ -251,14 +267,25 @@ mod tests { assert_eq!(functor[2], Cell(str_loc_as_cell!(5))); assert_eq!(functor[3], Cell(str_loc_as_cell!(8))); assert_eq!(functor[4], Cell(char_as_cell!('c'))); - assert_eq!(functor[5], InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))); - assert_eq!(functor[6], InnerFunctor(3, functor!(atom!("c"), [fixnum(1), fixnum(2)]))); + assert_eq!( + functor[5], + InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)])) + ); + assert_eq!( + functor[6], + InnerFunctor(3, functor!(atom!("c"), [fixnum(1), fixnum(2)])) + ); - let functor = functor!(atom!("fourth"), [atom_as_cell((atom!("a"))), - functor((atom!("b")), [fixnum(1), fixnum(2)]), - functor((atom!("c")), [fixnum(1)]), - functor((atom!("d")), [fixnum(453), fixnum(2)]), - char_as_cell('c')]); + let functor = functor!( + atom!("fourth"), + [ + atom_as_cell((atom!("a"))), + functor((atom!("b")), [fixnum(1), fixnum(2)]), + functor((atom!("c")), [fixnum(1)]), + functor((atom!("d")), [fixnum(453), fixnum(2)]), + char_as_cell('c') + ] + ); assert_eq!(functor.len(), 9); @@ -268,14 +295,26 @@ mod tests { assert_eq!(functor[3], Cell(str_loc_as_cell!(9))); assert_eq!(functor[4], Cell(str_loc_as_cell!(11))); assert_eq!(functor[5], Cell(char_as_cell!('c'))); - assert_eq!(functor[6], InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))); - assert_eq!(functor[7], InnerFunctor(2, functor!(atom!("c"), [fixnum(1)]))); - assert_eq!(functor[8], InnerFunctor(3, functor!(atom!("d"), [fixnum(453), fixnum(2)]))); + assert_eq!( + functor[6], + InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)])) + ); + assert_eq!( + functor[7], + InnerFunctor(2, functor!(atom!("c"), [fixnum(1)])) + ); + assert_eq!( + functor[8], + InnerFunctor(3, functor!(atom!("d"), [fixnum(453), fixnum(2)])) + ); } #[test] fn basic_terms_in_heap() { - let functor = functor!(atom!("first"), [atom_as_cell((atom!("a"))), char_as_cell('b')]); + let functor = functor!( + atom!("first"), + [atom_as_cell((atom!("a"))), char_as_cell('b')] + ); assert_eq!(functor.len(), 3); @@ -291,10 +330,15 @@ mod tests { heap.truncate(2); - let functor = functor!(atom!("second"), [atom_as_cell((atom!("a"))), - functor((atom!("b")), [fixnum(1), fixnum(2)]), - functor((atom!("c")), [fixnum(1), fixnum(2)]), - char_as_cell('b')]); + let functor = functor!( + atom!("second"), + [ + atom_as_cell((atom!("a"))), + functor((atom!("b")), [fixnum(1), fixnum(2)]), + functor((atom!("c")), [fixnum(1), fixnum(2)]), + char_as_cell('b') + ] + ); assert_eq!(functor.len(), 7); @@ -318,14 +362,24 @@ mod tests { #[test] fn nested_functors() { - let functor = functor!(atom!("first"), [atom_as_cell((atom!("a"))), - functor((atom!("d")), [fixnum(1), - functor((atom!("b")), - [atom_as_cell((atom!("c"))), - char_as_cell('c')])]), - functor((atom!("e")), [fixnum(453), - fixnum(2)]), - char_as_cell('b')]); + let functor = functor!( + atom!("first"), + [ + atom_as_cell((atom!("a"))), + functor( + (atom!("d")), + [ + fixnum(1), + functor( + (atom!("b")), + [atom_as_cell((atom!("c"))), char_as_cell('c')] + ) + ] + ), + functor((atom!("e")), [fixnum(453), fixnum(2)]), + char_as_cell('b') + ] + ); assert_eq!(functor.len(), 7); @@ -334,24 +388,47 @@ mod tests { assert_eq!(functor[2], Cell(str_loc_as_cell!(5))); assert_eq!(functor[3], Cell(str_loc_as_cell!(11))); assert_eq!(functor[4], Cell(char_as_cell!('b'))); - assert_eq!(functor[5], InnerFunctor(6, vec![Cell(atom_as_cell!(atom!("d"), 2)), - Cell(fixnum_as_cell!(Fixnum::build_with(1))), - Cell(str_loc_as_cell!(3)), - InnerFunctor(3, functor!(atom!("b"), [atom_as_cell((atom!("c"))), - char_as_cell('c')]))])); - assert_eq!(functor[6], InnerFunctor(3, functor!(atom!("e"), [fixnum(453), - fixnum(2)]))); + assert_eq!( + functor[5], + InnerFunctor( + 6, + vec![ + Cell(atom_as_cell!(atom!("d"), 2)), + Cell(fixnum_as_cell!(Fixnum::build_with(1))), + Cell(str_loc_as_cell!(3)), + InnerFunctor( + 3, + functor!(atom!("b"), [atom_as_cell((atom!("c"))), char_as_cell('c')]) + ) + ] + ) + ); + assert_eq!( + functor[6], + InnerFunctor(3, functor!(atom!("e"), [fixnum(453), fixnum(2)])) + ); } - #[test] fn nested_functors_in_heap() { - let functor = functor!(atom!("first"), [atom_as_cell((atom!("a"))), - functor((atom!("second")), [fixnum(1), - functor((atom!("third")), [atom_as_cell((atom!("b"))), - char_as_cell('c')])]), - functor((atom!("fourth")), [fixnum(453), fixnum(2)]), - char_as_cell('b')]); + let functor = functor!( + atom!("first"), + [ + atom_as_cell((atom!("a"))), + functor( + (atom!("second")), + [ + fixnum(1), + functor( + (atom!("third")), + [atom_as_cell((atom!("b"))), char_as_cell('c')] + ) + ] + ), + functor((atom!("fourth")), [fixnum(453), fixnum(2)]), + char_as_cell('b') + ] + ); let mut heap = Heap::new(); let mut functor_writer = Heap::functor_writer(functor); @@ -392,33 +469,43 @@ mod tests { assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1)); assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2))); - assert_eq!(heap.slice_to_str(heap_index!(2), "a string".len()), "a string"); + assert_eq!( + heap.slice_to_str(heap_index!(2), "a string".len()), + "a string" + ); assert_eq!(heap[4], empty_list_as_cell!()); heap.truncate(0); - let functor = functor!(atom!("second"), [string((String::from("a stuttered\0 string")))]); + let functor = functor!( + atom!("second"), + [string((String::from("a stuttered\0 string")))] + ); let mut functor_writer = Heap::functor_writer(functor); functor_writer(&mut heap).unwrap(); - assert_eq!(heap.cell_len(), 7); + assert_eq!(heap.cell_len(), 8); assert_eq!(heap[0], atom_as_cell!(atom!("second"), 1)); assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2))); - assert_eq!(heap.slice_to_str(heap_index!(2), "a stuttered".len()), "a stuttered"); + assert_eq!( + heap.slice_to_str(heap_index!(2), "a stuttered".len()), + "a stuttered" + ); assert_eq!(heap[4], pstr_loc_as_cell!(heap_index!(5))); - assert_eq!(heap.slice_to_str(heap_index!(5), " string".len()), " string"); - assert_eq!(heap[6], empty_list_as_cell!()); + assert_eq!( + heap.slice_to_str(heap_index!(5), " string".len()), + " string" + ); + assert_eq!(heap[7], empty_list_as_cell!()); } #[test] fn functors_with_lists_in_heap() { let functor = functor!( atom!("first"), - [list([fixnum(1), - atom_as_cell((atom!("a"))), - fixnum(2)])] + [list([fixnum(1), atom_as_cell((atom!("a"))), fixnum(2)])] ); assert_eq!(functor.len(), 3); @@ -462,8 +549,10 @@ mod tests { let code_ptr = IndexingCodePtr::Internal(0); let functor = functor!( atom!("first"), - [string((String::from("a string"))), - indexing_code_ptr(code_ptr)] + [ + string((String::from("a string"))), + indexing_code_ptr(code_ptr) + ] ); let mut heap = Heap::new(); @@ -476,18 +565,30 @@ mod tests { assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2)); assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3))); assert_eq!(heap[2], str_loc_as_cell!(6)); - assert_eq!(heap.slice_to_str(heap_index!(3), "a string".len()), "a string"); + assert_eq!( + heap.slice_to_str(heap_index!(3), "a string".len()), + "a string" + ); assert_eq!(heap[5], empty_list_as_cell!()); assert_eq!(heap[6], atom_as_cell!(atom!("internal"), 1)); assert_eq!(heap[7], fixnum_as_cell!(Fixnum::build_with(0))); heap.truncate(0); - let functor = functor!(atom!("second"), - [string((String::from("a string"))), - functor((atom!("third")), [atom_as_cell((atom!("a"))), - string((String::from("another string"))), - indexing_code_ptr(code_ptr)])]); + let functor = functor!( + atom!("second"), + [ + string((String::from("a string"))), + functor( + (atom!("third")), + [ + atom_as_cell((atom!("a"))), + string((String::from("another string"))), + indexing_code_ptr(code_ptr) + ] + ) + ] + ); let mut functor_writer = Heap::functor_writer(functor); functor_writer(&mut heap).unwrap(); @@ -497,24 +598,43 @@ mod tests { assert_eq!(heap[0], atom_as_cell!(atom!("second"), 2)); assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3))); assert_eq!(heap[2], str_loc_as_cell!(6)); - assert_eq!(heap.slice_to_str(heap_index!(3), "a string".len()), "a string"); + assert_eq!( + heap.slice_to_str(heap_index!(3), "a string".len()), + "a string" + ); assert_eq!(heap[5], empty_list_as_cell!()); assert_eq!(heap[6], atom_as_cell!(atom!("third"), 3)); assert_eq!(heap[7], atom_as_cell!(atom!("a"))); assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(10))); assert_eq!(heap[9], str_loc_as_cell!(13)); - assert_eq!(heap.slice_to_str(heap_index!(10), "another string".len()), "another string"); + assert_eq!( + heap.slice_to_str(heap_index!(10), "another string".len()), + "another string" + ); assert_eq!(heap[12], empty_list_as_cell!()); assert_eq!(heap[13], atom_as_cell!(atom!("internal"), 1)); assert_eq!(heap[14], fixnum_as_cell!(Fixnum::build_with(0))); - let functor = functor!(atom!("fourth"), - [string((String::from("a string"))), - functor((atom!("a")), - [functor((atom!("fifth")), [fixnum(5), - string((String::from("another string"))), - indexing_code_ptr(code_ptr)]), - string((String::from("and another")))])]); + let functor = functor!( + atom!("fourth"), + [ + string((String::from("a string"))), + functor( + (atom!("a")), + [ + functor( + (atom!("fifth")), + [ + fixnum(5), + string((String::from("another string"))), + indexing_code_ptr(code_ptr) + ] + ), + string((String::from("and another"))) + ] + ) + ] + ); heap.truncate(0); @@ -526,7 +646,10 @@ mod tests { assert_eq!(heap[0], atom_as_cell!(atom!("fourth"), 2)); assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3))); assert_eq!(heap[2], str_loc_as_cell!(6)); - assert_eq!(heap.slice_to_str(heap_index!(3), "a string".len()), "a string"); + assert_eq!( + heap.slice_to_str(heap_index!(3), "a string".len()), + "a string" + ); assert_eq!(heap[5], empty_list_as_cell!()); assert_eq!(heap[6], atom_as_cell!(atom!("a"), 2)); assert_eq!(heap[7], str_loc_as_cell!(9)); @@ -535,11 +658,17 @@ mod tests { assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(5))); assert_eq!(heap[11], pstr_loc_as_cell!(heap_index!(13))); assert_eq!(heap[12], str_loc_as_cell!(16)); - assert_eq!(heap.slice_to_str(heap_index!(13), "another string".len()), "another string"); + assert_eq!( + heap.slice_to_str(heap_index!(13), "another string".len()), + "another string" + ); assert_eq!(heap[15], empty_list_as_cell!()); assert_eq!(heap[16], atom_as_cell!(atom!("internal"), 1)); assert_eq!(heap[17], fixnum_as_cell!(Fixnum::build_with(0))); - assert_eq!(heap.slice_to_str(heap_index!(18), "and another".len()), "and another"); + assert_eq!( + heap.slice_to_str(heap_index!(18), "and another".len()), + "and another" + ); assert_eq!(heap[20], empty_list_as_cell!()); } @@ -550,17 +679,16 @@ mod tests { let stub = functor!( atom!("existence_error"), - [atom_as_cell((atom!("procedure"))), functor((culprit.clone()))] + [ + atom_as_cell((atom!("procedure"))), + functor((culprit.clone())) + ] ); println!("{:?}", stub); // now the error form - let lineless_error_form = functor!( - atom!("error"), - [functor(stub), - functor(culprit)] - ); + let lineless_error_form = functor!(atom!("error"), [functor(stub), functor(culprit)]); println!("{:?}", lineless_error_form); diff --git a/src/heap_iter.rs b/src/heap_iter.rs index 62e02f9f..fd9b1b0c 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -116,10 +116,10 @@ impl<'a> EagerStackfulPreOrderHeapIter<'a> { } } (HeapCellValueTag::PStrLoc, h) => { - let (_, tail_loc) = self.heap.scan_slice_to_str(h); + let tail_idx = self.heap.scan_slice_to_str(h).tail_idx; - self.heap[tail_loc].set_mark_bit(self.mark_phase); - self.iter_stack.push(self.heap[tail_loc]); + self.heap[tail_idx].set_mark_bit(self.mark_phase); + self.iter_stack.push(self.heap[tail_idx]); } _ => { } @@ -452,12 +452,12 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> } (HeapCellValueTag::PStrLoc, vh) => { let cell = *cell; - let (_, tail_loc) = self.heap.scan_slice_to_str(vh); + let tail_idx = self.heap.scan_slice_to_str(vh).tail_idx; // forward the current PStrLoc cell if the zero // byte at the end of the string buffer // is marked - let buf_bytes = self.heap[tail_loc - 1].into_bytes(); + let buf_bytes = self.heap[tail_idx - 1].into_bytes(); if buf_bytes[7] != 0u8 { let cell = self.read_cell_mut(h); @@ -469,9 +469,9 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> // is never inspected, which it isn't. self.push_if_unmarked( - IterStackLoc::iterable_loc(tail_loc - 1, HeapOrStackTag::Heap), + IterStackLoc::iterable_loc(tail_idx - 1, HeapOrStackTag::Heap), ); - self.stack.push(IterStackLoc::mark_loc(tail_loc, HeapOrStackTag::Heap)); + self.stack.push(IterStackLoc::mark_loc(tail_idx, HeapOrStackTag::Heap)); return Some(cell); } @@ -502,7 +502,6 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> } } - impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a, ElideLists> { type Item = HeapCellValue; @@ -707,9 +706,8 @@ mod tests { let mut functor_writer = Heap::functor_writer(functor!( f_atom, - [atom_as_cell(a_atom), - atom_as_cell(b_atom)]), - ); + [atom_as_cell(a_atom), atom_as_cell(b_atom)] + )); let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); wam.machine_st.heap.push_cell(cell).unwrap(); @@ -733,7 +731,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -758,10 +756,7 @@ mod tests { unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) ); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - str_loc_as_cell!(0) - ); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) @@ -778,7 +773,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -794,7 +789,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -837,7 +832,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); // now make the list cyclic. wam.machine_st.heap[4] = heap_loc_as_cell!(0); @@ -939,8 +934,6 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); - wam.machine_st.heap.clear(); let mut writer = wam.machine_st.heap.reserve(96).unwrap(); @@ -955,9 +948,11 @@ mod tests { let mut functor_writer = Heap::functor_writer(functor!( f_atom, - [atom_as_cell(a_atom), - atom_as_cell(b_atom), - atom_as_cell(b_atom)] + [ + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(b_atom) + ] )); functor_writer(&mut wam.machine_st.heap).unwrap(); @@ -1003,7 +998,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1044,7 +1039,7 @@ mod tests { // instance. } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); @@ -1074,7 +1069,7 @@ mod tests { // instance. } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); @@ -1126,7 +1121,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -1147,7 +1142,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1193,7 +1188,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1427,7 +1422,10 @@ mod tests { wam.machine_st.heap.clear(); { - wam.machine_st.heap.push_cell(fixnum_as_cell!(Fixnum::build_with(0))).unwrap(); + wam.machine_st + .heap + .push_cell(fixnum_as_cell!(Fixnum::build_with(0))) + .unwrap(); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1439,7 +1437,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -1473,7 +1471,7 @@ mod tests { assert!(iter.next().is_none()); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -1504,7 +1502,7 @@ mod tests { assert!(iter.next().is_none()); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -1564,7 +1562,7 @@ mod tests { assert!(iter.next().is_none()); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], str_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(atom!("g"), 2)); @@ -1634,13 +1632,6 @@ mod tests { { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 9); - /* - while let Some(_) = iter.next() { - print_heap_terms(iter.heap.iter(), 0); - println!(""); - } - */ - assert_eq!( unmark_cell_bits!(iter.next().unwrap()), list_loc_as_cell!(7) @@ -1693,9 +1684,8 @@ mod tests { let mut functor_writer = Heap::functor_writer(functor!( f_atom, - [atom_as_cell(a_atom), - atom_as_cell(b_atom)]), - ); + [atom_as_cell(a_atom), atom_as_cell(b_atom)] + )); let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); let h = wam.machine_st.heap.cell_len(); @@ -1924,7 +1914,7 @@ mod tests { ); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -2021,7 +2011,11 @@ mod tests { let functor = functor!( f_atom, - [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)] + [ + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(b_atom) + ] ); let mut writer = wam.machine_st.heap.reserve(96).unwrap(); @@ -2098,7 +2092,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -2163,7 +2157,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -2202,7 +2196,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -2221,18 +2215,18 @@ mod tests { 2, ); - assert_eq!( - iter.heap.slice_to_str(0, "a string".len()), - "a string" - ); - assert_eq!( - iter.next().unwrap(), - empty_list_as_cell!() - ); + assert_eq!(iter.heap.slice_to_str(0, "a string".len()), "a string"); + assert_eq!(iter.next().unwrap(), empty_list_as_cell!()); assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + assert_eq!(wam.machine_st.heap.slice_to_str(0, "a string".len()), "a string"); + assert_eq!(wam.machine_st.heap[1], HeapCellValue::build_with(HeapCellValueTag::Cons, 0)); + + for idx in 2 ..= 3 { + assert!(!wam.machine_st.heap[idx].get_mark_bit()); + assert!(!wam.machine_st.heap[idx].get_forwarding_bit()); + } wam.machine_st.heap.clear(); @@ -2291,9 +2285,8 @@ mod tests { let mut functor_writer = Heap::functor_writer(functor!( f_atom, - [atom_as_cell(a_atom), - atom_as_cell(b_atom)]), - ); + [atom_as_cell(a_atom), atom_as_cell(b_atom)] + )); let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); let h = wam.machine_st.heap.cell_len(); @@ -2325,7 +2318,6 @@ mod tests { wam.machine_st.heap.clear(); - let mut functor_writer = Heap::functor_writer(functor!( f_atom, [ @@ -2361,10 +2353,7 @@ mod tests { unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - str_loc_as_cell!(0) - ); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) @@ -2519,7 +2508,7 @@ mod tests { ); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -2616,7 +2605,11 @@ mod tests { let functor = functor!( f_atom, - [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)] + [ + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(b_atom) + ] ); let mut writer = wam.machine_st.heap.reserve(96).unwrap(); @@ -2694,7 +2687,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -2761,7 +2754,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); } @@ -2778,9 +2771,8 @@ mod tests { let mut functor_writer = Heap::functor_writer(functor!( f_atom, - [atom_as_cell(a_atom), - atom_as_cell(b_atom)]), - ); + [atom_as_cell(a_atom), atom_as_cell(b_atom)] + )); let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); wam.machine_st.heap.push_cell(cell).unwrap(); @@ -2969,7 +2961,7 @@ mod tests { ); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -3039,7 +3031,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2); @@ -3053,11 +3045,18 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); - let functor = functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)]); + let functor = functor!( + f_atom, + [ + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(b_atom) + ] + ); let mut writer = wam.machine_st.heap.reserve(96).unwrap(); @@ -3116,7 +3115,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -3164,6 +3163,6 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 2bc1706b..cdd166c8 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -486,7 +486,12 @@ pub struct HCPrinter<'a, Outputter> { pub double_quotes: bool, } -fn ambiguity_check(outputter: &impl HCValueOutputter, quoted: bool, last_item_idx: usize, atom: &str) -> bool { +fn ambiguity_check( + outputter: &impl HCValueOutputter, + quoted: bool, + last_item_idx: usize, + atom: &str, +) -> bool { let tail = &outputter.as_str()[last_item_idx..]; if atom == "," || !quoted || non_quoted_token(atom.chars()) { @@ -1132,7 +1137,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } macro_rules! emit_char { - ($c:expr) => ({ + ($c:expr) => {{ append_str!(self, "'.'"); push_char!(self, '('); @@ -1141,14 +1146,17 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::Close); char_count += 1; - }); + }}; } match iteratee { PStrIteratee::Char { value, .. } => { emit_char!(value); } - PStrIteratee::PStrSlice { slice_loc, slice_len } => { + PStrIteratee::PStrSlice { + slice_loc, + slice_len, + } => { let s = iter.heap.slice_to_str(slice_loc, slice_len); for c in s.chars() { @@ -1181,10 +1189,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if max_depth == 0 { while let Some(iteratee) = iter.next() { let iter: Box> = match iteratee { - PStrIteratee::Char { value: c, .. } => { - Box::new(std::iter::once(c)) - } - PStrIteratee::PStrSlice { slice_loc, slice_len } => { + PStrIteratee::Char { value: c, .. } => Box::new(std::iter::once(c)), + PStrIteratee::PStrSlice { + slice_loc, + slice_len, + } => { let s = iter.heap.slice_to_str(slice_loc, slice_len); Box::new(s.chars()) } @@ -1201,10 +1210,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { while let Some(iteratee) = iter.next() { let iter: Box> = match iteratee { - PStrIteratee::Char { value: c, .. } => { - Box::new(std::iter::once(c)) - } - PStrIteratee::PStrSlice { slice_loc, slice_len } => { + PStrIteratee::Char { value: c, .. } => Box::new(std::iter::once(c)), + PStrIteratee::PStrSlice { + slice_loc, + slice_len, + } => { let s = iter.heap.slice_to_str(slice_loc, slice_len); Box::new(s.chars()) } @@ -1583,22 +1593,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } else { - /* - let end_cell_h = Heap::neighboring_cell_offset(pstr_loc); - let end_cell = self.iter.heap[end_cell_h]; - let end_cell = heap_bound_store( - self.iter.heap, - heap_bound_deref(self.iter.heap, end_cell), - ); - - if end_cell != empty_list_as_cell!() { - self.iter.push_stack( - IterStackLoc::iterable_loc(end_cell_h, HeapOrStackTag::Heap), - ); - } - */ - - self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); + self.state_stack + .push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } } @@ -1872,9 +1868,8 @@ mod tests { let mut functor_writer = Heap::functor_writer(functor!( f_atom, - [atom_as_cell(a_atom), - atom_as_cell(b_atom)]), - ); + [atom_as_cell(a_atom), atom_as_cell(b_atom)] + )); let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); wam.machine_st.heap.push_cell(cell).unwrap(); @@ -1893,7 +1888,7 @@ mod tests { assert_eq!(output.result(), "f(a,b)"); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -1925,7 +1920,7 @@ mod tests { assert_eq!(output.result(), "f(a,b,a,...)"); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -1968,7 +1963,7 @@ mod tests { assert_eq!(output.result(), "[L|L]"); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -1984,9 +1979,11 @@ mod tests { let mut functor_writer = Heap::functor_writer(functor!( f_atom, - [atom_as_cell(a_atom), - atom_as_cell(b_atom), - atom_as_cell(b_atom)] + [ + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(b_atom) + ] )); functor_writer(&mut wam.machine_st.heap).unwrap(); @@ -2005,7 +2002,7 @@ mod tests { assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)]"); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -2023,7 +2020,7 @@ mod tests { assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|...]"); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); { let mut printer = HCPrinter::new( @@ -2043,7 +2040,7 @@ mod tests { assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|L]"); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); // issue #382 wam.machine_st.heap.clear(); @@ -2077,7 +2074,7 @@ mod tests { assert_eq!(output.result(), "[_1,_3,_5,_7,_9|...]"); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -2100,7 +2097,7 @@ mod tests { assert_eq!(output.result(), "[a,b,c|_1]"); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); let mut writer = wam.machine_st.heap.reserve(96).unwrap(); @@ -2131,7 +2128,7 @@ mod tests { assert_eq!(output.result(), "\"abcabc\""); } - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.machine_st.heap.clear(); @@ -2140,14 +2137,14 @@ mod tests { "=(X,[a,b,c|X])" ); - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!( &wam.parse_and_print_term("[a,b,\"a\",[a,b,c]].").unwrap(), "[a,b,[a],[a,b,c]]" ); - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!( &wam.parse_and_print_term("[\"abc\",e,f,[g,e,h,Y,v|[X,Y]]].") @@ -2155,11 +2152,11 @@ mod tests { "[[a,b,c],e,f,[g,e,h,Y,v,X,Y]]" ); - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!(&wam.parse_and_print_term("f((a,b)).").unwrap(), "f((a,b))"); - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.op_dir .insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX)); @@ -2171,14 +2168,14 @@ mod tests { "[a|[]+b]" ); - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); assert_eq!( &wam.parse_and_print_term("[a|[b|c]*d].").unwrap(), "[a|[b|c]*d]" ); - all_cells_unmarked(wam.machine_st.heap.splice(..)); + all_cells_unmarked(&wam.machine_st.heap); wam.op_dir .insert((atom!("fy"), Fixity::Pre), OpDesc::build_with(9, FY)); diff --git a/src/indexing.rs b/src/indexing.rs index d9a4f036..344155d8 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1110,12 +1110,11 @@ pub(crate) fn constant_key_alternatives( constants.push( Fixnum::build_with_checked(value) .map(|n| fixnum_as_cell!(n)) - .unwrap() + .unwrap(), ); } } - _ => { - } + _ => {} } /* @@ -1465,11 +1464,7 @@ impl CodeOffsets { self.indices.lists().push_back(index); } - fn index_constant( - &mut self, - constant: HeapCellValue, - index: usize, - ) -> Vec { + fn index_constant(&mut self, constant: HeapCellValue, index: usize) -> Vec { let overlapping_constants = constant_key_alternatives(constant); let code = self.indices.constants().entry(constant).or_default(); diff --git a/src/iterators.rs b/src/iterators.rs index b641c756..1de7541b 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -14,7 +14,9 @@ use std::iter::*; use std::ops::Deref; use std::vec::Vec; -pub(crate) trait TermIterator: Deref + Iterator { +pub(crate) trait TermIterator: + Deref + Iterator +{ fn focus(&self) -> IterStackLoc; fn level(&mut self) -> Level; } @@ -45,9 +47,9 @@ fn record_path( } } (HeapCellValueTag::Lis) => { - root_terms.insert(root_loc); - break; - } + root_terms.insert(root_loc); + break; + } _ => { if cell.is_ref() { root_terms.insert(cell.get_value() as usize); @@ -228,7 +230,10 @@ pub(crate) enum ClauseItem<'a> { FirstBranch(usize), NextBranch, BranchEnd(usize), - Chunk { chunk_num: usize, terms: &'a VecDeque }, + Chunk { + chunk_num: usize, + terms: &'a VecDeque, + }, } #[derive(Debug)] @@ -271,10 +276,9 @@ impl<'a> ClauseIterator<'a> { while let Some(state) = self.state_stack.pop() { match state { - ClauseIteratorState::RemainingBranches(terms, focus) - if terms.len() == focus => { - depth += 1; - } + ClauseIteratorState::RemainingBranches(terms, focus) if terms.len() == focus => { + depth += 1; + } _ => { self.state_stack.push(state); break; @@ -292,25 +296,27 @@ impl<'a> Iterator for ClauseIterator<'a> { fn next(&mut self) -> Option { while let Some(state) = self.state_stack.pop() { match state { - ClauseIteratorState::RemainingChunks(chunks, focus) - if focus < chunks.len() => { - if focus + 1 < chunks.len() { - self.state_stack - .push(ClauseIteratorState::RemainingChunks(chunks, focus + 1)); - } else { - self.remaining_chunks_on_stack -= 1; - } + ClauseIteratorState::RemainingChunks(chunks, focus) if focus < chunks.len() => { + if focus + 1 < chunks.len() { + self.state_stack + .push(ClauseIteratorState::RemainingChunks(chunks, focus + 1)); + } else { + self.remaining_chunks_on_stack -= 1; + } - match &chunks[focus] { - ChunkedTerms::Branch(branches) => { - self.state_stack - .push(ClauseIteratorState::RemainingBranches(branches, 0)); - } - &ChunkedTerms::Chunk { chunk_num, ref terms } => { - return Some(ClauseItem::Chunk { chunk_num, terms }); - } + match &chunks[focus] { + ChunkedTerms::Branch(branches) => { + self.state_stack + .push(ClauseIteratorState::RemainingBranches(branches, 0)); + } + &ChunkedTerms::Chunk { + chunk_num, + ref terms, + } => { + return Some(ClauseItem::Chunk { chunk_num, terms }); } } + } ClauseIteratorState::RemainingChunks(chunks, focus) => { debug_assert_eq!(chunks.len(), focus); } diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index bc78b711..31b40a3a 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -568,6 +568,7 @@ parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :- % maplist isn't % declared as a % meta-predicate yet + '$debug_hook', catch(lists:maplist(Selector, Options, OptionPairs0), error(E, _), builtins:throw(error(E, Stub))) -> diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index a779411d..86470097 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1165,9 +1165,8 @@ impl MachineState { return Err(self.error_form(type_error, stub_gen())); }; - let mut iter = stackful_post_order_iter::( - &mut self.heap, &mut self.stack, root_loc, - ); + 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.pl b/src/machine/attributed_variables.pl index 584abc80..c288511b 100644 --- a/src/machine/attributed_variables.pl +++ b/src/machine/attributed_variables.pl @@ -38,7 +38,6 @@ verify_attrs([], _, _, []). call_goals([ListOfGoalLists | ListsCubed]) :- - '$debug_hook', call_goals_0(ListOfGoalLists), call_goals(ListsCubed). call_goals([]). diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 6b5ae9b3..368152f5 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -145,7 +145,9 @@ impl MachineState { }; let mut iter = stackful_preorder_iter::( - &mut self.heap, &mut self.stack, root_loc, // cell, + &mut self.heap, + &mut self.stack, + root_loc, // cell, ); while let Some(value) = iter.next() { diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 71beaa47..84b89c39 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -2102,19 +2102,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> { - let key = match self - .payload - .predicates - .first() - .map(|term| term.focus) { - Some(focus) => { - clause_predicate_key(self.machine_heap(), focus) - .ok_or(SessionError::NamelessEntry)? - } - None => { - return Err(SessionError::NamelessEntry); - } - }; + let key = match self.payload.predicates.first().map(|term| term.focus) { + Some(focus) => clause_predicate_key(self.machine_heap(), focus) + .ok_or(SessionError::NamelessEntry)?, + None => { + return Err(SessionError::NamelessEntry); + } + }; let listing_src_file_name = self.listing_src_file_name(); @@ -2290,13 +2284,18 @@ impl Machine { term_reg: RegType, vars: Vec, ) -> Result<(), SessionError> { - let body_cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg])); + let body_cell = self + .machine_st + .store(self.machine_st.deref(self.machine_st[term_reg])); let new_header_loc = self.machine_st.heap.cell_len(); let arity = vars.len(); let term_loc = self.machine_st.heap.cell_len() + 1 + arity; - let mut writer = self.machine_st.heap.reserve(4 + arity) + let mut writer = self + .machine_st + .heap + .reserve(4 + arity) .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; writer.write_with(move |section| { diff --git a/src/machine/copier.rs b/src/machine/copier.rs index 5bb2fe90..57e034af 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -1,13 +1,71 @@ +use fxhash::FxBuildHasher; +use indexmap::IndexSet; + use crate::atom_table::*; use crate::machine::get_structure_index; use crate::machine::heap::*; use crate::machine::stack::*; use crate::types::*; +use scryer_modular_bitfield::specifiers::*; +use scryer_modular_bitfield::*; + +use std::collections::BTreeMap; use std::mem; use std::ops::{IndexMut, Range}; -type Trail = Vec<(Ref, HeapCellValue)>; +#[derive(BitfieldSpecifier, Copy, Clone, Debug)] +#[bits = 6] +enum TrailRefTag { + HeapCell = 0b001011, + StackCell = 0b001101, + AttrVar = 0b010001, + PStrLoc = 0b001111, +} + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +struct TrailRef { + val: B56, + #[allow(unused)] + m: bool, + #[allow(unused)] + f: bool, + tag: TrailRefTag, +} + +impl TrailRef { + #[inline(always)] + fn heap_cell(h: usize) -> Self { + TrailRef::new() + .with_tag(TrailRefTag::HeapCell) + .with_val(h as u64) + } + + #[inline(always)] + fn stack_cell(h: usize) -> Self { + TrailRef::new() + .with_tag(TrailRefTag::StackCell) + .with_val(h as u64) + } + + #[inline(always)] + fn attr_var(h: usize) -> Self { + TrailRef::new() + .with_tag(TrailRefTag::AttrVar) + .with_val(h as u64) + } + + #[inline(always)] + fn pstr_loc(h: usize) -> Self { + TrailRef::new() + .with_tag(TrailRefTag::PStrLoc) + .with_val(h as u64) + } +} + +type Trail = Vec<(TrailRef, HeapCellValue)>; #[derive(Debug, Clone, Copy)] pub enum AttrVarPolicy { @@ -18,15 +76,12 @@ pub enum AttrVarPolicy { pub trait CopierTarget: IndexMut { fn store(&self, value: HeapCellValue) -> HeapCellValue; fn deref(&self, value: HeapCellValue) -> HeapCellValue; - // fn push_cell(&mut self, value: HeapCellValue) -> Result<(), usize>; fn push_attr_var_queue(&mut self, attr_var_loc: usize); fn stack(&mut self) -> &mut Stack; fn threshold(&self) -> usize; // returns the tail location of the pstr on success + fn as_slice_from<'a>(&'a self, from: usize) -> Box + 'a>; fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result; - fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize; - fn pstr_at(&self, loc: usize) -> bool; - fn next_non_pstr_cell_index(&self, loc: usize) -> usize; fn reserve(&mut self, num_cells: usize) -> Result; fn copy_slice_to_end(&mut self, bounds: Range) -> Result<(), usize>; } @@ -35,14 +90,25 @@ pub(crate) fn copy_term( target: T, addr: HeapCellValue, attr_var_policy: AttrVarPolicy, -) -> Result<(), usize> { +) -> Result { let mut copy_term_state = CopyTermState::new(target, attr_var_policy); + let old_threshold = copy_term_state.target.threshold(); copy_term_state.copy_term_impl(addr)?; copy_term_state.copy_attr_var_lists()?; copy_term_state.unwind_trail(); - Ok(()) + let new_threshold = copy_term_state.target.threshold(); + copy_term_state.copy_pstrs()?; + + Ok(new_threshold - old_threshold) +} + +#[derive(Debug)] +pub struct PStrData { + pre_old_h_tail_loc: usize, + post_old_h_tail_loc: usize, + post_old_h_pstr_loc_locs: IndexSet, } #[derive(Debug)] @@ -53,6 +119,9 @@ struct CopyTermState { target: T, attr_var_policy: AttrVarPolicy, attr_var_list_locs: Vec<(usize, HeapCellValue)>, + // keys of pstr_loc_locs are byte indices rounded down to the + // nearest cell boundary + pstr_loc_locs: BTreeMap, } impl CopyTermState { @@ -64,6 +133,7 @@ impl CopyTermState { target, attr_var_policy, attr_var_list_locs: vec![], + pstr_loc_locs: BTreeMap::new(), } } @@ -74,7 +144,7 @@ impl CopyTermState { fn trail_list_cell(&mut self, addr: usize, threshold: usize) { let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold)); - self.trail.push((Ref::heap_cell(addr), trail_item)); + self.trail.push((TrailRef::heap_cell(addr), trail_item)); } fn copy_list(&mut self, addr: usize) -> Result<(), usize> { @@ -93,7 +163,7 @@ impl CopyTermState { } let threshold = self.target.threshold(); - self.target.copy_slice_to_end(addr .. addr + 2)?; + self.target.copy_slice_to_end(addr..addr + 2)?; *self.value_at_scan() = list_loc_as_cell!(threshold); @@ -122,54 +192,90 @@ impl CopyTermState { Ok(()) } - /* - * write a null byte to the first word of a partial string to - * flag that it has been copied followed by the copied - * string's index in the next 7 bytes. write the bytes in big - * endian order so that the null byte is at index 0. - */ - fn write_pstr_index(&mut self, head_cell_idx: usize, threshold: usize) { - let bytes = u64::to_be_bytes(threshold as u64); - debug_assert_eq!(bytes[0], 0); - self.target[head_cell_idx] = HeapCellValue::from_bytes(bytes); - } - fn copy_partial_string(&mut self, pstr_loc: usize) -> Result<(), usize> { - let head_cell_idx = self.target.pstr_head_cell_index(pstr_loc); - let head_byte_idx = heap_index!(head_cell_idx); - let pstr_offset = pstr_loc - head_byte_idx; - - // if a partial string has been copied previously, we - // track it by writing a null byte to its first word, which is trailed, - // and then the new pstr_loc in the word's remaining 7 bytes. see write_pstr_index - // comment. - - if self.target[head_cell_idx].into_bytes()[0] == 0u8 { - let head_bytes = self.target[head_cell_idx].into_bytes(); - let new_pstr_loc = u64::from_be_bytes(head_bytes) as usize; - - *self.value_at_scan() = pstr_loc_as_cell!(heap_index!(new_pstr_loc) + pstr_offset); - self.scan += 1; - return Ok(()); + match self.pstr_loc_locs.range_mut(..=pstr_loc).next_back() { + Some(( + _prev_pstr_loc, + &mut PStrData { + pre_old_h_tail_loc, + ref mut post_old_h_pstr_loc_locs, + .. + }, + )) if pre_old_h_tail_loc >= cell_index!(pstr_loc) => { + post_old_h_pstr_loc_locs.insert(self.scan); + self.scan += 1; + return Ok(()); + } + _ => {} } - let threshold = self.target.threshold(); - let tail_loc = self.target.copy_pstr_to_threshold(head_byte_idx)?; + let offset = self + .target + .as_slice_from(pstr_loc) + .take_while(|b| *b != 0u8) + .count(); - *self.value_at_scan() = pstr_loc_as_cell!(heap_index!(threshold) + pstr_offset); + let left_pstr_boundary = cell_index!(pstr_loc + offset); + let flag = u64::from_be_bytes(self.target[left_pstr_boundary].into_bytes()); + let pstr_loc_idx = cell_index!(pstr_loc); - self.trail.push((Ref::heap_cell(head_cell_idx), self.target[head_cell_idx])); - self.write_pstr_index(head_cell_idx, threshold); + if flag == 1 { + if left_pstr_boundary != pstr_loc_idx { + let mut pstr_data = self + .pstr_loc_locs + .remove(&heap_index!(left_pstr_boundary)) + .unwrap(); - let tail_cell = self.target[tail_loc]; - let mut writer = self.target.reserve(1)?; + pstr_data.post_old_h_pstr_loc_locs.insert(self.scan); + self.pstr_loc_locs + .insert(heap_index!(cell_index!(pstr_loc)), pstr_data); - writer.write_with(|section| { - section.push_cell(tail_cell); - }); + let old_cell = self.target[pstr_loc_idx]; + self.target[pstr_loc_idx] = HeapCellValue::from_bytes(u64::to_be_bytes(1)); + self.trail + .push((TrailRef::pstr_loc(pstr_loc_idx), old_cell)); + } else { + let pstr_data = self + .pstr_loc_locs + .get_mut(&heap_index!(left_pstr_boundary)) + .unwrap(); + pstr_data.post_old_h_pstr_loc_locs.insert(self.scan); + } + } else { + let old_cell = self.target[pstr_loc_idx]; + self.target[pstr_loc_idx] = HeapCellValue::from_bytes(u64::to_be_bytes(1)); + self.trail + .push((TrailRef::pstr_loc(pstr_loc_idx), old_cell)); + + let old_tail_idx = if (pstr_loc + offset + 1) % Heap::heap_cell_alignment() == 0 { + cell_index!(pstr_loc + offset) + 2 + } else { + cell_index!(pstr_loc + offset) + 1 + }; + + let tail_cell = self.target[old_tail_idx]; + + let new_tail_idx = self.target.threshold(); + let mut writer = self.target.reserve(1)?; + + writer.write_with(|section| { + section.push_cell(tail_cell); + }); + + let mut post_old_h_pstr_loc_locs = IndexSet::with_hasher(FxBuildHasher::default()); + post_old_h_pstr_loc_locs.insert(self.scan); + + let pstr_data = PStrData { + pre_old_h_tail_loc: old_tail_idx, + post_old_h_tail_loc: new_tail_idx, + post_old_h_pstr_loc_locs, + }; + + self.pstr_loc_locs + .insert(heap_index!(pstr_loc_idx), pstr_data); + } self.scan += 1; - Ok(()) } @@ -210,6 +316,7 @@ impl CopyTermState { }); debug_assert_eq!(str_cell.get_tag(), HeapCellValueTag::Str); + self.copy_term_impl(str_cell)?; list_addr = self.target[heap_loc + 1]; @@ -227,13 +334,13 @@ impl CopyTermState { self.target[frontier] = heap_loc_as_cell!(frontier); self.target[h] = heap_loc_as_cell!(frontier); - self.trail.push((Ref::heap_cell(h), heap_loc_as_cell!(h))); + self.trail.push((TrailRef::heap_cell(h), heap_loc_as_cell!(h))); } (HeapCellValueTag::StackVar, s) => { self.target[frontier] = heap_loc_as_cell!(frontier); self.target.stack()[s] = heap_loc_as_cell!(frontier); - self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s))); + self.trail.push((TrailRef::stack_cell(s), stack_loc_as_cell!(s))); } (HeapCellValueTag::AttrVar, h) => { let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy { @@ -245,10 +352,10 @@ impl CopyTermState { self.target[frontier] = heap_loc_as_cell!(threshold); self.target[h] = heap_loc_as_cell!(threshold); - self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h))); + self.trail.push((TrailRef::attr_var(h), attr_var_as_cell!(h))); if let AttrVarPolicy::DeepCopy = self.attr_var_policy { - let mut writer = self.target.reserve(2).unwrap(); + let mut writer = self.target.reserve(2)?; writer.write_with(|section| { section.push_cell(attr_var_as_cell!(threshold)); @@ -256,7 +363,7 @@ impl CopyTermState { }); let old_list_link = self.target[h + 1]; - self.trail.push((Ref::heap_cell(h + 1), old_list_link)); + self.trail.push((TrailRef::heap_cell(h + 1), old_list_link)); self.target[h + 1] = heap_loc_as_cell!(threshold + 1); if old_list_link.get_tag() == HeapCellValueTag::Lis { @@ -317,7 +424,21 @@ impl CopyTermState { (HeapCellValueTag::Atom, (_name, arity)) => { let threshold = self.target.threshold(); - *self.value_at_scan() = str_loc_as_cell!(threshold); + let index_cell = self.target[addr.saturating_sub(1)]; + + *self.value_at_scan() = if get_structure_index(index_cell).is_some() { + // copy the index pointer trailing this + // inlined or expanded goal. + let mut writer = self.target.reserve(1).unwrap(); + + writer.write_with(|section| { + section.push_cell(index_cell); + }); + + str_loc_as_cell!(threshold + 1) + } else { + str_loc_as_cell!(threshold) + }; self.target.copy_slice_to_end(addr .. addr + 1 + arity)?; @@ -326,28 +447,7 @@ impl CopyTermState { str_loc_as_cell!(threshold), ); - self.trail.push((Ref::heap_cell(addr), trail_item)); -/* - self.target.push(atom_as_cell!(name, arity)); - - for i in 0..arity { - let hcv = self.target[addr + 1 + i]; - self.target.push(hcv); - } -*/ - if !self.target.pstr_at(addr + 1 + arity) { - let index_cell = self.target[addr + 1 + arity]; - - if get_structure_index(index_cell).is_some() { - // copy the index pointer trailing this - // inlined or expanded goal. - let mut writer = self.target.reserve(1).unwrap(); - - writer.write_with(|section| { - section.push_cell(index_cell); - }); - } - } + self.trail.push((TrailRef::heap_cell(addr), trail_item)); } (HeapCellValueTag::Str, h) => { *self.value_at_scan() = str_loc_as_cell!(h); @@ -370,11 +470,6 @@ impl CopyTermState { }); while self.scan < self.target.threshold() { - if self.target.pstr_at(self.scan) { - self.scan = self.target.next_non_pstr_cell_index(self.scan); - continue; - } - let addr = *self.value_at_scan(); read_heap_cell!(addr, @@ -405,17 +500,40 @@ impl CopyTermState { Ok(()) } - fn unwind_trail(mut self) { - for (r, value) in self.trail { - let index = r.get_value() as usize; + fn copy_pstrs(&mut self) -> Result<(), usize> { + while let Some((least_pstr_loc, pstr_data)) = self.pstr_loc_locs.pop_first() { + let threshold = heap_index!(self.target.threshold()); - match r.get_tag() { - RefTag::AttrVar | RefTag::HeapCell => { + for pstr_loc_loc in pstr_data.post_old_h_pstr_loc_locs { + let pstr_loc = self.target[pstr_loc_loc].get_value() as usize; + self.target[pstr_loc_loc] = + pstr_loc_as_cell!(threshold + pstr_loc - least_pstr_loc); + } + + self.target.copy_pstr_to_threshold(least_pstr_loc)?; + + let mut writer = self.target.reserve(1)?; + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(pstr_data.post_old_h_tail_loc)); + }); + } + + Ok(()) + } + + fn unwind_trail(&mut self) { + for (r, value) in self.trail.drain(..) { + let index = r.val() as usize; + + match r.tag() { + TrailRefTag::AttrVar | TrailRefTag::HeapCell => { self.target[index] = value; self.target[index].set_mark_bit(false); self.target[index].set_forwarding_bit(false); } - RefTag::StackCell => self.target.stack()[index] = value, + TrailRefTag::StackCell => self.target.stack()[index] = value, + TrailRefTag::PStrLoc => self.target[index] = value, } } } @@ -438,9 +556,10 @@ mod tests { let a_atom = atom!("a"); let b_atom = atom!("b"); - let mut functor_writer = Heap::functor_writer( - functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom)]), - ); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [atom_as_cell(a_atom), atom_as_cell(b_atom)] + )); functor_writer(&mut wam.machine_st.heap).unwrap(); @@ -480,29 +599,233 @@ mod tests { copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap(); } - assert_eq!( - wam.machine_st.heap.slice_to_str(0, "abc ".len()), - "abc " - ); + assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc "); assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(2))); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(2), "def".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(2), "def".len()), "def" ); assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(0)); - assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(5))); + assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(7))); + assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(9))); + assert_eq!(wam.machine_st.heap[6], pstr_loc_as_cell!(heap_index!(7))); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(5), "abc ".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(7), "abc ".len()), "abc " ); - assert_eq!(wam.machine_st.heap[6], pstr_loc_as_cell!(heap_index!(7))); + assert_eq!(wam.machine_st.heap[8], heap_loc_as_cell!(5)); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(7), "def".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(9), "def".len()), "def" ); - assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(heap_index!(5))); + assert_eq!(wam.machine_st.heap[10], heap_loc_as_cell!(6)); + + wam.machine_st.heap.clear(); + + let mut writer = wam.machine_st.heap.reserve(4).unwrap(); + + writer.write_with(|section| { + section.push_pstr("abc "); + section.push_cell(pstr_loc_as_cell!(heap_index!(2) + 9)); + + section.push_pstr("defdefdefdef"); + section.push_cell(pstr_loc_as_cell!(0)); + }); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap(); + } + + assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc "); + assert_eq!( + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(2) + 9) + ); + assert_eq!( + wam.machine_st + .heap + .slice_to_str(heap_index!(2), "defdefdefdef".len()), + "defdefdefdef" + ); + assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(8))); + assert_eq!( + wam.machine_st.heap[6], + pstr_loc_as_cell!(heap_index!(10) + 1) + ); + assert_eq!(wam.machine_st.heap[7], pstr_loc_as_cell!(heap_index!(8))); + + assert_eq!( + wam.machine_st + .heap + .slice_to_str(heap_index!(8), "abc ".len()), + "abc " + ); + assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(6)); + assert_eq!( + wam.machine_st + .heap + .slice_to_str(heap_index!(10), "fdef".len()), + "fdef" + ); + assert_eq!(wam.machine_st.heap[11], heap_loc_as_cell!(7)); + + wam.machine_st.heap.clear(); + + let mut writer = wam.machine_st.heap.reserve(4).unwrap(); + + writer.write_with(|section| { + section.push_pstr("012345678912345"); + section.push_cell(pstr_loc_as_cell!(heap_index!(0))); + }); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap(); + } + + assert_eq!( + wam.machine_st.heap.slice_to_str(0, "012345678912345".len()), + "012345678912345" + ); + assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(heap_index!(0))); + + assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(6))); + + assert_eq!( + wam.machine_st + .heap + .slice_to_str(heap_index!(6), "012345678912345".len()), + "012345678912345" + ); + assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(6))); + + wam.machine_st.heap.clear(); + + let mut writer = wam.machine_st.heap.reserve(4).unwrap(); + + writer.write_with(|section| { + section.push_pstr("012345678912345"); + section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 9)); + }); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap(); + } + + assert_eq!( + wam.machine_st.heap.slice_to_str(0, "012345678912345".len()), + "012345678912345" + ); + assert_eq!( + wam.machine_st.heap[3], + pstr_loc_as_cell!(heap_index!(0) + 9) + ); + + assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(6))); + assert_eq!( + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(6) + 9) + ); + + assert_eq!( + wam.machine_st + .heap + .slice_to_str(heap_index!(6), "012345678912345".len()), + "012345678912345" + ); + assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(5)); + + wam.machine_st.heap.clear(); + + let mut writer = wam.machine_st.heap.reserve(4).unwrap(); + + writer.write_with(|section| { + section.push_pstr("012345678912345"); + section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 7)); + }); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, pstr_loc_as_cell!(11), AttrVarPolicy::DeepCopy).unwrap(); + } + + assert_eq!( + wam.machine_st.heap.slice_to_str(0, "012345678912345".len()), + "012345678912345" + ); + assert_eq!( + wam.machine_st.heap[3], + pstr_loc_as_cell!(heap_index!(0) + 7) + ); + + assert_eq!( + wam.machine_st.heap[4], + pstr_loc_as_cell!(heap_index!(6) + 11) + ); + assert_eq!( + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(6) + 7) + ); + + assert_eq!( + wam.machine_st + .heap + .slice_to_str(heap_index!(6), "012345678912345".len()), + "012345678912345" + ); + assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(5)); + + wam.machine_st.heap.clear(); + + let mut writer = wam.machine_st.heap.reserve(4).unwrap(); + + writer.write_with(|section| { + section.push_pstr("012345678912345"); + section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 12)); + }); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, pstr_loc_as_cell!(11), AttrVarPolicy::DeepCopy).unwrap(); + } + + assert_eq!( + wam.machine_st.heap.slice_to_str(0, "012345678912345".len()), + "012345678912345" + ); + assert_eq!( + wam.machine_st.heap[3], + pstr_loc_as_cell!(heap_index!(0) + 12) + ); + + assert_eq!( + wam.machine_st.heap[4], + pstr_loc_as_cell!(heap_index!(6) + 3) + ); + assert_eq!( + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(6) + 4) + ); + + assert_eq!( + wam.machine_st + .heap + .slice_to_str(heap_index!(6), "8912345".len()), + "8912345" + ); + assert_eq!(wam.machine_st.heap[8], heap_loc_as_cell!(5)); wam.machine_st.heap.clear(); @@ -528,7 +851,6 @@ mod tests { assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom)); assert_eq!(wam.machine_st.heap[3], atom_as_cell!(a_atom)); assert_eq!(wam.machine_st.heap[4], str_loc_as_cell!(0)); - assert_eq!(wam.machine_st.heap[5], str_loc_as_cell!(6)); assert_eq!(wam.machine_st.heap[6], atom_as_cell!(f_atom, 4)); assert_eq!(wam.machine_st.heap[7], atom_as_cell!(a_atom)); diff --git a/src/machine/cycle_detection.rs b/src/machine/cycle_detection.rs index 99ae40b4..da125518 100644 --- a/src/machine/cycle_detection.rs +++ b/src/machine/cycle_detection.rs @@ -206,9 +206,9 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { } HeapCellValueTag::PStrLoc => { let h = self.next as usize; - let (_, last_cell_loc) = self.heap.scan_slice_to_str(h); + let tail_idx = self.heap.scan_slice_to_str(h).tail_idx; - if self.heap[last_cell_loc].get_forwarding_bit() { + if self.heap[tail_idx].get_forwarding_bit() { if self.cycle_detection_active() { self.cycle_found = true; return None; @@ -219,11 +219,11 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { continue; } - self.heap[last_cell_loc].set_forwarding_bit(true); + self.heap[tail_idx].set_forwarding_bit(true); - self.next = self.heap[last_cell_loc].get_value(); - self.heap[last_cell_loc].set_value(self.current as u64); - self.current = last_cell_loc; + self.next = self.heap[tail_idx].get_value(); + self.heap[tail_idx].set_value(self.current as u64); + self.current = tail_idx; return Some(pstr_loc_as_cell!(h)); } diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index a7b2a128..ad4460d4 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -2,11 +2,11 @@ use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::fact_iterator; -use crate::machine::Stack; use crate::machine::heap::*; use crate::machine::loader::*; use crate::machine::machine_errors::CompilationError; use crate::machine::preprocessor::*; +use crate::machine::Stack; use crate::parser::ast::*; use crate::parser::dashu::Rational; use crate::types::*; @@ -229,7 +229,8 @@ impl VarLocsToNums { } pub fn get(&self, idx: VarPtrIndex) -> VarPtr { - self.map.get(&idx) + self.map + .get(&idx) .cloned() .map(VarPtr::Numbered) .unwrap_or_else(|| VarPtr::Anon) @@ -260,8 +261,10 @@ impl VarData { if let Some(global_cut_var_num) = global_cut_var_num { let term = QueryTerm::GetLevel(global_cut_var_num); - self.records[global_cut_var_num].allocation = - VarAlloc::Perm { reg: 0, allocation: PermVarAllocation::Pending }; + self.records[global_cut_var_num].allocation = VarAlloc::Perm { + reg: 0, + allocation: PermVarAllocation::Pending, + }; match build_stack.front_mut() { Some(ChunkedTerms::Branch(_)) => { @@ -395,11 +398,7 @@ impl VariableClassifier { let mut lvl = Level::Shallow; let mut stack = Stack::uninitialized(); - let mut iter = fact_iterator::( - term.heap, - &mut stack, - term.focus, - ); + let mut iter = fact_iterator::(term.heap, &mut stack, term.focus); // second arg is true to iterate the root, which may be a variable while let Some(subterm) = iter.next() { @@ -425,8 +424,7 @@ impl VariableClassifier { fn probe_body_var(&mut self, context: GenContext, var_info: VarInfo) { let chunk_num = context.chunk_num(); - let branch_info_v = self.branch_map.entry(var_info.var) - .or_default(); + let branch_info_v = self.branch_map.entry(var_info.var).or_default(); let needs_new_branch = if let Some(last_bi) = branch_info_v.last() { !self.root_set.contains(&last_bi.branch_num) @@ -489,14 +487,10 @@ impl VariableClassifier { debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str); - for idx in str_offset + 1 ..= str_offset + arity { + for idx in str_offset + 1..=str_offset + arity { let mut lvl = Level::Shallow; let mut stack = Stack::uninitialized(); - let mut iter = fact_iterator::( - heap, - &mut stack, - idx, - ); + let mut iter = fact_iterator::(heap, &mut stack, idx); while let Some(subterm) = iter.next() { if !subterm.is_var() { @@ -661,13 +655,14 @@ impl VariableClassifier { mut term_loc, } => { // return true iff new chunk should be added. - let update_chunk_data = |build_stack: &mut ChunkedTermVec, key: PredicateKey| { - if ClauseType::is_inlined(key.0, key.1) { - build_stack.try_set_chunk_at_inlined_boundary() - } else { - build_stack.try_set_chunk_at_call_boundary() - } - }; + let update_chunk_data = + |build_stack: &mut ChunkedTermVec, key: PredicateKey| { + if ClauseType::is_inlined(key.0, key.1) { + build_stack.try_set_chunk_at_inlined_boundary() + } else { + build_stack.try_set_chunk_at_call_boundary() + } + }; macro_rules! add_chunk { ($key:expr, $tag:expr, $term_loc:expr) => {{ @@ -678,9 +673,10 @@ impl VariableClassifier { let context = build_stack.current_gen_context(); for (arg_c, term_loc) in - ($term_loc + 1 ..= $term_loc + $key.1).enumerate() + ($term_loc + 1..=$term_loc + $key.1).enumerate() { - let mut term = FocusedHeapRefMut::from(loader.machine_heap(), term_loc); + let mut term = + FocusedHeapRefMut::from(loader.machine_heap(), term_loc); self.probe_body_term( arg_c + 1, @@ -710,9 +706,10 @@ impl VariableClassifier { let context = build_stack.current_gen_context(); for (arg_c, term_loc) in - ($term_loc + 1 ..= $term_loc + $key.1).enumerate() + ($term_loc + 1..=$term_loc + $key.1).enumerate() { - let mut term = FocusedHeapRefMut::from(loader.machine_heap(), term_loc); + let mut term = + FocusedHeapRefMut::from(loader.machine_heap(), term_loc); self.probe_body_term( arg_c + 1, @@ -1043,8 +1040,8 @@ impl BranchMap { for (var, branches) in self.iter_mut() { let (mut var_num, var_num_incr) = match var { - &ClassifiedVar::InSitu { var_num} => (var_num, false), - _ => (var_data.records.len(), true) + &ClassifiedVar::InSitu { var_num } => (var_num, false), + _ => (var_data.records.len(), true), }; for branch in branches.iter_mut() { @@ -1088,7 +1085,10 @@ impl BranchMap { let chunk_num = chunk.term_loc.chunk_num(); var_data.var_locs_to_nums.insert( - VarPtrIndex { chunk_num, term_loc }, + VarPtrIndex { + chunk_num, + term_loc, + }, var_num, ); } diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index ad0ebc7d..cd672320 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -140,10 +140,7 @@ impl MachineState { let a1 = self.registers[1]; let a2 = self.registers[2]; - step_or_resource_error!( - self, - copy_term(CopyTerm::new(self), a1, attr_var_policy) - ); + step_or_resource_error!(self, copy_term(CopyTerm::new(self), a1, attr_var_policy)); unify_fn!(*self, heap_loc_as_cell!(old_h), a2); } @@ -162,11 +159,7 @@ impl MachineState { let heap_addr = resource_error_call_result!( self, - sized_iter_to_heap_list( - &mut self.heap, - list.len(), - list.into_iter(), - ) + sized_iter_to_heap_list(&mut self.heap, list.len(), list.into_iter(),) ); let target_addr = self.registers[2]; @@ -5155,9 +5148,8 @@ impl Machine { let r = self.machine_st.registers[2]; let r = self.machine_st.store(self.machine_st.deref(r)); - let mut writer = Heap::functor_writer( - functor!(atom!("-"), [fixnum(n), fixnum(p)]), - ); + let mut writer = + Heap::functor_writer(functor!(atom!("-"), [fixnum(n), fixnum(p)])); let str_cell = backtrack_on_resource_error!( &mut self.machine_st, @@ -5178,9 +5170,8 @@ impl Machine { let r = self.machine_st.registers[2]; let r = self.machine_st.store(self.machine_st.deref(r)); - let mut writer = Heap::functor_writer( - functor!(atom!("-"), [fixnum(n), fixnum(p)]), - ); + let mut writer = + Heap::functor_writer(functor!(atom!("-"), [fixnum(n), fixnum(p)])); let str_cell = backtrack_on_resource_error!( &mut self.machine_st, diff --git a/src/machine/gc.rs b/src/machine/gc.rs index f0f480f3..b18b5300 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -5,17 +5,20 @@ use crate::machine::heap::*; #[cfg(test)] use crate::types::*; -#[cfg(test)] -use fxhash::FxBuildHasher; -#[cfg(test)] -use indexmap::IndexMap; - #[cfg(test)] use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc}; +#[cfg(test)] +use std::collections::BTreeMap; #[cfg(test)] use std::ops::Deref; +#[cfg(test)] +use fxhash::FxBuildHasher; + +#[cfg(test)] +use indexmap::IndexMap; + #[cfg(test)] pub(crate) trait UnmarkPolicy { fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option @@ -36,7 +39,8 @@ pub(crate) trait UnmarkPolicy { fn record_focus(_iter: &mut StacklessPreOrderHeapIter) where Self: Sized, - {} + { + } } #[cfg(test)] @@ -109,7 +113,63 @@ impl UnmarkPolicy for MarkerUMP { } #[cfg(test)] -type PStrLocValuesMap = IndexMap; +#[derive(Debug)] +struct PStrLocValuesMap { + hit_set: BTreeMap, + pstr_loc_locs: IndexMap, +} + +#[cfg(test)] +impl PStrLocValuesMap { + #[inline] + fn new() -> Self { + Self { + hit_set: BTreeMap::default(), + pstr_loc_locs: IndexMap::with_hasher(FxBuildHasher::default()), + } + } + + fn progress_pstr_marking(&mut self, heap_slice: &[u8], pstr_loc: usize) -> usize { + match self.hit_set.range(..= pstr_loc).next_back() { + Some((_prev_pstr_loc, &tail_idx)) if pstr_loc < heap_index!(tail_idx) => { + return tail_idx; + } + _ => {} + } + + let delimiter = match self.hit_set.range(pstr_loc + 1..).next() { + Some((&prev_pstr_loc, _)) => prev_pstr_loc, + None => heap_slice.len(), + }; + + match heap_slice[pstr_loc..delimiter].iter().position(|b| *b == 0u8) { + Some(zero_byte_offset) => { + let tail_idx = if (zero_byte_offset + 1) % Heap::heap_cell_alignment() == 0 { + cell_index!(pstr_loc + zero_byte_offset) + 2 + } else { + cell_index!(pstr_loc + zero_byte_offset) + 1 + }; + self.hit_set.insert(pstr_loc, tail_idx); + tail_idx + } + None => { + let tail_idx = self.hit_set.remove(&delimiter).unwrap(); + self.hit_set.insert(pstr_loc, tail_idx); + tail_idx //None + } + } + } + + #[inline] + fn pstr_loc_loc_value(&self, pstr_loc_loc: usize) -> Option { + self.pstr_loc_locs.get(&pstr_loc_loc).cloned() + } + + #[inline] + fn insert_pstr_loc_value(&mut self, pstr_loc_loc: usize, pstr_loc: usize) { + self.pstr_loc_locs.insert(pstr_loc_loc, pstr_loc); + } +} #[cfg(test)] #[derive(Debug)] @@ -164,7 +224,7 @@ impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> { current: start, next, iter_state: MarkerUMP {}, - pstr_loc_values: PStrLocValuesMap::with_hasher(FxBuildHasher::default()), + pstr_loc_values: PStrLocValuesMap::new(), } } } @@ -182,7 +242,7 @@ impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> { current: start, next, iter_state: IteratorUMP { mark_phase: true }, - pstr_loc_values: PStrLocValuesMap::with_hasher(FxBuildHasher::default()), + pstr_loc_values: PStrLocValuesMap::new(), } } } @@ -260,8 +320,8 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { let arity = cell_as_atom_cell!(self.heap[h]).get_arity(); - for cell in &mut self.heap.splice_mut(h + 1..h + arity + 1) { - cell.set_forwarding_bit(true); + for idx in h + 1..=h + arity { + self.heap[idx].set_forwarding_bit(true); } let last_cell_loc = h + arity; @@ -288,22 +348,25 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { return Some(list_loc_as_cell!(last_cell_loc - 1)); } HeapCellValueTag::PStrLoc => { - let h = self.next as usize; - let (_, last_cell_loc) = self.heap.scan_slice_to_str(h); + let pstr_loc = self.next as usize; - self.pstr_loc_values.insert(self.current, h); + let tail_idx = self + .pstr_loc_values + .progress_pstr_marking(self.heap.as_slice(), pstr_loc); - if self.heap[last_cell_loc].get_forwarding_bit() { + self.pstr_loc_values.insert_pstr_loc_value(self.current, pstr_loc); + + if self.heap[tail_idx].get_forwarding_bit() { return Some(self.backward_and_return()); } - self.next = self.heap[last_cell_loc].get_value(); - self.heap[last_cell_loc].set_value(self.current as u64); - self.current = last_cell_loc; + self.next = self.heap[tail_idx].get_value(); + self.heap[tail_idx].set_value(self.current as u64); + self.current = tail_idx; - self.heap[last_cell_loc].set_forwarding_bit(true); + self.heap[tail_idx].set_forwarding_bit(true); - return Some(pstr_loc_as_cell!(h)); + return Some(pstr_loc_as_cell!(pstr_loc)); } tag @ HeapCellValueTag::Atom => { let cell = HeapCellValue::build_with(tag, self.next); @@ -315,17 +378,24 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { return None; } } - HeapCellValueTag::Cons if self.heap.pstr_at(self.current) => { - let pstr_loc_loc = self.heap[self.current].get_value() as usize; - let pstr_loc_val = self.pstr_loc_values.get(&pstr_loc_loc).unwrap(); + HeapCellValueTag::Cons => { + match self.pstr_loc_values.hit_set.range(.. heap_index!(self.current + 1)).next_back() { + Some((_prev_pstr_loc, &tail_idx)) if self.current + 1 == tail_idx => { + let pstr_loc_loc = self.heap[self.current].get_value() as usize; + let pstr_loc_val = self.pstr_loc_values.pstr_loc_loc_value(pstr_loc_loc).unwrap(); - self.heap[self.current].set_value(self.next); + self.heap[self.current].set_value(self.next); - self.next = *pstr_loc_val as u64; - self.current = pstr_loc_loc; + self.next = pstr_loc_val as u64; + self.current = pstr_loc_loc; - if self.backward() { - return None; + if self.backward() { + return None; + } + } + _ => { + return Some(self.backward_and_return()); + } } } _ => { @@ -398,9 +468,10 @@ mod tests { let a_atom = atom!("a"); let b_atom = atom!("b"); - let mut functor_writer = Heap::functor_writer( - functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom)]), - ); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [atom_as_cell(a_atom), atom_as_cell(b_atom)] + )); let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); let h = wam.machine_st.heap.cell_len(); @@ -409,7 +480,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, h); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[3]), @@ -431,17 +502,15 @@ mod tests { wam.machine_st.heap.clear(); - let mut functor_writer = Heap::functor_writer( - functor!( - f_atom, - [ - atom_as_cell(a_atom), - atom_as_cell(b_atom), - atom_as_cell(a_atom), - str_loc_as_cell(1) - ] - ), - ); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [ + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(1) + ] + )); let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); let h = wam.machine_st.heap.cell_len(); @@ -449,7 +518,7 @@ mod tests { wam.machine_st.heap.push_cell(cell).unwrap(); mark_cells(&mut wam.machine_st.heap, h); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[5]), @@ -473,28 +542,26 @@ mod tests { atom_as_cell!(a_atom) ); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + unmark_all_cells(&mut wam.machine_st.heap, 0); // make the structure doubly cyclic. wam.machine_st.heap[1] = str_loc_as_cell!(0); mark_cells(&mut wam.machine_st.heap, h); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); wam.machine_st.heap.clear(); - let mut functor_writer = Heap::functor_writer( - functor!( - f_atom, - [ - atom_as_cell(a_atom), - atom_as_cell(b_atom), - atom_as_cell(a_atom), - str_loc_as_cell(0) - ] - ), - ); + let mut functor_writer = Heap::functor_writer(functor!( + f_atom, + [ + atom_as_cell(a_atom), + atom_as_cell(b_atom), + atom_as_cell(a_atom), + str_loc_as_cell(0) + ] + )); let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); let h = wam.machine_st.heap.cell_len(); @@ -503,7 +570,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, h); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[5]), @@ -536,7 +603,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -558,7 +625,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -581,14 +648,14 @@ mod tests { empty_list_as_cell!() ); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + unmark_all_cells(&mut wam.machine_st.heap, 0); // now make the list cyclic. wam.machine_st.heap[4] = heap_loc_as_cell!(0); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -611,24 +678,21 @@ mod tests { heap_loc_as_cell!(0) ); - for cell in &mut wam.machine_st.heap.splice_mut(..) { - cell.set_mark_bit(false); - } + unmark_all_cells(&mut wam.machine_st.heap, 0); // make the list doubly cyclic. wam.machine_st.heap[3] = heap_loc_as_cell!(0); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); wam.machine_st.heap.clear(); // term is: [a, ] let stream = Stream::from_static_string("test", &mut wam.machine_st.arena); - let stream_cell = HeapCellValue::from( - ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons), - ); + let stream_cell = + HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons)); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -642,7 +706,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -677,7 +741,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -708,19 +772,27 @@ mod tests { let pstr_cell_loc = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push_cell(pstr_loc_as_cell!(heap_index!(0))).unwrap(); + wam.machine_st + .heap + .push_cell(pstr_loc_as_cell!(heap_index!(0))) + .unwrap(); mark_cells(&mut wam.machine_st.heap, pstr_cell_loc); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 1); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + unmark_all_cells(&mut wam.machine_st.heap, 1); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(0), "abc ".len()), "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[pstr_cell_loc]), pstr_cell); + assert_eq!( + unmark_cell_bits!(wam.machine_st.heap[pstr_cell_loc]), + pstr_cell + ); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1) @@ -728,135 +800,155 @@ mod tests { wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.allocate_pstr("abc ").unwrap(); - wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); + wam.machine_st.allocate_pstr("abcdef ").unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap(); mark_cells(&mut wam.machine_st.heap, 2); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + assert!(wam.machine_st.heap[0].get_mark_bit()); + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + + unmark_all_cells(&mut wam.machine_st.heap, 0); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(0), "abc ".len()), "abc " ); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(3))); + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(heap_index!(0))); assert_eq!( - wam.machine_st.heap[1], - pstr_loc_as_cell!(heap_index!(3)) - ); - assert_eq!( - wam.machine_st.heap[2], - pstr_loc_as_cell!(heap_index!(0)) - ); - assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), - "abc " - ); - assert_eq!( - wam.machine_st.heap[4], - heap_loc_as_cell!(4) + wam.machine_st + .heap + .slice_to_str(heap_index!(3), "abcdef ".len()), + "abcdef " ); + assert_eq!(wam.machine_st.heap[5], heap_loc_as_cell!(5)); // create a cycle offset two characters into the partial string at 0 - wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(0) + 2); + wam.machine_st.heap[5] = pstr_loc_as_cell!(heap_index!(0) + 2); mark_cells(&mut wam.machine_st.heap, 2); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + assert!(wam.machine_st.heap[0].get_mark_bit()); + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + wam.machine_st.heap[0].set_mark_bit(false); + wam.machine_st.heap[1].set_mark_bit(false); + wam.machine_st.heap[2].set_mark_bit(false); + wam.machine_st.heap[4].set_mark_bit(false); + wam.machine_st.heap[5].set_mark_bit(false); + + assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc "); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(3))); + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(heap_index!(0))); assert_eq!( - wam.machine_st.heap.slice_to_str(0, "abc ".len()), - "abc " + wam.machine_st + .heap + .slice_to_str(heap_index!(3), "abcdef ".len()), + "abcdef " ); assert_eq!( - wam.machine_st.heap[1], - pstr_loc_as_cell!(heap_index!(3)) - ); - assert_eq!( - wam.machine_st.heap[2], - pstr_loc_as_cell!(heap_index!(0)) - ); - assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), - "abc " - ); - assert_eq!( - wam.machine_st.heap[4], + wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(0) + 2) ); - wam.machine_st.heap[4] = heap_loc_as_cell!(2); - + wam.machine_st.heap[5] = heap_loc_as_cell!(2); wam.machine_st.heap.push_cell(heap_loc_as_cell!(2)).unwrap(); - mark_cells(&mut wam.machine_st.heap, 5); + mark_cells(&mut wam.machine_st.heap, 6); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + assert!(wam.machine_st.heap[0].get_mark_bit()); + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + assert!(wam.machine_st.heap[6].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_forwarding_bit()); - assert_eq!( - wam.machine_st.heap.slice_to_str(0, "abc ".len()), - "abc " - ); - assert_eq!( - wam.machine_st.heap[1], - pstr_loc_as_cell!(heap_index!(3)) - ); - assert_eq!( - wam.machine_st.heap[2], - pstr_loc_as_cell!(heap_index!(0)) - ); - assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), - "abc " - ); - assert_eq!( - wam.machine_st.heap[4], - heap_loc_as_cell!(2) - ); - assert_eq!( - wam.machine_st.heap[5], - heap_loc_as_cell!(2) - ); + wam.machine_st.heap[0].set_mark_bit(false); + wam.machine_st.heap[1].set_mark_bit(false); + wam.machine_st.heap[2].set_mark_bit(false); + wam.machine_st.heap[4].set_mark_bit(false); + wam.machine_st.heap[5].set_mark_bit(false); + wam.machine_st.heap[6].set_mark_bit(false); - wam.machine_st.heap[4] = pstr_loc_as_cell!(0); + assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc "); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(3))); + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(heap_index!(0))); + assert_eq!( + wam.machine_st + .heap + .slice_to_str(heap_index!(3), "abcdef ".len()), + "abcdef " + ); + assert_eq!(wam.machine_st.heap[5], heap_loc_as_cell!(2)); + assert_eq!(wam.machine_st.heap[6], heap_loc_as_cell!(2)); + + wam.machine_st.heap[5] = pstr_loc_as_cell!(0); mark_cells(&mut wam.machine_st.heap, 2); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(.. 5)); + assert!(wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); - unmark_all_cells(wam.machine_st.heap.splice_mut(.. 5)); + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); + assert!(!wam.machine_st.heap[3].get_forwarding_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + assert!(!wam.machine_st.heap[6].get_forwarding_bit()); - assert_eq!( - wam.machine_st.heap.slice_to_str(0, "abc ".len()), - "abc " - ); - assert_eq!( - wam.machine_st.heap[1], - pstr_loc_as_cell!(heap_index!(3)) - ); - assert_eq!( - wam.machine_st.heap[2], - pstr_loc_as_cell!(heap_index!(0)) - ); - assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), - "abc " - ); - assert_eq!( - wam.machine_st.heap[4], - pstr_loc_as_cell!(heap_index!(0)) - ); - assert_eq!( - wam.machine_st.heap[5], - heap_loc_as_cell!(2) - ); + wam.machine_st.heap[0].set_mark_bit(false); + wam.machine_st.heap[1].set_mark_bit(false); + wam.machine_st.heap[2].set_mark_bit(false); + wam.machine_st.heap[4].set_mark_bit(false); + wam.machine_st.heap[5].set_mark_bit(false); - wam.machine_st.heap.truncate(4); + assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc "); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(3))); + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(heap_index!(0))); + assert_eq!( + wam.machine_st + .heap + .slice_to_str(heap_index!(3), "abcdef ".len()), + "abcdef " + ); + assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(0))); + assert_eq!(wam.machine_st.heap[6], heap_loc_as_cell!(2)); + + wam.machine_st.heap.truncate(5); let mut writer = wam.machine_st.heap.reserve(2).unwrap(); @@ -865,51 +957,42 @@ mod tests { section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 2)); // offset two chars into pstr at 0 }); - wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(6)).unwrap(); - mark_cells(&mut wam.machine_st.heap, 6); + mark_cells(&mut wam.machine_st.heap, 7); - // indices 0 and 3 are the beginning of one-cell partial - // strings, and they should be marked! despite the HeapCellValue casts - // otherwise not being sensible. + // indices 0 and 3 - 4 are the beginning of one-cell partial + // strings, and they should be marked! despite the + // HeapCellValue casts otherwise not being sensible. assert!(wam.machine_st.heap[0].get_mark_bit()); assert!(wam.machine_st.heap[1].get_mark_bit()); assert!(!wam.machine_st.heap[2].get_mark_bit()); - assert!(wam.machine_st.heap[3].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); assert!(wam.machine_st.heap[4].get_mark_bit()); assert!(wam.machine_st.heap[5].get_mark_bit()); assert!(wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + unmark_all_cells(&mut wam.machine_st.heap, 0); + assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc "); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(3))); + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(heap_index!(0))); assert_eq!( - wam.machine_st.heap.slice_to_str(0, "abc ".len()), - "abc " - ); - assert_eq!( - wam.machine_st.heap[1], - pstr_loc_as_cell!(heap_index!(3)) - ); - assert_eq!( - wam.machine_st.heap[2], - pstr_loc_as_cell!(heap_index!(0)) - ); - assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), - "abc " - ); - assert_eq!( - wam.machine_st.heap[4], - atom_as_cell!(atom!("irrelevant stuff")) + wam.machine_st + .heap + .slice_to_str(heap_index!(3), "abcdef ".len()), + "abcdef " ); assert_eq!( wam.machine_st.heap[5], - pstr_loc_as_cell!(heap_index!(0) + 2) + atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( wam.machine_st.heap[6], - heap_loc_as_cell!(5) + pstr_loc_as_cell!(heap_index!(0) + 2) ); + assert_eq!(wam.machine_st.heap[7], heap_loc_as_cell!(6)); wam.machine_st.heap.clear(); @@ -944,26 +1027,27 @@ mod tests { assert!(!wam.machine_st.heap[5].get_forwarding_bit()); assert!(!wam.machine_st.heap[6].get_forwarding_bit()); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + unmark_all_cells(&mut wam.machine_st.heap, 0); assert_eq!( wam.machine_st.heap[0], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(1), "abc ".len()), "abc " ); - assert_eq!( - wam.machine_st.heap[2], - pstr_loc_as_cell!(heap_index!(4)) - ); + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(heap_index!(4))); assert_eq!( wam.machine_st.heap[3], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(4), "def".len()), "def" ); assert_eq!( @@ -988,34 +1072,31 @@ mod tests { assert!(!wam.machine_st.heap[6].get_mark_bit()); assert!(wam.machine_st.heap[7].get_mark_bit()); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + unmark_all_cells(&mut wam.machine_st.heap, 0); - assert!(!wam.machine_st.heap[0].get_forwarding_bit()); - assert!(!wam.machine_st.heap[1].get_forwarding_bit()); - assert!(!wam.machine_st.heap[2].get_forwarding_bit()); - assert!(!wam.machine_st.heap[3].get_forwarding_bit()); - assert!(!wam.machine_st.heap[4].get_forwarding_bit()); - assert!(!wam.machine_st.heap[5].get_forwarding_bit()); - assert!(!wam.machine_st.heap[6].get_forwarding_bit()); + for idx in 0..=6 { + assert!(!wam.machine_st.heap[idx].get_forwarding_bit()); + } assert_eq!( wam.machine_st.heap[0], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(1), "abc ".len()), "abc " ); - assert_eq!( - wam.machine_st.heap[2], - pstr_loc_as_cell!(heap_index!(4)) - ); + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(heap_index!(4))); assert_eq!( wam.machine_st.heap[3], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(4), "def".len()), "def" ); assert_eq!( @@ -1040,34 +1121,31 @@ mod tests { assert!(!wam.machine_st.heap[6].get_mark_bit()); assert!(wam.machine_st.heap[7].get_mark_bit()); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + unmark_all_cells(&mut wam.machine_st.heap, 0); - assert!(!wam.machine_st.heap[0].get_forwarding_bit()); - assert!(!wam.machine_st.heap[1].get_forwarding_bit()); - assert!(!wam.machine_st.heap[2].get_forwarding_bit()); - assert!(!wam.machine_st.heap[3].get_forwarding_bit()); - assert!(!wam.machine_st.heap[4].get_forwarding_bit()); - assert!(!wam.machine_st.heap[5].get_forwarding_bit()); - assert!(!wam.machine_st.heap[6].get_forwarding_bit()); + for idx in 0..=6 { + assert!(!wam.machine_st.heap[idx].get_forwarding_bit()); + } assert_eq!( wam.machine_st.heap[0], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(1), "abc ".len()), "abc " ); - assert_eq!( - wam.machine_st.heap[2], - pstr_loc_as_cell!(heap_index!(4)) - ); + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(heap_index!(4))); assert_eq!( wam.machine_st.heap[3], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(4), "def".len()), "def" ); assert_eq!( @@ -1096,34 +1174,24 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 5); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + unmark_all_cells(&mut wam.machine_st.heap, 0); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(0), "abc ".len()), "abc " ); assert_eq!( wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(0) + 3) ); - assert_eq!( - wam.machine_st.heap[2], - list_loc_as_cell!(3) - ); - assert_eq!( - wam.machine_st.heap[3], - pstr_loc_as_cell!(0) - ); - assert_eq!( - wam.machine_st.heap[4], - empty_list_as_cell!() - ); - assert_eq!( - wam.machine_st.heap[5], - heap_loc_as_cell!(2) - ); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(0)); + assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!()); + assert_eq!(wam.machine_st.heap[5], heap_loc_as_cell!(2)); wam.machine_st.heap.clear(); @@ -1140,26 +1208,14 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); - unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + unmark_all_cells(&mut wam.machine_st.heap, 0); - assert_eq!( - wam.machine_st.heap[0], - heap_loc_as_cell!(1) - ); - assert_eq!( - wam.machine_st.heap[1], - heap_loc_as_cell!(2) - ); - assert_eq!( - wam.machine_st.heap[2], - heap_loc_as_cell!(3) - ); - assert_eq!( - wam.machine_st.heap[3], - heap_loc_as_cell!(3) - ); + assert_eq!(wam.machine_st.heap[0], heap_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(2)); + assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], heap_loc_as_cell!(3)); wam.machine_st.heap.clear(); @@ -1175,7 +1231,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1215,7 +1271,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1274,7 +1330,8 @@ mod tests { let clpz_atom = atom!("clpz"); let p_atom = atom!("p"); - for cell in &mut wam.machine_st.heap.splice_mut(..) { + for idx in 0..wam.machine_st.heap.cell_len() { + let cell = &mut wam.machine_st.heap[idx]; cell.set_mark_bit(false); cell.set_forwarding_bit(false); } @@ -1299,7 +1356,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1398,7 +1455,9 @@ mod tests { heap_loc_as_cell!(23) ); - for cell in &mut wam.machine_st.heap.splice_mut(..) { + for idx in 0..wam.machine_st.heap.cell_len() { + let cell = &mut wam.machine_st.heap[idx]; + cell.set_mark_bit(false); cell.set_forwarding_bit(false); } @@ -1415,10 +1474,13 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(0..24)); + for idx in 0..24 { + assert!(wam.machine_st.heap[idx].get_mark_bit()); + assert!(!wam.machine_st.heap[idx].get_forwarding_bit()); + } - for cell in wam.machine_st.heap.splice(24..) { - assert!(!cell.get_mark_bit()); + for idx in 24..wam.machine_st.heap.cell_len() { + assert!(!wam.machine_st.heap[idx].get_mark_bit()); } assert_eq!( @@ -1540,7 +1602,7 @@ mod tests { assert_eq!(wam.machine_st.heap.cell_len(), 1); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); wam.machine_st.heap.clear(); @@ -1563,7 +1625,7 @@ mod tests { assert_eq!(wam.machine_st.heap.cell_len(), 10); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1619,7 +1681,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 3); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1653,7 +1715,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 7); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1708,7 +1770,7 @@ mod tests { assert!(wam.machine_st.heap[0].get_mark_bit()); assert!(!wam.machine_st.heap[1].get_mark_bit()); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(2..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 2); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1770,7 +1832,7 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + all_cells_marked_and_unforwarded(&wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 8f4d4a6c..fc517740 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -5,22 +5,17 @@ use crate::types::*; use std::alloc; use std::convert::TryFrom; -use std::mem; use std::ops::{Bound, Index, IndexMut, Range, RangeBounds}; use std::ptr; use std::sync::Once; use super::MachineState; -use bitvec::prelude::*; -use bitvec::slice::BitSlice; - const ALIGN: usize = Heap::heap_cell_alignment(); #[derive(Debug)] pub struct Heap { inner: InnerHeap, - pstr_vec: BitVec, resource_err_loc: usize, } @@ -90,40 +85,51 @@ unsafe impl Sync for Heap {} static RESOURCE_ERROR_OFFSET_INIT: Once = Once::new(); +#[derive(Debug)] +pub struct HeapStringScan<'a> { + pub string: &'a str, + pub tail_idx: usize, +} + // return the string at ptr and the tail location relative to ptr. -// pstr_vec records the location of each string cell starting at index -// 0. -fn scan_slice_to_str(orig_ptr: *const u8, pstr_vec: &BitSlice) -> (&str, usize) { - unsafe { - debug_assert_eq!(pstr_vec[0], true); +unsafe fn scan_slice_to_str<'a>(heap_slice: &'a [u8]) -> HeapStringScan<'a> { + let string_len = heap_slice.iter().position(|b| *b == 0u8).unwrap(); + let zero_byte_addr = heap_slice.as_ptr().add(string_len); + let sentinel_len = pstr_sentinel_length(zero_byte_addr as usize); + let tail_idx = cell_index!( + (string_len + sentinel_len).next_multiple_of(ALIGN) + + if sentinel_len <= 1 { heap_index!(1) } else { 0 } + ); - let tail_cell_offset = pstr_vec[0..].first_zero().unwrap(); - let offset = (ALIGN - orig_ptr.align_offset(ALIGN)) % 8; - let buf_len = heap_index!(tail_cell_offset) - offset; - let slice = std::slice::from_raw_parts(orig_ptr, buf_len); + let str_slice = &heap_slice[..string_len]; - // skip the final buffer byte which may not be 0 depending on - // the context, i.e. marking by an iterator. it is counted by - // the initial 1 as part of the padding but for this reason - // mustn't be allowed to stop the count. - - let padding_len = 1 + slice.iter() - .rev() - .skip(1) - .position(|b| *b != 0u8) - .unwrap(); - - let s_len = slice.len() - padding_len; - (std::str::from_utf8_unchecked(&slice[0 .. s_len]), tail_cell_offset) + HeapStringScan { + string: std::str::from_utf8_unchecked(str_slice), + tail_idx, } } #[derive(Debug, Clone, Copy)] pub(crate) enum PStrSegmentCmpResult { - Mismatch { c1: char, c2: char }, - FirstMatch { pstr_loc1: usize, pstr_loc2: usize, l1_offset: usize }, - SecondMatch { pstr_loc1: usize, pstr_loc2: usize, l2_offset: usize }, - BothMatch { pstr_loc1: usize, pstr_loc2: usize, null_offset: usize }, + Mismatch { + c1: char, + c2: char, + }, + FirstMatch { + pstr_loc1: usize, + pstr_loc2: usize, + l1_offset: usize, + }, + SecondMatch { + pstr_loc1: usize, + pstr_loc2: usize, + l2_offset: usize, + }, + BothMatch { + pstr_loc1: usize, + pstr_loc2: usize, + null_offset: usize, + }, } impl PStrSegmentCmpResult { @@ -132,24 +138,36 @@ impl PStrSegmentCmpResult { pdl: &mut Vec, ) -> Option { match self { - PStrSegmentCmpResult::FirstMatch { pstr_loc1, pstr_loc2, l1_offset } => { - let tail1 = Heap::neighboring_cell_offset(pstr_loc1 + l1_offset); + PStrSegmentCmpResult::FirstMatch { + pstr_loc1, + pstr_loc2, + l1_offset, + } => { + let tail1 = Heap::pstr_tail_idx(pstr_loc1 + l1_offset); let rest_of_l2 = pstr_loc_as_cell!(pstr_loc2 + l1_offset); pdl.push(heap_loc_as_cell!(tail1)); pdl.push(rest_of_l2); } - PStrSegmentCmpResult::SecondMatch { pstr_loc1, pstr_loc2, l2_offset } => { - let tail2 = Heap::neighboring_cell_offset(pstr_loc2 + l2_offset); + PStrSegmentCmpResult::SecondMatch { + pstr_loc1, + pstr_loc2, + l2_offset, + } => { + let tail2 = Heap::pstr_tail_idx(pstr_loc2 + l2_offset); let rest_of_l1 = pstr_loc_as_cell!(pstr_loc1 + l2_offset); pdl.push(rest_of_l1); pdl.push(heap_loc_as_cell!(tail2)); } - PStrSegmentCmpResult::BothMatch { pstr_loc1, pstr_loc2, null_offset } => { + PStrSegmentCmpResult::BothMatch { + pstr_loc1, + pstr_loc2, + null_offset, + } => { // exhaustive match - let tail1 = Heap::neighboring_cell_offset(pstr_loc1 + null_offset); - let tail2 = Heap::neighboring_cell_offset(pstr_loc2 + null_offset); + let tail1 = Heap::pstr_tail_idx(pstr_loc1 + null_offset); + let tail2 = Heap::pstr_tail_idx(pstr_loc2 + null_offset); pdl.push(heap_loc_as_cell!(tail1)); pdl.push(heap_loc_as_cell!(tail2)); @@ -163,162 +181,18 @@ impl PStrSegmentCmpResult { } } -#[derive(Debug)] -pub(crate) struct HeapView<'a> { - slice: *const u8, - cell_offset: usize, - slice_cell_len: usize, - pstr_slice: &'a BitSlice, -} - -impl<'a> HeapView<'a> { - /* - pub fn get(&self, idx: usize) -> Option { - if idx < self.slice_cell_len { - Some(*self.index(idx)) - } else { - None - } - } - */ - - fn iter_follow(&mut self) -> Option { - if self.slice_cell_len == 0 { - None - } else { - let cell; - - if self.pstr_slice[0] { - cell = pstr_loc_as_cell!(heap_index!(self.cell_offset)); - let next_cell_idx = self.pstr_slice[0 ..].first_zero().unwrap(); - - unsafe { self.slice = self.slice.add(heap_index!(next_cell_idx)); } - self.slice_cell_len -= next_cell_idx; - self.cell_offset += next_cell_idx; - self.pstr_slice = &self.pstr_slice[next_cell_idx ..]; - } else { - unsafe { - cell = ptr::read(self.slice as *mut HeapCellValue); - self.slice = self.slice.add(heap_index!(1)); - } - - self.cell_offset += 1; - self.slice_cell_len -= 1; - self.pstr_slice = &self.pstr_slice[1 ..]; - } - - Some(cell) - } - } -} - -impl<'a> Iterator for HeapView<'a> { - type Item = HeapCellValue; - - #[inline] - fn next(&mut self) -> Option { - self.iter_follow() - } -} - -impl<'a> Index for HeapView<'a> { - type Output = HeapCellValue; - - fn index(&self, idx: usize) -> &Self::Output { - debug_assert!(idx < self.slice_cell_len); - unsafe { - &*(self.slice.add(heap_index!(idx)) as *const HeapCellValue) - } - } -} - -#[derive(Debug)] -pub(crate) struct HeapViewMut<'a> { - slice: *mut u8, - cell_offset: usize, - slice_cell_len: usize, - pstr_slice: &'a BitSlice, -} - -impl<'a> HeapViewMut<'a> { - fn iter_follow(&mut self) -> Option<&'a mut HeapCellValue> { - if self.slice_cell_len == 0 { - None - } else { - let cell; - - loop { - if self.pstr_slice[0] { - let next_cell_idx = self.pstr_slice[0 ..].first_zero().unwrap(); - - unsafe { self.slice = self.slice.add(heap_index!(next_cell_idx)); } - - self.slice_cell_len -= next_cell_idx; - self.cell_offset += next_cell_idx; - self.pstr_slice = &self.pstr_slice[next_cell_idx ..]; - } else { - unsafe { - cell = &mut *(self.slice as *mut HeapCellValue); - self.slice = self.slice.add(heap_index!(1)); - } - - self.cell_offset += 1; - self.slice_cell_len -= 1; - self.pstr_slice = &self.pstr_slice[1 ..]; - - break; - } - } - - Some(cell) - } - } -} - - - -impl<'a> Index for HeapViewMut<'a> { - type Output = HeapCellValue; - - fn index(&self, idx: usize) -> &Self::Output { - debug_assert!(idx < self.slice_cell_len); - unsafe { - &*(self.slice.add(heap_index!(idx)) as *const HeapCellValue) - } - } -} - -impl<'a> IndexMut for HeapViewMut<'a> { - fn index_mut(&mut self, idx: usize) -> &mut Self::Output { - debug_assert!(idx < self.slice_cell_len); - unsafe { - &mut *(self.slice.add(heap_index!(idx)) as *mut HeapCellValue) - } - } -} - -impl<'a> Iterator for &'a mut HeapViewMut<'a> { - type Item = &'a mut HeapCellValue; - - #[inline] - fn next(&mut self) -> Option { - self.iter_follow() - } -} - #[derive(Debug)] pub struct PStrWriteInfo { pstr_loc: usize, } #[derive(Debug)] -pub(crate) struct ReservedHeapSection<'a> { +pub(crate) struct ReservedHeapSection { heap_ptr: *mut u8, heap_cell_len: usize, - pstr_vec: &'a mut BitVec, } -impl<'a> ReservedHeapSection<'a> { +impl ReservedHeapSection { #[inline] pub(crate) fn cell_len(&self) -> usize { self.heap_cell_len @@ -326,16 +200,16 @@ impl<'a> ReservedHeapSection<'a> { pub(crate) fn push_cell(&mut self, cell: HeapCellValue) { unsafe { - ptr::write(self.heap_ptr.add(heap_index!(self.heap_cell_len)) as *mut _, cell); + ptr::write( + self.heap_ptr.add(heap_index!(self.heap_cell_len)) as *mut _, + cell, + ); } - self.pstr_vec.push(false); + // self.pstr_vec.push(false); self.heap_cell_len += 1; } - fn push_pstr_segment( - &mut self, - src: &str, - ) -> usize { + fn push_pstr_segment(&mut self, src: &str) -> usize { if src.is_empty() { return 0; } @@ -354,23 +228,30 @@ impl<'a> ReservedHeapSection<'a> { let align_offset = pstr_sentinel_length(zero_region_idx); - ptr::write_bytes( - self.heap_ptr.add(zero_region_idx), - 0u8, - align_offset, - ); + ptr::write_bytes(self.heap_ptr.add(zero_region_idx), 0u8, align_offset); + + cells_written = if align_offset == 1 { + ptr::write_bytes( + self.heap_ptr.add(zero_region_idx + 1), + 0u8, + size_of::(), + ); + + // ensure there are at least two bytes in the boundary + // buffer separating the string data from the tail + // cell + cell_index!(src.len() + align_offset + size_of::()) + } else { + cell_index!(src.len() + align_offset) + }; - cells_written = cell_index!(src.len() + align_offset); self.heap_cell_len += cells_written; } cells_written } - pub(crate) fn push_pstr( - &mut self, - mut src: &str, - ) -> Option { + pub(crate) fn push_pstr(&mut self, mut src: &str) -> Option { let orig_h = self.cell_len(); if src.is_empty() { @@ -386,18 +267,14 @@ impl<'a> ReservedHeapSection<'a> { loop { let null_char_idx = src.find('\u{0}').unwrap_or_else(|| src.len()); - - let cell_len = self.cell_len(); let cells_written = self.push_pstr_segment(&src[0..null_char_idx]); let tail_idx = self.cell_len(); - self.pstr_vec.resize(cell_len + cells_written, true); - if cells_written == 0 { return None; } else if null_char_idx + 1 < src.len() { self.push_cell(pstr_loc_as_cell!(heap_index!(tail_idx + 1))); - src = &src[null_char_idx + 1 ..]; + src = &src[null_char_idx + 1..]; } else { return Some(pstr_loc_as_cell!(heap_index!(orig_h))); } @@ -420,7 +297,12 @@ impl<'a> ReservedHeapSection<'a> { cursor: 0, }]; - while let Some(FunctorData { functor, cell_offset, mut cursor }) = functor_stack.pop() { + while let Some(FunctorData { + functor, + cell_offset, + mut cursor, + }) = functor_stack.pop() + { while cursor < functor.len() { match &functor[cursor] { &FunctorElement::AbsoluteCell(cell) => { @@ -460,15 +342,13 @@ impl<'a> ReservedHeapSection<'a> { } } -impl<'a> Index for ReservedHeapSection<'a> { +impl Index for ReservedHeapSection { type Output = HeapCellValue; #[inline] fn index(&self, idx: usize) -> &Self::Output { debug_assert!(idx < self.heap_cell_len); - unsafe { - &*(self.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue) - } + unsafe { &*(self.heap_ptr as *const HeapCellValue).add(idx) } } } @@ -489,7 +369,7 @@ fn pstr_sentinel_length(chunk_len: usize) -> usize { #[must_use] #[derive(Debug)] pub struct HeapWriter<'a> { - section: ReservedHeapSection<'a>, + section: ReservedHeapSection, heap_byte_len: &'a mut usize, } @@ -504,13 +384,12 @@ impl<'a> HeapWriter<'a> { *self.heap_byte_len = heap_index!(self.section.heap_cell_len); // return the number of bytes written - Ok(heap_index!(self.section.heap_cell_len - old_section_cell_len)) + Ok(heap_index!( + self.section.heap_cell_len - old_section_cell_len + )) } - pub(crate) fn write_with( - &mut self, - writer: impl FnOnce(&mut ReservedHeapSection), - ) -> usize { + pub(crate) fn write_with(&mut self, writer: impl FnOnce(&mut ReservedHeapSection)) -> usize { let old_section_cell_len = self.section.heap_cell_len; writer(&mut self.section); *self.heap_byte_len = heap_index!(self.section.heap_cell_len); @@ -522,7 +401,7 @@ impl<'a> HeapWriter<'a> { #[inline] pub(crate) fn truncate(&mut self, cell_offset: usize) { self.section.heap_cell_len = cell_offset; - self.section.pstr_vec.truncate(cell_offset); + // self.section.pstr_vec.truncate(cell_offset); *self.heap_byte_len = heap_index!(cell_offset); } @@ -543,9 +422,7 @@ impl<'a> Index for HeapWriter<'a> { #[inline] fn index(&self, idx: usize) -> &Self::Output { debug_assert!(heap_index!(idx) < *self.heap_byte_len); - unsafe { - &*(self.section.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue) - } + unsafe { &*(self.section.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue) } } } @@ -553,9 +430,7 @@ impl<'a> IndexMut for HeapWriter<'a> { #[inline] fn index_mut(&mut self, idx: usize) -> &mut Self::Output { debug_assert!(heap_index!(idx) < *self.heap_byte_len); - unsafe { - &mut *(self.section.heap_ptr.add(heap_index!(idx)) as *mut HeapCellValue) - } + unsafe { &mut *(self.section.heap_ptr.add(heap_index!(idx)) as *mut HeapCellValue) } } } @@ -564,17 +439,29 @@ impl<'a> SizedHeap for HeapWriter<'a> { self.section.cell_len() } - fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { - let (s, tail_cell_offset) = scan_slice_to_str( - unsafe { self.section.heap_ptr.add(slice_loc) }, - &self.section.pstr_vec.as_bitslice()[cell_index!(slice_loc) ..], - ); + fn scan_slice_to_str(&self, slice_loc: usize) -> HeapStringScan { + let HeapStringScan { string, tail_idx } = unsafe { + let slice = std::slice::from_raw_parts( + self.section.heap_ptr.byte_add(slice_loc), + heap_index!(self.section.heap_cell_len) - slice_loc, + ); - (s, cell_index!(slice_loc) + tail_cell_offset) + scan_slice_to_str(slice) + }; + + HeapStringScan { + string, + tail_idx: cell_index!(slice_loc) + tail_idx, + } } - fn pstr_at(&self, cell_offset: usize) -> bool { - self.section.pstr_vec[cell_offset] + fn as_slice(&self) -> &[u8] { + unsafe { + std::slice::from_raw_parts( + self.section.heap_ptr, + heap_index!(self.section.heap_cell_len), + ) + } } } @@ -588,20 +475,23 @@ impl Heap { byte_len: 0, byte_cap: 0, }, - pstr_vec: bitvec![], resource_err_loc: 0, } } + // takes a heap index, returns a cell index + #[inline] + pub const fn pstr_tail_idx(pstr_zero_byte_loc: usize) -> usize { + if (pstr_zero_byte_loc + 1) % Heap::heap_cell_alignment() == 0 { + cell_index!(pstr_zero_byte_loc) + 2 + } else { + cell_index!(pstr_zero_byte_loc) + 1 + } + } + #[inline(always)] unsafe fn grow(&mut self) -> bool { - let result = self.inner.grow(); - - if result { - self.pstr_vec.reserve(cell_index!(self.inner.byte_cap)); - } - - result + self.inner.grow() } #[inline] @@ -624,7 +514,7 @@ impl Heap { byte_len: 0, byte_cap: heap_index!(cap), }, - pstr_vec: bitvec![], + // pstr_vec: bitvec![], resource_err_loc: 0, }) } @@ -641,7 +531,6 @@ impl Heap { section = ReservedHeapSection { heap_ptr: self.inner.ptr, heap_cell_len: self.cell_len(), - pstr_vec: &mut self.pstr_vec, }; break; } else if !self.grow() { @@ -656,28 +545,42 @@ impl Heap { }) } - pub(crate) fn last_cell_mut(&mut self) -> Option<&mut HeapCellValue> { - if self.inner.byte_len == 0 { - None - } else { - unsafe { - Some(&mut *(self.inner.ptr.add(self.inner.byte_len - heap_index!(1)) - as *mut HeapCellValue)) - } - } - } - pub(crate) fn last_cell(&mut self) -> Option { if self.inner.byte_len == 0 { None } else { unsafe { - Some(ptr::read(self.inner.ptr.add(self.inner.byte_len - heap_index!(1)) - as *const HeapCellValue)) + Some(ptr::read( + self.inner.ptr.add(self.inner.byte_len - heap_index!(1)) + as *const HeapCellValue, + )) } } } + pub(crate) fn append(&mut self, other_heap: &impl SizedHeap) -> Result<(), usize> { + let other_len = heap_index!(other_heap.cell_len()); + + loop { + if self.free_space() >= other_len { + let heap_slice = unsafe { + std::slice::from_raw_parts_mut( + self.inner.ptr.add(self.inner.byte_len), + other_len, + ) + }; + + heap_slice.copy_from_slice(other_heap.as_slice()); + self.inner.byte_len += heap_index!(other_heap.cell_len()); + break; + } else if unsafe { !self.grow() } { + return Err(self.resource_error_offset()); + } + } + + Ok(()) + } + #[inline] pub(crate) fn is_empty(&self) -> bool { self.inner.byte_len == 0 @@ -703,31 +606,31 @@ impl Heap { self.inner.byte_len = 0; self.inner.byte_cap = 0; - self.pstr_vec.clear(); + // self.pstr_vec.clear(); } - pub(crate) fn append(&mut self, heap_slice: HeapView) -> Result<(), usize> { - unsafe { - loop { - if self.free_space() >= heap_index!(heap_slice.slice_cell_len) { - ptr::copy_nonoverlapping( - heap_slice.slice, - self.inner.ptr.add(self.inner.byte_len), - heap_index!(heap_slice.slice_cell_len), - ); + // pub(crate) fn append(&mut self, heap_slice: HeapView) -> Result<(), usize> { + // unsafe { + // loop { + // if self.free_space() >= heap_index!(heap_slice.slice_cell_len) { + // ptr::copy_nonoverlapping( + // heap_slice.slice, + // self.inner.ptr.add(self.inner.byte_len), + // heap_index!(heap_slice.slice_cell_len), + // ); - self.inner.byte_len += heap_index!(heap_slice.slice_cell_len); - self.pstr_vec.extend(heap_slice.pstr_slice.iter()); + // self.inner.byte_len += heap_index!(heap_slice.slice_cell_len); + // // self.pstr_vec.extend(heap_slice.pstr_slice.iter()); - break; - } else if !self.grow() { - return Err(self.resource_error_offset()); - } - } - } + // break; + // } else if !self.grow() { + // return Err(self.resource_error_offset()); + // } + // } + // } - Ok(()) - } + // Ok(()) + // } pub(crate) fn store_resource_error(&mut self) { RESOURCE_ERROR_OFFSET_INIT.call_once(move || { @@ -763,11 +666,23 @@ impl Heap { for ((idx, c1), c2) in str1.char_indices().zip(str2.chars()) { if c1 == '\u{0}' && c2 == '\u{0}' { - return PStrSegmentCmpResult::BothMatch { pstr_loc1, pstr_loc2, null_offset: idx }; + return PStrSegmentCmpResult::BothMatch { + pstr_loc1, + pstr_loc2, + null_offset: idx, + }; } else if c1 == '\u{0}' { - return PStrSegmentCmpResult::FirstMatch { pstr_loc1, pstr_loc2, l1_offset: idx }; + return PStrSegmentCmpResult::FirstMatch { + pstr_loc1, + pstr_loc2, + l1_offset: idx, + }; } else if c2 == '\u{0}' { - return PStrSegmentCmpResult::SecondMatch { pstr_loc1, pstr_loc2, l2_offset: idx }; + return PStrSegmentCmpResult::SecondMatch { + pstr_loc1, + pstr_loc2, + l2_offset: idx, + }; } else if c1 != c2 { return PStrSegmentCmpResult::Mismatch { c1, c2 }; } @@ -822,7 +737,7 @@ impl Heap { // - Invariant: from `InnerHeap`, `self.inner.byte_cap < isize::MAX`. let cell_ptr = (self.inner.ptr as *mut HeapCellValue).add(self.cell_len()); cell_ptr.write(cell); - self.pstr_vec.push(false); + // self.pstr_vec.push(false); self.inner.byte_len += heap_index!(1); } @@ -866,6 +781,7 @@ impl Heap { Range { start, end } } + /* pub(crate) fn splice>( &self, range: R, @@ -876,7 +792,7 @@ impl Heap { slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, cell_offset: range.start, slice_cell_len: range.end - range.start, - pstr_slice: &self.pstr_vec.as_bitslice()[range], + // pstr_slice: &self.pstr_vec.as_bitslice()[range], } } @@ -890,9 +806,10 @@ impl Heap { slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, cell_offset: range.start, slice_cell_len: range.end - range.start, - pstr_slice: &self.pstr_vec.as_bitslice()[range], + // pstr_slice: &self.pstr_vec.as_bitslice()[range], } } + */ pub fn allocate_pstr(&mut self, src: &str) -> Result, usize> { let size_in_heap = Self::compute_pstr_size(src); @@ -911,39 +828,18 @@ impl Heap { }) } - const fn heap_cell_alignment() -> usize { + pub const fn heap_cell_alignment() -> usize { // yes, size_of, not align_of. the alignment of HeapCellValue // is 1 byte. In the heap, though, its alignment must be its // size. - mem::size_of::() - } - - // takes a byte offset into the Heap ptr. - #[inline(always)] - pub(crate) const fn neighboring_cell_offset(offset: usize) -> usize { - cell_index!((offset & !(ALIGN - 1)) + ALIGN) - } - - #[inline] - pub(crate) fn iter(&self) -> HeapView { - HeapView { - slice: self.inner.ptr, - cell_offset: 0, - slice_cell_len: cell_index!(self.inner.byte_len), - pstr_slice: &self.pstr_vec.as_bitslice(), - } - } - - #[inline] - pub(crate) fn pstr_vec(&self) -> &BitSlice { - self.pstr_vec.as_bitslice() + size_of::() } #[inline] pub(crate) fn char_at(&self, byte_idx: usize) -> char { let s = unsafe { let char_ptr = self.inner.ptr.add(byte_idx); - let slice = std::slice::from_raw_parts(char_ptr, mem::size_of::()); + let slice = std::slice::from_raw_parts(char_ptr, size_of::()); std::str::from_utf8_unchecked(&slice) }; @@ -961,7 +857,7 @@ impl Heap { let succ_len = loc + c.len_utf8(); if chars_iter.next() == Some('\u{0}') { - (c, heap_loc_as_cell!(Self::neighboring_cell_offset(succ_len))) + (c, heap_loc_as_cell!(Self::pstr_tail_idx(succ_len))) } else { (c, pstr_loc_as_cell!(succ_len)) } @@ -971,8 +867,8 @@ impl Heap { // copies only the string, not its tail. returns the cell index of // the tail location pub(crate) fn copy_pstr_within(&mut self, pstr_loc: usize) -> Result { - let (s, tail_loc) = self.scan_slice_to_str(pstr_loc); - let s_len = s.len(); + let HeapStringScan { string, tail_idx } = self.scan_slice_to_str(pstr_loc); + let s_len = string.len(); let align_offset = pstr_sentinel_length(s_len); let copy_size = s_len + align_offset; @@ -980,15 +876,10 @@ impl Heap { unsafe { loop { if self.free_space() >= copy_size { - let slice = std::slice::from_raw_parts_mut( - self.inner.ptr, - self.inner.byte_len + s_len, - ); + let slice = + std::slice::from_raw_parts_mut(self.inner.ptr, self.inner.byte_len + s_len); - slice.copy_within( - pstr_loc .. pstr_loc + s_len, - self.inner.byte_len, - ); + slice.copy_within(pstr_loc..pstr_loc + s_len, self.inner.byte_len); ptr::write_bytes( self.inner.ptr.add(self.inner.byte_len + s_len), @@ -996,8 +887,17 @@ impl Heap { align_offset, ); - self.inner.byte_len += copy_size; - self.pstr_vec.resize(self.cell_len(), true); + if align_offset == 1 { + ptr::write_bytes( + self.inner.ptr.add(self.inner.byte_len + copy_size), + 0u8, + size_of::(), + ); + + self.inner.byte_len += copy_size + heap_index!(1); + } else { + self.inner.byte_len += copy_size; + } break; } else if !self.grow() { @@ -1006,7 +906,7 @@ impl Heap { } } - Ok(tail_loc) + Ok(tail_idx) } // src is a cell-indexed range. @@ -1023,7 +923,7 @@ impl Heap { heap_index!(len), ); - self.pstr_vec.resize(self.cell_len() + len, false); + // self.pstr_vec.resize(self.cell_len() + len, false); self.inner.byte_len += heap_index!(len); break; @@ -1059,10 +959,14 @@ impl Heap { byte_size += null_idx + pstr_sentinel_length(null_idx); + // each partial string must be buffered from its tail cell + // by at least two null bytes so one of them may be used + // to mark partial strings e.g. during iteration + if (null_idx + 1) % ALIGN == 0 { - byte_size += 2 * mem::size_of::(); + byte_size += 2 * size_of::(); } else { - byte_size += mem::size_of::(); + byte_size += size_of::(); } if null_idx + 1 >= src.len() { @@ -1082,13 +986,13 @@ impl Heap { while idx < functor.len() { match &functor[idx] { &FunctorElement::InnerFunctor(inner_cell_size, ref _inner_functor) => { - byte_size += inner_cell_size as usize * mem::size_of::(); + byte_size += inner_cell_size as usize * size_of::(); } FunctorElement::AbsoluteCell(_cell) | FunctorElement::Cell(_cell) => { - byte_size += mem::size_of::(); + byte_size += size_of::(); } &FunctorElement::String(cell_len, _) => { - byte_size += cell_len as usize * mem::size_of::(); + byte_size += cell_len as usize * size_of::(); } } @@ -1120,12 +1024,10 @@ impl Heap { #[inline] pub(crate) fn truncate(&mut self, cell_offset: usize) { self.inner.byte_len = heap_index!(cell_offset); - self.pstr_vec.truncate(cell_offset); + // self.pstr_vec.truncate(cell_offset); } } - - pub(crate) struct PStrSegmentIter<'a> { string_buf: &'a str, } @@ -1153,7 +1055,7 @@ impl<'a> Iterator for PStrSegmentIter<'a> { if c == '\u{0}' { None } else { - self.string_buf = &self.string_buf[c.len_utf8() ..]; + self.string_buf = &self.string_buf[c.len_utf8()..]; Some(c) } }) @@ -1187,14 +1089,15 @@ pub trait SizedHeap: Index { fn cell_len(&self) -> usize; // return a pointer to the heap string and the cell index of its tail - fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize); + fn scan_slice_to_str<'a>(&'a self, slice_loc: usize) -> HeapStringScan<'a>; + + fn as_slice(&self) -> &[u8]; // return true iff a partial string is stored at cell_offset. - fn pstr_at(&self, cell_offset: usize) -> bool; + // fn pstr_at(&self, cell_offset: usize) -> bool; } -pub trait SizedHeapMut: IndexMut + SizedHeap { -} +pub trait SizedHeapMut: IndexMut + SizedHeap {} impl Index for Heap { type Output = HeapCellValue; @@ -1215,62 +1118,29 @@ impl SizedHeap for Heap { self.cell_len() } - fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { - let (s, tail_cell_offset) = scan_slice_to_str( - unsafe { self.inner.ptr.add(slice_loc) }, - &self.pstr_vec.as_bitslice()[cell_index!(slice_loc) ..], - ); + fn scan_slice_to_str<'a>(&'a self, slice_loc: usize) -> HeapStringScan<'a> { + let HeapStringScan { string, tail_idx } = unsafe { + let slice = std::slice::from_raw_parts( + self.inner.ptr.add(slice_loc), + self.inner.byte_len - slice_loc, + ); - (s, cell_index!(slice_loc) + tail_cell_offset) + scan_slice_to_str(slice) + }; + + HeapStringScan { + string, + tail_idx: cell_index!(slice_loc) + tail_idx, + } } - fn pstr_at(&self, cell_offset: usize) -> bool { - self.pstr_vec[cell_offset] + fn as_slice(&self) -> &[u8] { + unsafe { std::slice::from_raw_parts(self.inner.ptr, self.inner.byte_len) } } } impl SizedHeapMut for Heap {} -impl<'a> SizedHeap for HeapView<'a> { - fn cell_len(&self) -> usize { - self.slice_cell_len - } - - fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { - let (s, tail_cell_offset) = scan_slice_to_str( - unsafe { self.slice.add(slice_loc) }, - &self.pstr_slice[cell_index!(slice_loc) ..], - ); - - (s, cell_index!(slice_loc) + tail_cell_offset) - } - - fn pstr_at(&self, cell_offset: usize) -> bool { - self.pstr_slice[cell_offset] - } -} - -impl<'a> SizedHeap for HeapViewMut<'a> { - fn cell_len(&self) -> usize { - self.slice_cell_len - } - - fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { - let (s, tail_cell_offset) = scan_slice_to_str( - unsafe { self.slice.add(slice_loc) }, - &self.pstr_slice[cell_index!(slice_loc) ..], - ); - - (s, cell_index!(slice_loc) + tail_cell_offset) - } - - fn pstr_at(&self, cell_offset: usize) -> bool { - self.pstr_slice[cell_offset] - } -} - -impl<'a> SizedHeapMut for HeapViewMut<'a> {} - // sometimes we need to dereference variables that are found only in // the heap without access to the full WAM (e.g., while detecting // cycles in terms), and which therefore may only point other cells in @@ -1307,9 +1177,10 @@ pub fn heap_bound_store(heap: &impl SizedHeap, value: HeapCellValue) -> HeapCell } #[allow(dead_code)] -pub fn print_heap_terms<'a, I: Iterator>(heap: I, h: usize) { - for (index, term) in heap.enumerate() { - println!("{} : {:?}", h + index, term); +pub fn print_heap_terms(heap: &Heap, h: usize) { + for idx in 0..heap.cell_len() { + let term = heap[idx]; + println!("{} : {:?}", h + idx, term); } } diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index 90725d61..c139bc12 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -1,4 +1,3 @@ -use std::cmp::Ordering; use std::collections::BTreeMap; use crate::atom_table; @@ -442,7 +441,7 @@ impl Iterator for QueryState<'_> { if let Err(resource_err_loc) = machine .machine_st .heap - .append(machine.machine_st.ball.stub.splice(..)) + .append(&machine.machine_st.ball.stub) { return Some(Err(Term::from_heapcell( machine, @@ -530,10 +529,10 @@ impl Machine { /// Consults a module into the [`Machine`] from a string. pub fn consult_module_string(&mut self, module_name: &str, program: impl Into) { let stream = Stream::from_owned_string(program.into(), &mut self.machine_st.arena); - self.machine_st.registers[1] = stream.into(); - self.machine_st.registers[2] = atom_as_cell!(&atom_table::AtomTable::build_with( + self.machine_st.registers[1] = stream_as_cell!(stream); + self.machine_st.registers[2] = atom_as_cell!(atom_table::AtomTable::build_with( &self.machine_st.atom_tbl, - module_name + module_name, )); self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2)); diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 34499ced..0d850150 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -27,15 +27,14 @@ impl TermWriteResult { heap[0] = value; - let inverse_var_locs = inverse_var_locs_from_iter( - stackful_preorder_iter::( - heap, - &mut stack, - 0, - ), - ); + let inverse_var_locs = inverse_var_locs_from_iter(stackful_preorder_iter::( + heap, &mut stack, 0, + )); - Ok(Self { focus, inverse_var_locs }) + Ok(Self { + focus, + inverse_var_locs, + }) } } @@ -529,9 +528,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target); let mut term = load_state.term_stream.next(&composite_op_dir)?; - let predicate_focus_opt = load_state.predicates.first().map(|term_write_result| { - term_write_result.focus - }); + let predicate_focus_opt = load_state + .predicates + .first() + .map(|term_write_result| term_write_result.focus); let machine_st = LS::machine_st(&mut self.payload); let term_key_opt = clause_predicate_key(&machine_st.heap, term.focus); @@ -1072,10 +1072,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let cell = machine_st[r]; let focus = machine_st.heap.cell_len(); - machine_st.heap.push_cell(cell) + machine_st + .heap + .push_cell(cell) .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - let export_list = FocusedHeapRefMut { heap: &mut machine_st.heap, focus }; + let export_list = FocusedHeapRefMut { + heap: &mut machine_st.heap, + focus, + }; let export_list = setup_module_export_list(export_list)?; Ok(export_list.into_iter().collect()) @@ -1129,8 +1134,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } ); - Ok(TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus)) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?) + Ok( + TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus)) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?, + ) } fn add_extensible_predicate_declaration( @@ -1628,18 +1635,15 @@ impl Machine { }; let value = self.machine_st.registers[2]; - let term = resource_error_call_result!( + let term = resource_error_call_result!( self.machine_st, TermWriteResult::from(&mut self.machine_st.heap, value) ); let add_clause = || { let indexing_arg_opt = match term_predicate_key(&self.machine_st.heap, term.focus) { - Some((atom!(":-"), _)) => { - term_nth_arg(&self.machine_st.heap, term.focus, 1).and_then(|h| { - term_nth_arg(&self.machine_st.heap, h, 1) - }) - } + Some((atom!(":-"), _)) => term_nth_arg(&self.machine_st.heap, term.focus, 1) + .and_then(|h| term_nth_arg(&self.machine_st.heap, h, 1)), Some(_) => term_nth_arg(&self.machine_st.heap, term.focus, 1), None => None, }; @@ -2240,9 +2244,11 @@ impl Machine { }; let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); - let predicate_focus_opt = loader.payload.predicates.first().map(|term_write_result| { - term_write_result.focus - }); + let predicate_focus_opt = loader + .payload + .predicates + .first() + .map(|term_write_result| term_write_result.focus); let is_consistent = if let Some(predicate_focus) = predicate_focus_opt { let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload); @@ -2253,7 +2259,7 @@ impl Machine { LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = (!loader.payload.predicates.is_empty() - && loader.payload.predicates.compilation_target != compilation_target) + && loader.payload.predicates.compilation_target != compilation_target) || !is_consistent; let result = LiveLoadAndMachineState::evacuate(loader); diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 5017cb78..1a4e8487 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -187,7 +187,11 @@ impl PermissionError for HeapCellValue { let stub = functor!( atom!("permission_error"), - [atom_as_cell((perm.as_atom())), atom_as_cell(index_atom), cell(cell)] + [ + atom_as_cell((perm.as_atom())), + atom_as_cell(index_atom), + cell(cell) + ] ); MachineError { @@ -226,7 +230,10 @@ pub(super) trait DomainError { impl DomainError for HeapCellValue { fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { - let stub = functor!(atom!("domain_error"), [atom_as_cell((error.as_atom())), cell(self)]); + let stub = functor!( + atom!("domain_error"), + [atom_as_cell((error.as_atom())), cell(self)] + ); MachineError { stub, @@ -239,7 +246,10 @@ impl DomainError for Number { fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { let stub = functor!( atom!("domain_error"), - [atom_as_cell((error.as_atom())), number(self, (&mut machine_st.arena))] + [ + atom_as_cell((error.as_atom())), + number(self, (&mut machine_st.arena)) + ] ); MachineError { @@ -280,7 +290,10 @@ impl MachineState { } pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError { - let stub = functor!(atom!("evaluation_error"), [atom_as_cell((eval_error.as_atom()))]); + let stub = functor!( + atom!("evaluation_error"), + [atom_as_cell((eval_error.as_atom()))] + ); MachineError { stub, @@ -297,7 +310,10 @@ impl MachineState { ) } ResourceError::OutOfFiles => { - functor!(atom!("resource_error"), [atom_as_cell((atom!("file_descriptors")))]) + functor!( + atom!("resource_error"), + [atom_as_cell((atom!("file_descriptors")))] + ) } }; @@ -480,12 +496,12 @@ impl MachineState { SessionError::CannotOverwriteBuiltIn(key) => self.permission_error( Permission::Modify, atom!("static_procedure"), - functor_stub(key.0, key.1) + functor_stub(key.0, key.1), ), SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error( Permission::Modify, atom!("static_procedure"), - functor_stub(key.0, key.1) + functor_stub(key.0, key.1), ), SessionError::CannotOverwriteBuiltInModule(module) => { self.permission_error(Permission::Modify, atom!("static_module"), module) @@ -559,14 +575,14 @@ impl MachineState { let stub = functor!(atom!("syntax_error"), [functor(stub)]); - MachineError { - stub, - location, - } + MachineError { stub, location } } pub(super) fn representation_error(&self, flag: RepFlag) -> MachineError { - let stub = functor!(atom!("representation_error"), [atom_as_cell((flag.as_atom()))]); + let stub = functor!( + atom!("representation_error"), + [atom_as_cell((flag.as_atom()))] + ); MachineError { stub, @@ -593,13 +609,19 @@ impl MachineState { } pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub { - if let Some(ParserErrorSrc { line_num, .. }) = err.location { - functor!(atom!("error"), [functor((err.stub)), - functor((atom!(":")), [functor(src), - number(line_num, (&mut self.arena))])]) + if let Some(ParserErrorSrc { line_num, .. }) = err.location { + functor!( + atom!("error"), + [ + functor((err.stub)), + functor( + (atom!(":")), + [functor(src), number(line_num, (&mut self.arena))] + ) + ] + ) } else { - functor!(atom!("error"), [functor((err.stub)), - functor(src)]) + functor!(atom!("error"), [functor((err.stub)), functor(src)]) } } @@ -826,13 +848,29 @@ impl EvalError { // used by '$skip_max_list'. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CycleSearchResult { - Cyclic { lambda: usize }, // number of steps + Cyclic { + lambda: usize, + }, // number of steps EmptyList, - NotList { num_steps: usize, heap_loc: HeapCellValue }, - PartialList { num_steps: usize, heap_loc: HeapCellValue }, - ProperList { num_steps: usize }, - PStrLocation { num_steps: usize, pstr_loc: HeapCellValue }, - UntouchedList { num_steps: usize, list_loc: usize }, + NotList { + num_steps: usize, + heap_loc: HeapCellValue, + }, + PartialList { + num_steps: usize, + heap_loc: HeapCellValue, + }, + ProperList { + num_steps: usize, + }, + PStrLocation { + num_steps: usize, + pstr_loc: HeapCellValue, + }, + UntouchedList { + num_steps: usize, + list_loc: usize, + }, } impl MachineState { @@ -856,7 +894,9 @@ impl MachineState { }; match BrentAlgState::detect_cycles(&self.heap, sorted) { - CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } if !sorted.is_var() => { + CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } + if !sorted.is_var() => + { let err = self.type_error(ValidType::List, sorted); Err(self.error_form(err, stub_gen())) } @@ -868,7 +908,9 @@ impl MachineState { let stub_gen = || functor_stub(atom!("keysort"), 2); match BrentAlgState::detect_cycles(&self.heap, list) { - CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } if !list.is_var() => { + CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } + if !list.is_var() => + { let err = self.type_error(ValidType::List, list); Err(self.error_form(err, stub_gen())) } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index b5fdc1c0..dcf7a920 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -37,7 +37,7 @@ pub(super) enum MachineMode { pub(super) enum HeapPtr { HeapCell(usize), PStr(usize), // Char(usize), - // PStrLocation(usize), + // PStrLocation(usize), } impl Default for HeapPtr { @@ -215,7 +215,8 @@ fn push_var_eq_functors( let mut writer = heap.reserve(1 + 5 * size)?; writer.write_with(|section| { - for (var_loc, var) in iter { // (var, binding) in iter { + for (var_loc, var) in iter { + // (var, binding) in iter { let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); let binding = heap_loc_as_cell!(var_loc); @@ -224,7 +225,7 @@ fn push_var_eq_functors( section.push_cell(binding); } - for idx in 0 .. size { + for idx in 0..size { section.push_cell(list_loc_as_cell!(section.cell_len() + 1)); section.push_cell(str_loc_as_cell!(src_h + 3 * idx)); } @@ -252,6 +253,7 @@ pub(crate) fn copy_and_align_iter>( #[derive(Debug)] pub struct Ball { pub(super) boundary: usize, + pub(super) pstr_boundary: usize, pub(super) stub: Heap, } @@ -259,12 +261,14 @@ impl Ball { pub(super) fn new() -> Self { Ball { boundary: 0, + pstr_boundary: 0, stub: Heap::new(), } } pub(super) fn reset(&mut self) { self.boundary = 0; + self.pstr_boundary = 0; self.stub.clear(); } @@ -272,10 +276,23 @@ impl Ball { let h = dest.cell_len(); let diff = self.boundary as i64 - h as i64; - dest.append(self.stub.splice(..))?; + let mut dest_writer = dest.reserve(self.stub.cell_len())?; - for cell in &mut dest.splice_mut(h ..) { - *cell = *cell - diff; + dest_writer.write_with(|section| { + for idx in 0..self.pstr_boundary { + section.push_cell(self.stub[idx] - diff); + } + }); + + let mut pstr_threshold = heap_index!(self.pstr_boundary); + + while pstr_threshold < heap_index!(self.stub.cell_len()) { + let HeapStringScan { string, tail_idx } = self.stub.scan_slice_to_str(pstr_threshold); + + pstr_threshold += dest_writer.write_with(|section| { + section.push_pstr(string).unwrap(); + section.push_cell(self.stub[tail_idx] - diff); + }); } Ok(h) @@ -335,32 +352,16 @@ impl<'a> CopierTarget for CopyTerm<'a> { self.state.heap.cell_len() } + #[inline(always)] + fn as_slice_from<'b>(&'b self, from: usize) -> Box + 'b> { + Box::new(self.state.heap.as_slice()[from..].iter().cloned()) + } + #[inline(always)] fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result { self.state.heap.copy_pstr_within(pstr_loc) } - #[inline(always)] - fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize { - self.state.heap.pstr_vec()[0 .. cell_index!(pstr_loc)] - .last_zero() - .map(|idx| idx + 1) - .unwrap_or(0) - } - - #[inline(always)] - fn pstr_at(&self, loc: usize) -> bool { - self.state.heap.pstr_vec()[loc] - } - - #[inline(always)] - fn next_non_pstr_cell_index(&self, loc: usize) -> usize { - // unwrap is safe here because a partial string is always - // followed by a tail cell, i.e. a non-pstr cell, supposing - // self.state.heap[loc] is a pstr cell - self.state.heap.pstr_vec()[loc ..].first_zero().unwrap() - } - #[inline(always)] fn reserve(&mut self, num_cells: usize) -> Result { self.state.heap.reserve(num_cells) @@ -469,9 +470,22 @@ impl<'a> CopierTarget for CopyBallTerm<'a> { fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result { debug_assert!(pstr_loc < self.heap.byte_len()); - let (string, tail_loc) = self.heap.scan_slice_to_str(pstr_loc); + let HeapStringScan { string, tail_idx } = self.heap.scan_slice_to_str(pstr_loc); self.stub.allocate_pstr(string)?; - Ok(tail_loc) + Ok(tail_idx) + } + + fn as_slice_from<'b>(&'b self, from: usize) -> Box + 'b> { + if from < self.heap.byte_len() { + Box::new( + self.heap.as_slice()[from..] + .iter() + .cloned() + .chain(self.stub.as_slice().iter().cloned()), + ) + } else { + Box::new(self.stub.as_slice()[from..].iter().cloned()) + } } #[inline] @@ -479,41 +493,6 @@ impl<'a> CopierTarget for CopyBallTerm<'a> { self.stub.reserve(num_cells) } - #[inline] - fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize { - if pstr_loc >= self.heap.byte_len() { - self.stub.pstr_vec()[0 .. cell_index!(pstr_loc - self.heap.byte_len())] - .last_zero() - .map(|idx| idx + 1) - .unwrap_or(0) - } else { - self.heap.pstr_vec()[0 .. cell_index!(pstr_loc)] - .last_zero() - .map(|idx| idx + 1) - .unwrap_or(0) - } - } - - #[inline] - fn pstr_at(&self, loc: usize) -> bool { - if loc >= self.heap.cell_len() { - self.stub.pstr_vec()[loc - self.heap.cell_len()] - } else { - self.heap.pstr_vec()[loc] - } - } - - #[inline] - fn next_non_pstr_cell_index(&self, loc: usize) -> usize { - let zero_from_loc = if loc >= self.heap.cell_len() { - self.stub.pstr_vec()[loc - self.heap.cell_len() ..].first_zero().unwrap() - } else { - self.heap.pstr_vec()[loc ..].first_zero().unwrap() - }; - - zero_from_loc + loc - } - fn copy_slice_to_end(&mut self, bounds: Range) -> Result<(), usize> { let len = bounds.end - bounds.start; let mut stub_writer = self.stub.reserve(len)?; @@ -699,9 +678,9 @@ impl MachineState { push_var_eq_functors( &mut self.heap, var_list.len(), - var_list.iter().map(|(var_name, var, _)| { - (var.get_value() as usize, var_name.clone()) - }), + var_list + .iter() + .map(|(var_name, var, _)| { (var.get_value() as usize, var_name.clone()) }), &self.atom_tbl, ) ); @@ -737,7 +716,9 @@ impl MachineState { let mut singleton_var_set: IndexMap = IndexMap::new(); - for cell in stackful_preorder_iter::(&mut self.heap, &mut self.stack, term.focus) { + for cell in + stackful_preorder_iter::(&mut self.heap, &mut self.stack, term.focus) + { let cell = unmark_cell_bits!(cell); if let Some(var) = cell.as_var() { @@ -756,9 +737,10 @@ impl MachineState { singleton_var_set .iter() .filter(|(var, is_singleton)| { - **is_singleton && term.inverse_var_locs.contains_key( - &(var.get_value() as usize) - ) + **is_singleton + && term + .inverse_var_locs + .contains_key(&(var.get_value() as usize)) }) .count(), term.inverse_var_locs @@ -873,7 +855,8 @@ impl MachineState { CompilationError::ParserError(e) if e.is_unexpected_eof() => { match eof_handler(self, stream)? { OnEOF::Return => { - return self.write_read_term_options(vec![], empty_list_as_cell!()); + return self + .write_read_term_options(vec![], empty_list_as_cell!()); } OnEOF::Continue => continue, } @@ -1012,11 +995,9 @@ impl MachineState { let term_loc = self.heap.cell_len(); - step_or_resource_error!( - self, - self.heap.push_cell(term_to_be_printed), - { return Ok(None); } - ); + step_or_resource_error!(self, self.heap.push_cell(term_to_be_printed), { + return Ok(None); + }); let mut printer = HCPrinter::new( &mut self.heap, diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 34fbe5ca..a7dc5d9e 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -327,9 +327,9 @@ impl MachineState { self.ball.reset(); let addr = self.registers[1]; - let ball_boundary = self.heap.cell_len(); - step_or_resource_error!( + self.ball.boundary = self.heap.cell_len(); + self.ball.pstr_boundary = step_or_resource_error!( self, copy_term( CopyBallTerm::new( @@ -342,8 +342,6 @@ impl MachineState { AttrVarPolicy::DeepCopy, ) ); - - self.ball.boundary = ball_boundary; } #[inline(always)] @@ -359,14 +357,14 @@ impl MachineState { HeapPtr::PStr(h) => { let mut char_iter = self.heap.char_iter(h); - if self.s_offset == 0 { // read the car of the list + if self.s_offset == 0 { + // read the car of the list let c = char_iter.next().unwrap(); char_as_cell!(c) - } else { // read the (self.s_offset)^{th} cdr of the list - let byte_offset: usize = char_iter - .take(self.s_offset) - .map(|c| c.len_utf8()) - .sum(); + } else { + // read the (self.s_offset)^{th} cdr of the list + let byte_offset: usize = + char_iter.take(self.s_offset).map(|c| c.len_utf8()).sum(); let new_h = h + byte_offset; self.s_offset = 0; @@ -375,7 +373,7 @@ impl MachineState { self.s = HeapPtr::PStr(new_h); pstr_loc_as_cell!(new_h) } else { - let h = Heap::neighboring_cell_offset(new_h); + let h = Heap::pstr_tail_idx(new_h); self.s = HeapPtr::HeapCell(h); self.deref(heap_loc_as_cell!(h)) } @@ -946,7 +944,7 @@ impl MachineState { if char_iter.next().is_some() { unify_fn!(*self, pstr_loc_as_cell!(pstr_loc + c.len_utf8()), a3); } else { - let tail_idx = Heap::neighboring_cell_offset(pstr_loc); + let tail_idx = Heap::pstr_tail_idx(pstr_loc); unify_fn!(*self, self.heap[tail_idx]); } @@ -1044,7 +1042,12 @@ impl MachineState { } } - fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) -> Result<(), usize> { + fn try_functor_fabricate_struct( + &mut self, + name: Atom, + arity: usize, + r: Ref, + ) -> Result<(), usize> { let h = self.heap.cell_len(); let mut writer = self.heap.reserve(arity + 1)?; @@ -1144,7 +1147,7 @@ impl MachineState { }; read_heap_cell!(store_name, - (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // HeapCellValueTag::Char | + (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // HeapCellValueTag::Char | HeapCellValueTag::F64) if arity == 0 => { self.bind(a1.as_var().unwrap(), deref_name); } diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index e0551a60..71f74f0c 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -51,14 +51,12 @@ impl MockWAM { ) -> Result { let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?; - print_heap_terms(self.machine_st.heap.splice(..), term_write_result.focus); + print_heap_terms(&self.machine_st.heap, term_write_result.focus); let var_names = term_write_result .inverse_var_locs .iter() - .map(|(var_loc, var_name)| { - (self.machine_st.heap[*var_loc], var_name.clone()) - }) + .map(|(var_loc, var_name)| (self.machine_st.heap[*var_loc], var_name.clone())) .collect(); let mut printer = HCPrinter::new( @@ -90,6 +88,7 @@ pub struct TermCopyingMockWAM<'a> { impl<'a> Index for TermCopyingMockWAM<'a> { type Output = HeapCellValue; + #[inline] fn index(&self, index: usize) -> &HeapCellValue { &self.wam.machine_st.heap[index] } @@ -107,6 +106,7 @@ impl<'a> IndexMut for TermCopyingMockWAM<'a> { impl<'a> Deref for TermCopyingMockWAM<'a> { type Target = MockWAM; + #[inline] fn deref(&self) -> &Self::Target { self.wam } @@ -114,6 +114,7 @@ impl<'a> Deref for TermCopyingMockWAM<'a> { #[cfg(test)] impl<'a> DerefMut for TermCopyingMockWAM<'a> { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.wam } @@ -170,26 +171,8 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> { } #[inline(always)] - fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize { - self.wam.machine_st.heap.pstr_vec()[0 .. cell_index!(pstr_loc)] - .last_zero() - .map(|idx| idx + 1) - .unwrap_or(0) - } - - #[inline(always)] - fn pstr_at(&self, loc: usize) -> bool { - self.wam.machine_st.heap.pstr_vec()[loc] - } - - #[inline(always)] - fn next_non_pstr_cell_index(&self, loc: usize) -> usize { - // unwrap is safe here because a partial string is always - // followed by a tail cell, i.e. a non-pstr cell, supposing - // self.machine_st.heap[loc] is a pstr cell - self.wam.machine_st.heap.pstr_vec()[loc ..].first_zero() - .map(|idx| idx + loc) - .unwrap() + fn as_slice_from<'b>(&'b self, from: usize) -> Box + 'b> { + Box::new(self.wam.machine_st.heap.as_slice()[from..].iter().cloned()) } #[inline(always)] @@ -204,20 +187,9 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> { } #[cfg(test)] -pub fn all_cells_marked_and_unforwarded(iter: impl SizedHeap) { - let mut idx = 0; - let cell_len = iter.cell_len(); - - while idx < cell_len { - let curr_idx = idx; - let cell = if iter.pstr_at(idx) { - let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx)); - idx = last_cell_loc; - iter[last_cell_loc - 1] - } else { - idx += 1; - iter[curr_idx] - }; +pub fn all_cells_marked_and_unforwarded(heap: &Heap, offset: usize) { + for curr_idx in offset..heap.cell_len() { + let cell = heap[curr_idx]; assert!( cell.get_mark_bit(), @@ -235,43 +207,21 @@ pub fn all_cells_marked_and_unforwarded(iter: impl SizedHeap) { } #[cfg(test)] -pub fn unmark_all_cells(mut iter: impl SizedHeapMut) { - let mut idx = 0; - let cell_len = iter.cell_len(); - - while idx < cell_len { - if iter.pstr_at(idx) { - iter[idx].set_mark_bit(false); - - let last_cell_loc = { - let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx)); - last_cell_loc - }; - - iter[last_cell_loc].set_mark_bit(false); - idx = last_cell_loc; - } else { - iter[idx].set_mark_bit(false); - idx += 1; - } +pub fn unmark_all_cells(heap: &mut Heap, offset: usize) { + for idx in offset..heap.cell_len() { + heap[idx].set_mark_bit(false); } } #[cfg(test)] -pub fn all_cells_unmarked(iter: impl SizedHeap) { +pub fn all_cells_unmarked(iter: &impl SizedHeap) { let mut idx = 0; let cell_len = iter.cell_len(); while idx < cell_len { let curr_idx = idx; - let cell = if iter.pstr_at(idx) { - let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx)); - idx = last_cell_loc; - iter[last_cell_loc - 1] - } else { - idx += 1; - iter[curr_idx] - }; + idx += 1; + let cell = iter[curr_idx]; assert!( !cell.get_mark_bit(), @@ -354,7 +304,7 @@ mod tests { assert!(wam.fail); } - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.fail = false; wam.heap.clear(); @@ -375,7 +325,7 @@ mod tests { assert!(!wam.fail); } - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.fail = false; wam.heap.clear(); @@ -396,7 +346,7 @@ mod tests { assert!(!wam.fail); } - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.fail = false; wam.heap.clear(); @@ -417,7 +367,7 @@ mod tests { assert!(!wam.fail); } - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.fail = false; wam.heap.clear(); @@ -438,7 +388,7 @@ mod tests { assert!(!wam.fail); } - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.fail = false; wam.heap.clear(); @@ -450,7 +400,7 @@ mod tests { let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); unify!( wam, @@ -461,7 +411,7 @@ mod tests { assert!(!wam.fail); } - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.heap.clear(); @@ -489,9 +439,15 @@ mod tests { assert!(!wam.fail); + assert_eq!(wam.heap.slice_to_str(heap_index!(0), "this is a string".len()), + "this is a string"); assert_eq!(wam.heap[3], pstr_loc_as_cell!(heap_index!(8))); - - all_cells_unmarked(wam.heap.splice(..)); + assert_eq!(wam.heap.slice_to_str(heap_index!(4), "this is a string".len()), + "this is a string"); + assert_eq!(wam.heap[7], pstr_loc_as_cell!(heap_index!(8))); + assert_eq!(wam.heap.slice_to_str(heap_index!(8), "this is a string".len()), + "this is a string"); + assert_eq!(wam.heap[11], pstr_loc_as_cell!(heap_index!(8))); wam.heap.clear(); @@ -515,7 +471,7 @@ mod tests { assert!(!wam.fail); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.heap.clear(); @@ -540,7 +496,7 @@ mod tests { assert!(wam.fail); wam.fail = false; - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.heap.clear(); @@ -562,7 +518,7 @@ mod tests { unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); assert!(!wam.fail); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); } #[test] @@ -581,7 +537,7 @@ mod tests { let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); unify_with_occurs_check!( wam, @@ -632,11 +588,7 @@ mod tests { let cstr_cell = wam.allocate_cstr("string").unwrap(); assert_eq!( - compare_term_test!( - wam, - atom_as_cell!(atom!("atom")), - cstr_cell - ), + compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell), Some(Ordering::Less) ); @@ -735,11 +687,7 @@ mod tests { let cstr_cell = wam.allocate_cstr("string").unwrap(); assert_eq!( - compare_term_test!( - wam, - empty_list_as_cell!(), - cstr_cell - ), + compare_term_test!(wam, empty_list_as_cell!(), cstr_cell), Some(Ordering::Less) ); @@ -782,16 +730,13 @@ mod tests { assert!(!wam.is_cyclic_term(1)); assert!(!wam.is_cyclic_term(2)); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.heap.clear(); - let mut functor_writer = Heap::functor_writer( - functor!( - atom!("f"), - [atom_as_cell((atom!("a"))), - atom_as_cell((atom!("b")))] - ), - ); + let mut functor_writer = Heap::functor_writer(functor!( + atom!("f"), + [atom_as_cell((atom!("a"))), atom_as_cell((atom!("b")))] + )); functor_writer(&mut wam.heap).unwrap(); @@ -800,30 +745,30 @@ mod tests { assert!(!wam.is_cyclic_term(h)); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); assert!(!wam.is_cyclic_term(1)); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); assert!(!wam.is_cyclic_term(2)); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.heap[2] = str_loc_as_cell!(0); - print_heap_terms(wam.heap.iter(), 0); + print_heap_terms(&wam.heap, 0); assert!(wam.is_cyclic_term(2)); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.heap[2] = atom_as_cell!(atom!("b")); wam.heap[1] = str_loc_as_cell!(0); assert!(wam.is_cyclic_term(1)); - all_cells_unmarked(wam.heap.splice(..)); + all_cells_unmarked(&wam.heap); wam.heap.clear(); diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 06abf425..02471f25 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -508,7 +508,8 @@ impl Machine { s, )) => { cell = self.deref_register(arg); - self.machine_st.select_switch_on_term_index(cell, v, c, l, s) + self.machine_st + .select_switch_on_term_index(cell, v, c, l, s) } IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => { // let lit = self.machine_st.constant_to_literal(cell); @@ -1113,6 +1114,7 @@ impl Machine { if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { self.try_execute(name, arity, idx.get()) } else { + println!("aaand undefined!"); self.undefined_procedure(name, arity) } } else if let Some(module) = self.indices.modules.get(&module_name) { diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 6176e73a..9484bf40 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -19,9 +19,17 @@ pub struct HeapPStrIter<'a> { #[derive(Debug, Clone, Copy)] pub enum PStrCmpResult<'a> { - ListMatch { list_loc: usize }, - CompletePStrMatch { chars_matched: usize, pstr_loc: usize }, - PartialPStrMatch { string: &'a str, var_loc: usize }, + ListMatch { + list_loc: usize, + }, + CompletePStrMatch { + chars_matched: usize, + pstr_loc: usize, + }, + PartialPStrMatch { + string: &'a str, + var_loc: usize, + }, } struct PStrIterStep { @@ -81,7 +89,7 @@ impl<'a> HeapPStrIter<'a> { if s.is_empty() { return Some(PStrCmpResult::CompletePStrMatch { chars_matched, pstr_loc: h }); } else { - let next_hare = Heap::neighboring_cell_offset(h + bytes_matched); + let next_hare = Heap::pstr_tail_idx(h + bytes_matched); curr_hare = next_hare; } } @@ -179,11 +187,11 @@ impl<'a> HeapPStrIter<'a> { loop { read_heap_cell!(self.heap[curr_hare], (HeapCellValueTag::PStrLoc, h) => { - let (s, tail_loc) = self.heap.scan_slice_to_str(h); + let HeapStringScan { string, tail_idx } = self.heap.scan_slice_to_str(h); return Ok(PStrIterStep { - iteratee: PStrIteratee::PStrSlice { slice_loc: h, slice_len: s.len() }, - next_hare: tail_loc, + iteratee: PStrIteratee::PStrSlice { slice_loc: h, slice_len: string.len() }, + next_hare: tail_idx, }); } (HeapCellValueTag::Lis, h) => { @@ -319,7 +327,10 @@ impl<'a> Iterator for PStrCharsIter<'a> { self.item = self.iter.next(); return Some(value); } - PStrIteratee::PStrSlice { slice_loc, slice_len } => { + PStrIteratee::PStrSlice { + slice_loc, + slice_len, + } => { let s = self.iter.heap.slice_to_str(slice_loc, slice_len); match s.chars().next() { @@ -353,7 +364,10 @@ mod test { let mut wam = MockWAM::new(); let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap(); - wam.machine_st.heap.push_cell(empty_list_as_cell!()).unwrap(); + wam.machine_st + .heap + .push_cell(empty_list_as_cell!()) + .unwrap(); // not overwriting anything! 0 is an interstitial cell // reserved for use by the runtime @@ -364,7 +378,10 @@ mod test { assert_eq!( iter.next(), - Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }), + Some(PStrIteratee::PStrSlice { + slice_loc: heap_index!(1), + slice_len: "abc ".len() + }), ); assert_eq!(iter.next(), None); assert!(!iter.is_cyclic()); @@ -384,7 +401,10 @@ mod test { assert_eq!( iter.next(), - Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }) + Some(PStrIteratee::PStrSlice { + slice_loc: heap_index!(1), + slice_len: "abc ".len() + }) ); assert_eq!( iter.next(), @@ -407,7 +427,10 @@ mod test { assert_eq!( iter.next(), - Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }) + Some(PStrIteratee::PStrSlice { + slice_loc: heap_index!(1), + slice_len: "abc ".len() + }) ); assert_eq!( iter.next(), @@ -552,7 +575,11 @@ mod test { section.push_cell(heap_loc_as_cell!(h)); }); - unify!(wam.machine_st, pstr_cell, pstr_loc_as_cell!(heap_index!(start))); + unify!( + wam.machine_st, + pstr_cell, + pstr_loc_as_cell!(heap_index!(start)) + ); assert!(!wam.machine_st.fail); @@ -561,7 +588,9 @@ mod test { "abcdef" ); assert_eq!( - wam.machine_st.heap.slice_to_str(heap_index!(start), "abc".len()), + wam.machine_st + .heap + .slice_to_str(heap_index!(start), "abc".len()), "abc" ); assert_eq!( @@ -587,7 +616,10 @@ mod test { assert_eq!( iter.next(), - Some(PStrIteratee::PStrSlice { slice_loc: 'a'.len_utf8(), slice_len: "bc".len() }) + Some(PStrIteratee::PStrSlice { + slice_loc: 'a'.len_utf8(), + slice_len: "bc".len() + }) ); for _ in iter {} @@ -609,7 +641,11 @@ mod test { section.push_cell(empty_list_as_cell!()); }); - unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + unify!( + wam.machine_st, + list_loc_as_cell!(start), + pstr_loc_as_cell!(0) + ); assert!(!wam.machine_st.fail); @@ -629,7 +665,11 @@ mod test { section.push_cell(empty_list_as_cell!()); }); - unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + unify!( + wam.machine_st, + list_loc_as_cell!(start), + pstr_loc_as_cell!(0) + ); assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a')); assert!(!wam.machine_st.fail); @@ -652,7 +692,11 @@ mod test { section.push_cell(empty_list_as_cell!()); }); - unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + unify!( + wam.machine_st, + list_loc_as_cell!(start), + pstr_loc_as_cell!(0) + ); assert_eq!(wam.machine_st.heap[start], char_as_cell!('a')); assert_eq!(wam.machine_st.heap[4 + start], char_as_cell!('b')); @@ -676,7 +720,11 @@ mod test { section.push_cell(empty_list_as_cell!()); }); - unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + unify!( + wam.machine_st, + list_loc_as_cell!(start), + pstr_loc_as_cell!(0) + ); assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a')); assert!(!wam.machine_st.fail); @@ -699,10 +747,17 @@ mod test { section.push_cell(heap_loc_as_cell!(5 + start)); }); - unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + unify!( + wam.machine_st, + list_loc_as_cell!(start), + pstr_loc_as_cell!(0) + ); assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a')); - assert_eq!(wam.machine_st.heap[5 + start], pstr_loc_as_cell!(heap_index!(0) + 3)); + assert_eq!( + wam.machine_st.heap[5 + start], + pstr_loc_as_cell!(heap_index!(0) + 3) + ); assert!(!wam.machine_st.fail); // #2293, test6. @@ -723,7 +778,11 @@ mod test { section.push_cell(empty_list_as_cell!()); }); - unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + unify!( + wam.machine_st, + list_loc_as_cell!(start), + pstr_loc_as_cell!(0) + ); assert_eq!(wam.machine_st.heap[start], char_as_cell!('a')); assert_eq!(wam.machine_st.heap[4 + start], char_as_cell!('c')); @@ -750,7 +809,11 @@ mod test { section.push_cell(empty_list_as_cell!()); }); - unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + unify!( + wam.machine_st, + list_loc_as_cell!(start), + pstr_loc_as_cell!(0) + ); assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('b')); assert_eq!(wam.machine_st.heap[6 + start], char_as_cell!('d')); diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index 751b55b6..51e45a4a 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -28,26 +28,26 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result Result { let (focus, _cell) = subterm_index(term.heap, term.focus); - let name = match term_predicate_key(term.heap, focus+3) { + let name = match term_predicate_key(term.heap, focus + 3) { Some((name, 0)) => name, _ => { return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclNameType(term.heap[focus+3]), + DirectiveError::InvalidOpDeclNameType(term.heap[focus + 3]), )); } }; - let spec = match term_predicate_key(term.heap, focus+2) { + let spec = match term_predicate_key(term.heap, focus + 2) { Some((name, _)) => name, None => { return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus+2]), + DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus + 2]), )); } }; let spec = to_op_decl_spec(spec)?; - let prec = term.deref_loc(focus+1); + let prec = term.deref_loc(focus + 1); let prec = read_heap_cell!(prec, (HeapCellValueTag::Fixnum, n) => { @@ -147,34 +147,34 @@ pub(super) fn setup_module_export_list( let mut focus = term.focus; loop { - read_heap_cell!(term.heap[focus], - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h == focus { - break; - } else { - focus = h; - } - } - (HeapCellValueTag::Lis, l) => { - let term = FocusedHeapRefMut { - heap: term.heap, - focus: l, - }; + 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; - } - ); + exports.push(setup_module_export(&term)?); + focus = l + 1; + } + (HeapCellValueTag::Atom, (name, _arity)) => { + if name == atom!("[]") { + return Ok(exports); + } else { + break; + } + } + _ => { + break; + } + ); } Err(CompilationError::InvalidModuleDecl) @@ -281,7 +281,7 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result>( } let heap = loader.machine_heap(); - let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[term.focus+1])); + let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[term.focus + 1])); read_heap_cell!(cell, (HeapCellValueTag::Str, s) => { @@ -506,28 +506,27 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc); let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); - let (module_name, key, term_loc) = - if subterm_key_opt == Some((atom!(":"), 2)) { - match get_qualified_name(loader.machine_heap(), subterm_loc + 1, subterm_loc + 2) { - Some(QualifiedNameInfo { - module_name, - name, - arity, - qualified_term_loc, - }) => ( - module_name, - (name, arity + supp_args), - qualified_term_loc, - ), - None => { - continue; - } + let (module_name, key, term_loc) = if subterm_key_opt == Some((atom!(":"), 2)) { + match get_qualified_name( + loader.machine_heap(), + subterm_loc + 1, + subterm_loc + 2, + ) { + Some(QualifiedNameInfo { + module_name, + name, + arity, + qualified_term_loc, + }) => (module_name, (name, arity + supp_args), qualified_term_loc), + None => { + continue; } - } else { - (module_name, (name, arity + supp_args), subterm_loc) - }; + } + } else { + (module_name, (name, arity + supp_args), subterm_loc) + }; - if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), key.1, term_loc) { + if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), term_loc) { index_ptrs.insert(term_loc, index_ptr); continue; } @@ -642,7 +641,12 @@ impl Preprocessor { let classifier = VariableClassifier::new(self.settings.default_call_policy()); let var_data = classifier.classify_fact(loader, &term)?; - Ok((Fact { term_loc: term.focus }, var_data)) + Ok(( + Fact { + term_loc: term.focus, + }, + var_data, + )) } else { Err(CompilationError::InadmissibleFact) } @@ -660,7 +664,13 @@ impl Preprocessor { let head_loc = term_nth_arg(heap, term.focus, 1).unwrap(); if term_predicate_key(heap, head_loc).is_some() { - Ok((Rule { term_loc: term.focus, clauses }, var_data)) + Ok(( + Rule { + term_loc: term.focus, + clauses, + }, + var_data, + )) } else { Err(CompilationError::InvalidRuleHead) } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index fac20d46..0e063b36 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -181,10 +181,7 @@ fn pstr_segment_char_count_and_tail(heap: &Heap, pstr_loc: usize) -> (usize, usi byte_offset += c.len_utf8(); } - ( - char_count, - Heap::neighboring_cell_offset(pstr_loc + byte_offset), - ) + (char_count, Heap::pstr_tail_idx(pstr_loc + byte_offset)) } fn pstr_segment_char_count_up_to( @@ -217,10 +214,9 @@ fn pstr_segment_char_count_up_to( pstr_loc: pstr_loc + byte_offset, } } else { - let tail_loc = Heap::neighboring_cell_offset(pstr_loc + byte_offset); PStrSegmentCountResult::End { char_count, - tail_loc, + tail_loc: Heap::pstr_tail_idx(pstr_loc + byte_offset), } } } @@ -567,6 +563,12 @@ struct AttrListMatch { prev_tail: Option, } +#[derive(Debug)] +pub(crate) struct FindallCopyInfo { + offset: usize, + pstr_threshold: usize, +} + impl MachineState { #[inline(always)] pub(crate) fn unattributed_var(&mut self) { @@ -648,9 +650,8 @@ impl MachineState { loop { read_heap_cell!(value, (HeapCellValueTag::PStrLoc, h) => { - let (_, tail) = heap.scan_slice_to_str(h); - // let (h_offset, _) = pstr_loc_and_offset(heap, h); - return tail; + let HeapStringScan { tail_idx, .. } = heap.scan_slice_to_str(h); + return tail_idx; } (HeapCellValueTag::Lis, h) => { return h+1; @@ -855,17 +856,10 @@ impl MachineState { &mut self, lh_offset: usize, copy_target: HeapCellValue, - ) -> Result { + ) -> Result { let threshold = self.lifted_heap.cell_len() - lh_offset; - let mut copy_ball_term = CopyBallTerm::new( - &mut self.attr_var_init.attr_var_queue, - &mut self.stack, - &mut self.heap, - &mut self.lifted_heap, - ); - - let mut writer = copy_ball_term.reserve(3)?; + let mut writer = self.lifted_heap.reserve(3)?; writer.write_with(|section| { section.push_cell(list_loc_as_cell!(threshold + 1)); @@ -873,9 +867,21 @@ impl MachineState { section.push_cell(heap_loc_as_cell!(threshold + 2)); }); - copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy)?; + let old_lifted_cell_len = self.lifted_heap.cell_len(); - Ok(threshold + lh_offset + 2) + let copy_ball_term = CopyBallTerm::new( + &mut self.attr_var_init.attr_var_queue, + &mut self.stack, + &mut self.heap, + &mut self.lifted_heap, + ); + + let pstr_boundary = copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy)?; + + Ok(FindallCopyInfo { + offset: threshold + lh_offset + 2, + pstr_threshold: pstr_boundary + old_lifted_cell_len, + }) } #[inline(always)] @@ -1045,18 +1051,6 @@ impl MachineState { pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option { read_heap_cell!(value, - /* - (HeapCellValueTag::CStr, cstr_atom) => { - // avoid allocating a String if possible: - // We must be careful to preserve the string "[]" as is, - // instead of turning it into the atom [], i.e., "". - if cstr_atom == atom!("[]") { - Some(AtomOrString::String("[]".to_string())) - } else { - Some(AtomOrString::Atom(cstr_atom)) - } - } - */ (HeapCellValueTag::Atom, (atom, arity)) => { if arity == 0 { // ... likewise. @@ -1389,15 +1383,7 @@ impl Machine { let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) .get_name_and_arity(); - (name, arity, if self.machine_st.heap.cell_len() > s + arity + 1 { - if !self.machine_st.heap.pstr_at(s + arity + 1) { - get_structure_index(self.machine_st.heap[s + arity + 1]) - } else { - None - } - } else { - None - }) + (name, arity, get_structure_index(self.machine_st.heap[s.saturating_sub(1)])) } (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); @@ -1457,7 +1443,6 @@ impl Machine { if let Some(code_index) = index_cell { if !code_index.is_undefined() { - // println!("(fast) calling {}/{}", name.as_str(), arity); load_registers(&mut self.machine_st, goal, goal_arity); self.machine_st.neck_cut(); return call_at_index(self, name, arity, code_index.get()); @@ -1481,6 +1466,7 @@ impl Machine { .variable_set(&mut supp_vars, self.machine_st.registers[2]); struct GoalAnalysisResult { + index_ptr_loc: usize, is_simple_goal: bool, goal: HeapCellValue, key: PredicateKey, @@ -1496,7 +1482,7 @@ impl Machine { // fill expanded_vars with variables of the partial // goal pre-completion by complete_partial_goal. - for idx in s + 1 .. s + arity - supp_vars.len() + 1 { + for idx in s + 1 ..= s + arity - supp_vars.len() { self.machine_st.variable_set(&mut expanded_vars, self.machine_st.heap[idx]); } @@ -1510,7 +1496,8 @@ impl Machine { // disjoint from them. if they are not, the // expanded goal is not simple. - let post_supp_args = self.machine_st.heap.splice(s+arity-supp_vars.len()+1 .. s+arity+1); + let post_supp_args = (s+arity-supp_vars.len()+1 ..= s+arity) + .map(|idx| self.machine_st.heap[idx]); post_supp_args .zip(supp_vars.iter()) @@ -1535,27 +1522,33 @@ impl Machine { false }; - let goal = if is_simple_goal { + let (index_ptr_loc, goal) = if is_simple_goal { let h = self.machine_st.heap.cell_len(); let arity = arity - supp_vars.len(); + resource_error_call_result!( + self.machine_st, + self.machine_st.heap.push_cell(empty_list_as_cell!()) + ); + resource_error_call_result!( self.machine_st, self.machine_st.heap.copy_slice_to_end( - s .. s + arity + 1 + s ..= s + arity, ) ); - self.machine_st.heap[h] = atom_as_cell!(name, arity); + self.machine_st.heap[h+1] = atom_as_cell!(name, arity); // even if arity == 0, goal must be a Str cell, // since an index is about to appended to it. - str_loc_as_cell!(h) + (h, str_loc_as_cell!(h+1)) } else { - goal + (0, goal) }; GoalAnalysisResult { + index_ptr_loc, is_simple_goal, goal, key: (name, arity), @@ -1566,36 +1559,25 @@ impl Machine { debug_assert_eq!(arity, 0); let h = self.machine_st.heap.cell_len(); - resource_error_call_result!( + + let mut writer = resource_error_call_result!( self.machine_st, - self.machine_st.heap.push_cell(goal) + self.machine_st.heap.reserve(2) ); + writer.write_with(|section| { + section.push_cell(empty_list_as_cell!()); + section.push_cell(goal); + }); + GoalAnalysisResult { + index_ptr_loc: h, is_simple_goal: true, - goal: str_loc_as_cell!(h), + goal: str_loc_as_cell!(h+1), key: (name, 0), supp_vars, } } - /* - (HeapCellValueTag::Char, c) => { - let name = AtomTable::build_with(&self.machine_st.atom_tbl,&c.to_string()); - let h = self.machine_st.heap.cell_len(); - - resource_error_call_result!( - self.machine_st, - self.machine_st.heap.push_cell(atom_as_cell!(name)) - ); - - GoalAnalysisResult { - is_simple_goal: true, - goal: str_loc_as_cell!(h), - key: (name, 0), - supp_vars, - } - } - */ _ => { self.machine_st.fail = true; return Ok(()); @@ -1609,14 +1591,8 @@ impl Machine { let expanded_term = if result.is_simple_goal { let idx = self.get_or_insert_qualified_code_index(module_name, result.key); - - resource_error_call_result!( - self.machine_st, - self.machine_st - .heap - .push_cell(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))) - ); - + self.machine_st.heap[result.index_ptr_loc] = + untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)); result.goal } else { let mut unexpanded_vars = IndexSet::with_hasher(FxBuildHasher::default()); @@ -1648,29 +1624,24 @@ impl Machine { self.machine_st.heap.reserve(unexpanded_vars.len() + 2) ); - writer.write_with(|section| { - section.push_cell(atom_as_cell!(atom!("$aux"), 0)); - - for value in unexpanded_vars.difference(&result.supp_vars).cloned() { - section.push_cell(value); - } - - section.push_cell(atom_as_cell!(atom!("[]"))); - }); - - let anon_str_arity = self.machine_st.heap.cell_len() - h - 2; - self.machine_st.heap[h] = atom_as_cell!(atom!("$aux"), anon_str_arity); - let idx = CodeIndex::new( IndexPtr::index(helper_clause_loc), &mut self.machine_st.arena, ); - self.machine_st.heap.last_cell_mut().map(|cell| { - *cell = untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)); + writer.write_with(|section| { + section.push_cell(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))); + section.push_cell(atom_as_cell!(atom!("$aux"), 0)); + + for value in unexpanded_vars.difference(&result.supp_vars).cloned() { + section.push_cell(value); + } }); - str_loc_as_cell!(h) + let anon_str_arity = self.machine_st.heap.cell_len() - h - 2; + self.machine_st.heap[h + 1] = atom_as_cell!(atom!("$aux"), anon_str_arity); + + str_loc_as_cell!(h + 1) } } }; @@ -1688,28 +1659,22 @@ impl Machine { if HeapCellValueTag::Str == qualified_goal.get_tag() { let s = qualified_goal.get_value() as usize; - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity(); + let name = cell_as_atom_cell!(self.machine_st.heap[s]).get_name(); if name == atom!("$call") { return false; } - if self.machine_st.heap.cell_len() > s + 1 + arity { - if self.machine_st.heap.pstr_at(s + 1 + arity) { - return false; - } + let idx_cell = self.machine_st.heap[s.saturating_sub(1)]; - let idx_cell = self.machine_st.heap[s + 1 + arity]; - - if HeapCellValueTag::Cons == idx_cell.get_tag() { - match_untyped_arena_ptr!(cell_as_untyped_arena_ptr!(idx_cell), - (ArenaHeaderTag::IndexPtr, _ip) => { - return true; - } - _ => { - } - ); - } + if HeapCellValueTag::Cons == idx_cell.get_tag() { + match_untyped_arena_ptr!(cell_as_untyped_arena_ptr!(idx_cell), + (ArenaHeaderTag::IndexPtr, _ip) => { + return true; + } + _ => { + } + ); } } @@ -2312,27 +2277,6 @@ impl Machine { let a1 = self.deref_register(1); read_heap_cell!(a1, - /* - (HeapCellValueTag::Char) => { - let h = self.machine_st.heap.cell_len(); - - let mut writer = resource_error_call_result!( - self.machine_st, - self.machine_st.heap.reserve(2) - ); - - step_or_resource_error!( - self.machine_st, - writer.write_with(|section| { - section.push_cell(a1); - section.push_cell(empty_list_as_cell!()); - Ok::<(), usize>(()) - }) - ); - - unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h)); - } - */ (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); @@ -2542,7 +2486,7 @@ impl Machine { self.machine_st.allocate_pstr(&*atom.as_str()) ); - let tail_loc = Heap::neighboring_cell_offset(atom.as_str().len() + heap_index!(pstr_h)); + let tail_loc = Heap::pstr_tail_idx(atom.as_str().len() + heap_index!(pstr_h)); step_or_resource_error!( self.machine_st, @@ -2585,8 +2529,8 @@ impl Machine { read_heap_cell!(pstr, (HeapCellValueTag::PStrLoc, h) => { - let (_, tail_loc) = self.machine_st.heap.scan_slice_to_str(h); - unify_fn!(self.machine_st, heap_loc_as_cell!(tail_loc), a2); + let HeapStringScan { tail_idx, .. } = self.machine_st.heap.scan_slice_to_str(h); + unify_fn!(self.machine_st, heap_loc_as_cell!(tail_idx), a2); } (HeapCellValueTag::Lis, h) => { unify_fn!( @@ -3970,7 +3914,10 @@ impl Machine { pub(crate) fn copy_to_lifted_heap(&mut self) { let lh_offset = cell_as_fixnum!(self.deref_register(1)).get_num() as usize; let copy_target = self.machine_st.registers[2]; - let old_threshold = step_or_resource_error!( + let FindallCopyInfo { + offset: old_threshold, + pstr_threshold, + } = step_or_resource_error!( self.machine_st, self.machine_st .copy_findall_solution(lh_offset, copy_target) @@ -3980,8 +3927,20 @@ impl Machine { self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold); - for addr in &mut self.machine_st.lifted_heap.splice_mut(old_threshold + 1..) { - *addr -= self.machine_st.heap.cell_len() + lh_offset; + for idx in old_threshold + 1..pstr_threshold { + self.machine_st.lifted_heap[idx] -= self.machine_st.heap.cell_len() + lh_offset; + } + + let mut pstr_threshold = heap_index!(pstr_threshold); + + while pstr_threshold < heap_index!(self.machine_st.lifted_heap.cell_len()) { + let HeapStringScan { tail_idx, .. } = self + .machine_st + .lifted_heap + .scan_slice_to_str(pstr_threshold); + + self.machine_st.lifted_heap[tail_idx] -= self.machine_st.heap.cell_len() + lh_offset; + pstr_threshold = heap_index!(tail_idx + 1); } } @@ -5797,17 +5756,18 @@ impl Machine { unify_fn!(self.machine_st, solutions, diff); } else { let h = self.machine_st.heap.cell_len(); + let reserve_size = self.machine_st.lifted_heap.cell_len() - lh_offset; - step_or_resource_error!( + let mut writer = step_or_resource_error!( self.machine_st, - self.machine_st - .heap - .append(self.machine_st.lifted_heap.splice(lh_offset..),) + self.machine_st.heap.reserve(reserve_size) ); - for cell in &mut self.machine_st.heap.splice_mut(h..) { - *cell = *cell + h; - } + writer.write_with(|section| { + for idx in lh_offset..self.machine_st.lifted_heap.cell_len() { + section.push_cell(self.machine_st.lifted_heap[idx] + h); + } + }); let diff = self.machine_st.registers[3]; unify_fn!( @@ -5834,17 +5794,18 @@ impl Machine { unify_fn!(self.machine_st, solutions, empty_list_as_cell!()); } else { let h = self.machine_st.heap.cell_len(); + let reserve_size = self.machine_st.lifted_heap.cell_len() - lh_offset; - step_or_resource_error!( + let mut writer = step_or_resource_error!( self.machine_st, - self.machine_st - .heap - .append(self.machine_st.lifted_heap.splice(lh_offset..),) + self.machine_st.heap.reserve(reserve_size) ); - for cell in &mut self.machine_st.heap.splice_mut(h..) { - *cell = *cell + h; - } + writer.write_with(|section| { + for idx in lh_offset..self.machine_st.lifted_heap.cell_len() { + section.push_cell(self.machine_st.lifted_heap[idx] + h); + } + }); self.machine_st.lifted_heap.truncate(lh_offset); @@ -7223,8 +7184,7 @@ impl Machine { let mut ball = Ball::new(); ball.boundary = self.machine_st.heap.cell_len(); - - step_or_resource_error!( + ball.pstr_boundary = step_or_resource_error!( self.machine_st, copy_term( CopyBallTerm::new( diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs index 9a1f9fa6..f8488af7 100644 --- a/src/machine/term_stream.rs +++ b/src/machine/term_stream.rs @@ -44,14 +44,19 @@ impl<'a> BootstrappingTermStream<'a> { listing_src: ListingSource, ) -> Self { let lexer_parser = LexerParser::new(stream, machine_st); - Self { lexer_parser, listing_src } + Self { + lexer_parser, + listing_src, + } } } impl<'a> TermStream for BootstrappingTermStream<'a> { #[inline] fn next(&mut self, op_dir: &CompositeOpDir) -> Result { - let result = self.lexer_parser.read_term(op_dir, Tokens::Default) + let result = self + .lexer_parser + .read_term(op_dir, Tokens::Default) .map_err(CompilationError::from); result @@ -125,7 +130,9 @@ pub struct InlineTermStream {} impl TermStream for InlineTermStream { fn next(&mut self, _: &CompositeOpDir) -> Result { - Err(CompilationError::from(ParserError::unexpected_eof(ParserErrorSrc::default()))) + 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 5b7c23e8..899fc3ac 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -507,11 +507,9 @@ fn bind_with_occurs_check(unifier: &mut U, r: Ref, value: HeapCellVa if value.is_ref() && !value.is_stack_var() { machine_st.heap[0] = value; - for cell in stackful_preorder_iter::( - &mut machine_st.heap, - &mut machine_st.stack, - 0, - ) { + for cell in + stackful_preorder_iter::(&mut machine_st.heap, &mut machine_st.stack, 0) + { let cell = unmark_cell_bits!(cell); if let Some(inner_r) = cell.as_var() { diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 52aff1c0..2785b0bf 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -141,7 +141,11 @@ macro_rules! fixnum { ($n:expr, $arena:expr) => { Fixnum::build_with_checked($n) .map(|n| fixnum_as_cell!(n)) - .unwrap_or_else(|_| typed_arena_ptr_as_cell!(arena_alloc!(Integer::from($n), $arena) as TypedArenaPtr)) + .unwrap_or_else(|_| { + typed_arena_ptr_as_cell!( + arena_alloc!(Integer::from($n), $arena) as TypedArenaPtr + ) + }) }; ($wrapper:ty, $n:expr, $arena:expr) => { Fixnum::build_with_checked($n) @@ -619,10 +623,7 @@ impl Literal { pub type Var = Rc; -pub(crate) fn subterm_index( - heap: &impl SizedHeap, - subterm_loc: usize, -) -> (usize, HeapCellValue) { +pub(crate) fn subterm_index(heap: &impl SizedHeap, subterm_loc: usize) -> (usize, HeapCellValue) { let subterm = heap[subterm_loc]; if subterm.is_ref() { @@ -715,16 +716,10 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec { } */ -pub(crate) fn fetch_index_ptr( - heap: &impl SizedHeap, - arity: usize, - term_loc: usize, -) -> Option { - if term_loc + arity + 1 >= heap.cell_len() || heap.pstr_at(term_loc + arity + 1) { - return None; - } +pub(crate) fn fetch_index_ptr(heap: &impl SizedHeap, term_loc: usize) -> Option { + let index_cell_loc = term_loc.saturating_sub(1); - read_heap_cell!(heap[term_loc + arity + 1], + read_heap_cell!(heap[index_cell_loc], (HeapCellValueTag::Cons, c) => { match_untyped_arena_ptr!(c, (ArenaHeaderTag::IndexPtr, ptr) => { @@ -744,7 +739,7 @@ pub(crate) fn blunt_index_ptr( key: PredicateKey, term_loc: usize, ) -> bool { - if fetch_index_ptr(heap, key.1, term_loc).is_some() { + if fetch_index_ptr(heap, term_loc).is_some() { heap[term_loc] = atom_as_cell!(key.0, key.1); true } else { @@ -757,10 +752,7 @@ pub(crate) fn unfold_by_str_once( start_term: HeapCellValue, atom: Atom, ) -> Option { - let start_term = heap_bound_store( - heap, - heap_bound_deref(heap, start_term), - ); + 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; @@ -769,7 +761,7 @@ pub(crate) fn unfold_by_str_once( blunt_index_ptr(heap, (s_atom, s_arity), s); if (s_atom, s_arity) == (atom, 2) { - return Some(s+1); + return Some(s + 1); } } @@ -826,7 +818,7 @@ pub fn unfold_by_str_locs( 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; + term_loc = fst_loc + 1; current_term = heap[term_loc]; let fst = heap[fst_loc]; terms.push((fst, fst_loc)); @@ -836,10 +828,7 @@ pub fn unfold_by_str_locs( terms } -pub fn term_predicate_key( - heap: &impl SizedHeap, - mut term_loc: usize, -) -> Option { +pub fn term_predicate_key(heap: &impl SizedHeap, mut term_loc: usize) -> Option { loop { read_heap_cell!(heap[term_loc], (HeapCellValueTag::Atom, (name, arity)) => { @@ -879,10 +868,7 @@ pub fn inverse_var_locs_from_iter>(iter: I) -> let var_loc = var.get_value() as usize; if count > 1 { - inverse_var_locs.insert( - var_loc, - Rc::new(format!("_{}", var_loc)), - ); + inverse_var_locs.insert(var_loc, Rc::new(format!("_{}", var_loc))); } } diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 615b00ca..e1be5c46 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -56,22 +56,18 @@ impl Token { Token::String(string) if flags.double_quotes.is_codes() => { 2 * string.chars().count() + 1 } - Token::String(string) => { - Heap::compute_pstr_size(&string) - } - Token::Literal(_) | - Token::Comma | - Token::HeadTailSeparator | - Token::Open | - Token::OpenCT | - Token::OpenCurly | - Token::OpenList | - Token::Var(_) => { + Token::String(string) => Heap::compute_pstr_size(&string), + Token::Literal(_) + | Token::Comma + | Token::HeadTailSeparator + | Token::Open + | Token::OpenCT + | Token::OpenCurly + | Token::OpenList + | Token::Var(_) => { heap_index!(1) } - _ => { - 0 - } + _ => 0, } } @@ -462,10 +458,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { self.skip_char(c); u32::from_str_radix(&token, radix).map_or_else( |_| Err(ParserError::ParseBigInt(self.loc_to_err_src())), - |n| { - char::try_from(n) - .map_err(|_| ParserError::Utf8Error(self.loc_to_err_src())) - }, + |n| char::try_from(n).map_err(|_| ParserError::Utf8Error(self.loc_to_err_src())), ) } else { Err(ParserError::IncompleteReduction(self.loc_to_err_src())) @@ -657,7 +650,9 @@ impl<'a, R: CharRead> LexerParser<'a, R> { } } } else { - return Err(ParserError::InvalidSingleQuotedCharacter(self.loc_to_err_src())); + return Err(ParserError::InvalidSingleQuotedCharacter( + self.loc_to_err_src(), + )); } } else { match self.get_back_quoted_string() { diff --git a/src/parser/parser.rs b/src/parser/parser.rs index a9240f22..a13b0d57 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -187,7 +187,9 @@ struct Parser<'a> { inverse_var_locs: InverseVarLocs, } -pub fn read_tokens(lexer: &mut LexerParser) -> Result<(Vec, usize), ParserError> { +pub fn read_tokens( + lexer: &mut LexerParser, +) -> Result<(Vec, usize), ParserError> { let mut tokens = vec![]; let mut term_size = 0; @@ -264,9 +266,9 @@ pub(crate) fn as_partial_string( tail = heap[l+1]; } (HeapCellValueTag::PStrLoc, l) => { - let (pstr, tail_loc) = heap.scan_slice_to_str(l); + let HeapStringScan { string: pstr, tail_idx } = heap.scan_slice_to_str(l); string += pstr; - tail = heap[tail_loc]; + tail = heap[tail_idx]; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if heap[h] != tail { @@ -306,8 +308,7 @@ impl<'a> Parser<'a> { TokenType::Comma => Some(atom!(",")), TokenType::Term { heap_loc } => { if heap_loc.is_ref() { - term_predicate_key(&self.terms, heap_loc.get_value() as usize) - .map(|key| key.0) + term_predicate_key(&self.terms, heap_loc.get_value() as usize).map(|key| key.0) } else { None } @@ -392,7 +393,8 @@ impl<'a> Parser<'a> { fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) { let h = self.terms.cell_len(); - self.terms.write_with(|section| section.push_cell(atom_as_cell!(atom))); + self.terms + .write_with(|section| section.push_cell(atom_as_cell!(atom))); self.stack.push(TokenDesc { tt: TokenType::Term { heap_loc: heap_loc_as_cell!(h), @@ -438,10 +440,12 @@ impl<'a> Parser<'a> { section.push_cell(list_loc_as_cell!(h)); }); - TokenType::Term { heap_loc: heap_loc_as_cell!(h + 2) } + TokenType::Term { + heap_loc: heap_loc_as_cell!(h + 2), + } } else { - self.terms.write_with(|section| { - match section.push_pstr(&s) { + self.terms + .write_with(|section| match section.push_pstr(&s) { Some(pstr_loc_cell) => { section.push_cell(empty_list_as_cell!()); let h = section.cell_len(); @@ -451,10 +455,11 @@ impl<'a> Parser<'a> { None => { section.push_cell(empty_list_as_cell!()); } - } - }); + }); - TokenType::Term { heap_loc: pstr_cell } + TokenType::Term { + heap_loc: pstr_cell, + } } } Token::Literal(c) => { @@ -478,13 +483,14 @@ impl<'a> Parser<'a> { if var.trim() != "_" { self.var_locs.insert(var.clone(), heap_loc); - self.inverse_var_locs.insert(heap_loc.get_value() as usize, var); + self.inverse_var_locs + .insert(heap_loc.get_value() as usize, var); } TokenType::Term { heap_loc } } } - }, + } Token::Comma => TokenType::Comma, Token::Open => TokenType::Open, Token::Close => TokenType::Close, @@ -619,15 +625,21 @@ impl<'a> Parser<'a> { let term_idx = self.terms.cell_len(); let push_structure = |parser: &mut Self, name: Atom| -> TokenType { - parser.terms.write_with(|section| section.push_cell(atom_as_cell!(name, arity))); + parser + .terms + .write_with(|section| section.push_cell(atom_as_cell!(name, arity))); for idx in (stack_len + 2..parser.stack.len()).step_by(2) { let subterm = parser.term_from_stack(idx).unwrap(); - parser.terms.write_with(|section| section.push_cell(subterm)); + parser + .terms + .write_with(|section| section.push_cell(subterm)); } let str_loc_idx = parser.terms.cell_len(); - parser.terms.write_with(|section| section.push_cell(str_loc_as_cell!(term_idx))); + parser + .terms + .write_with(|section| section.push_cell(str_loc_as_cell!(term_idx))); TokenType::Term { heap_loc: heap_loc_as_cell!(str_loc_idx), @@ -709,23 +721,20 @@ impl<'a> Parser<'a> { } fn loc_to_err_src(&self) -> ParserErrorSrc { - ParserErrorSrc { line_num: *self.line_num, col_num: *self.col_num } + ParserErrorSrc { + line_num: *self.line_num, + col_num: *self.col_num, + } } fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { if let Some(term) = self.term_from_stack(index - 1) { let mut op_desc = self.stack[index - 1]; - let mut term = heap_bound_store( - &self.terms, - heap_bound_deref( - &self.terms, - term, - ), - ); + let mut term = heap_bound_store(&self.terms, heap_bound_deref(&self.terms, term)); - if term.is_ref() && - 0 < op_desc.priority && - op_desc.priority < self.stack[index].priority + if 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 @@ -740,11 +749,9 @@ impl<'a> Parser<'a> { } else { let mut terms = vec![]; - while let Some(fst_loc) = unfold_by_str_once( - &mut self.terms, - 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); @@ -763,14 +770,13 @@ impl<'a> Parser<'a> { }; let arity = terms.len() - 1; - self.stack.extend(terms.into_iter().map(|heap_loc| { - TokenDesc { + self.stack + .extend(terms.into_iter().map(|heap_loc| TokenDesc { tt: TokenType::Term { heap_loc }, priority: 0, spec: 0, unfold_bounds: 0, - } - })); + })); return arity; } } @@ -816,7 +822,8 @@ impl<'a> Parser<'a> { // parsed an empty list token if td.tt == TokenType::OpenList { let h = self.terms.cell_len(); - self.terms.write_with(|section| section.push_cell(empty_list_as_cell!())); + self.terms + .write_with(|section| section.push_cell(empty_list_as_cell!())); td.spec = TERM; td.tt = TokenType::Term { @@ -845,9 +852,7 @@ impl<'a> Parser<'a> { let tail_term = match self.term_from_stack(idx + 1) { Some(term) => term, None => { - return Err(ParserError::IncompleteReduction( - self.loc_to_err_src(), - )); + return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); } }; @@ -863,18 +868,14 @@ impl<'a> Parser<'a> { }; if arity > self.terms.cell_len() { - return Err(ParserError::IncompleteReduction( - self.loc_to_err_src(), - )); + return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); } let pre_terms_len = self.terms.cell_len(); while let Some(token_desc) = self.stack.pop() { let subterm = match token_desc.tt { - TokenType::Term { heap_loc } => { - heap_loc - } + TokenType::Term { heap_loc } => heap_loc, _ => { continue; } @@ -942,7 +943,8 @@ impl<'a> Parser<'a> { if td.tt == TokenType::OpenCurly { let h = self.terms.cell_len(); - self.terms.write_with(|section| section.push_cell(atom_as_cell!(atom!("{}")))); + self.terms + .write_with(|section| section.push_cell(atom_as_cell!(atom!("{}")))); td.tt = TokenType::Term { heap_loc: heap_loc_as_cell!(h), @@ -1160,66 +1162,58 @@ impl<'a> Parser<'a> { Token::String(string) => { self.shift(Token::String(string), 0, TERM); } - Token::Literal(c) => { - match Number::try_from(c) { - Ok(Number::Integer(n)) => { - self.negate_number(n, negate_int_rc, |n, _| typed_arena_ptr_as_cell!(n)) - } - Ok(Number::Rational(n)) => { - self.negate_number(n, negate_rat_rc, |r, _| typed_arena_ptr_as_cell!(r)) - } - Ok(Number::Float(n)) if n.is_infinite() => { - return Err(ParserError::InfiniteFloat( - self.lexer.loc_to_err_src(), - )); - } - Ok(Number::Float(n)) => { - use ordered_float::OrderedFloat; + Token::Literal(c) => match Number::try_from(c) { + Ok(Number::Integer(n)) => { + self.negate_number(n, negate_int_rc, |n, _| typed_arena_ptr_as_cell!(n)) + } + Ok(Number::Rational(n)) => { + self.negate_number(n, negate_rat_rc, |r, _| typed_arena_ptr_as_cell!(r)) + } + Ok(Number::Float(n)) if n.is_infinite() => { + return Err(ParserError::InfiniteFloat( + self.loc_to_err_src(), + )); + } + Ok(Number::Float(n)) => { + use ordered_float::OrderedFloat; - self.negate_number( - n, - |n, _| -n, - |OrderedFloat(n), arena| HeapCellValue::from(float_alloc!(n, arena)), - ) - } - Ok(Number::Fixnum(n)) => { - self.negate_number(n, |n, _| -n, |n, _| fixnum_as_cell!(n)) - } - Err(_) => { - if let Some(name) = c.to_atom() { - if !self.shift_op(name, op_dir)? { - self.shift(Token::Literal(c), 0, TERM); - } - } else { + self.negate_number( + n, + |n, _| -n, + |OrderedFloat(n), arena| HeapCellValue::from(float_alloc!(n, arena)), + ) + } + Ok(Number::Fixnum(n)) => { + self.negate_number(n, |n, _| -n, |n, _| fixnum_as_cell!(n)) + } + Err(_) => { + if let Some(name) = c.to_atom() { + if !self.shift_op(name, op_dir)? { self.shift(Token::Literal(c), 0, TERM); } + } else { + self.shift(Token::Literal(c), 0, TERM); } } - } + }, Token::Var(v) => self.shift(Token::Var(v), 0, TERM), Token::Open => self.shift(Token::Open, 1300, DELIMITER), Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER), Token::Close => { if !self.reduce_term() && !self.reduce_brackets() { - return Err(ParserError::IncompleteReduction( - self.loc_to_err_src(), - )); + return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); } } Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER), Token::CloseList => { if !self.reduce_list()? { - return Err(ParserError::IncompleteReduction( - self.loc_to_err_src(), - )); + return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); } } Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER), Token::CloseCurly => { if !self.reduce_curly()? { - return Err(ParserError::IncompleteReduction( - self.loc_to_err_src(), - )); + return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); } } Token::HeadTailSeparator => { @@ -1253,9 +1247,7 @@ impl<'a> Parser<'a> { | Some(TokenType::OpenCurly) | Some(TokenType::HeadTailSeparator) | Some(TokenType::Comma) => { - return Err(ParserError::IncompleteReduction( - self.loc_to_err_src(), - )) + return Err(ParserError::IncompleteReduction(self.loc_to_err_src())) } _ => {} }, @@ -1272,7 +1264,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> { } pub fn loc_to_err_src(&self) -> ParserErrorSrc { - ParserErrorSrc { line_num: self.line_num, col_num: self.col_num } + ParserErrorSrc { + line_num: self.line_num, + col_num: self.col_num, + } } // on success, returns the parsed term and the number of lines read. @@ -1289,7 +1284,11 @@ impl<'a, R: CharRead> LexerParser<'a, R> { // the parser uses conditional indirection in many places so // the reserved size should be at least 4 * term_byte_size // so all cells are accounted for. - let writer = match self.machine_st.heap.reserve(cell_index!(4 * term_byte_size)) { + let writer = match self + .machine_st + .heap + .reserve(cell_index!(4 * term_byte_size)) + { Ok(term) => term, Err(_err_loc) => { return Err(ParserError::ResourceError(self.loc_to_err_src())); diff --git a/src/read.rs b/src/read.rs index e0b5d7d9..549cdef0 100644 --- a/src/read.rs +++ b/src/read.rs @@ -58,7 +58,7 @@ impl MachineState { let op_dir = CompositeOpDir::new(op_dir, None); let term_result = lexer_parser.read_term(&op_dir, Tokens::Default); - let lines_read = lexer_parser.line_num(); + let lines_read = lexer_parser.line_num(); term_result.map(|term| (term, lines_read)) } diff --git a/src/types.rs b/src/types.rs index 47c7b137..a2dd7225 100644 --- a/src/types.rs +++ b/src/types.rs @@ -369,8 +369,8 @@ impl HeapCellValue { name == atom!("[]") && arity == 0 } (HeapCellValueTag::PStrLoc, h) => { - let (_s, tail_loc) = heap.scan_slice_to_str(h); - self = heap[tail_loc]; + let HeapStringScan { tail_idx, .. } = heap.scan_slice_to_str(h); + self = heap[tail_idx]; continue; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { @@ -399,8 +399,7 @@ impl HeapCellValue { | HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar - | HeapCellValueTag::PStrLoc - // | HeapCellValueTag::PStrOffset + | HeapCellValueTag::PStrLoc // | HeapCellValueTag::PStrOffset ) } @@ -503,9 +502,7 @@ impl HeapCellValue { #[inline] pub fn to_atom(self) -> Option { match self.get_tag() { - HeapCellValueTag::Atom => { - Some(AtomCell::from_bytes(self.into_bytes()).get_name()) - } + HeapCellValueTag::Atom => Some(AtomCell::from_bytes(self.into_bytes()).get_name()), _ => None, } } @@ -775,7 +772,8 @@ impl Sub for HeapCellValue { HeapCellValue::build_with(tag, self.get_value() + rhs.unsigned_abs()) } tag @ HeapCellValueTag::PStrLoc => { - let value = self.get_value() as usize + heap_index!(rhs.unsigned_abs() as usize); + let value = + self.get_value() as usize + heap_index!(rhs.unsigned_abs() as usize); HeapCellValue::build_with(tag, value as u64) } _ => self, diff --git a/src/variable_records.rs b/src/variable_records.rs index a2b98918..a22e5be1 100644 --- a/src/variable_records.rs +++ b/src/variable_records.rs @@ -1,5 +1,5 @@ -use crate::parser::ast::*; use crate::forms::GenContext; +use crate::parser::ast::*; use bit_set::*; use fxhash::FxBuildHasher; @@ -88,7 +88,10 @@ pub enum VarAlloc { safety: VarSafetyStatus, to_perm_var_num: Option, }, - Perm { reg: usize, allocation: PermVarAllocation }, // stack offset, allocation info + Perm { + reg: usize, + allocation: PermVarAllocation, + }, // stack offset, allocation info } impl VarAlloc { @@ -152,7 +155,10 @@ pub struct VariableRecord { impl Default for VariableRecord { fn default() -> Self { VariableRecord { - allocation: VarAlloc::Perm { reg: 0, allocation: PermVarAllocation::Pending }, + allocation: VarAlloc::Perm { + reg: 0, + allocation: PermVarAllocation::Pending, + }, num_occurrences: 0, running_count: 0, } From 57f76169fda98b6657eb179994940018e32d1fdf Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 1 Mar 2025 13:58:50 -0800 Subject: [PATCH 011/122] run cargo fmt --- src/heap_iter.rs | 13 +++++++++---- src/lib.rs | 1 - src/machine/gc.rs | 22 +++++++++++++++++----- src/machine/mock_wam.rs | 21 +++++++++++++++------ 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/heap_iter.rs b/src/heap_iter.rs index fd9b1b0c..2b0e44c1 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -2220,10 +2220,16 @@ mod tests { assert_eq!(iter.next(), None); } - assert_eq!(wam.machine_st.heap.slice_to_str(0, "a string".len()), "a string"); - assert_eq!(wam.machine_st.heap[1], HeapCellValue::build_with(HeapCellValueTag::Cons, 0)); + assert_eq!( + wam.machine_st.heap.slice_to_str(0, "a string".len()), + "a string" + ); + assert_eq!( + wam.machine_st.heap[1], + HeapCellValue::build_with(HeapCellValueTag::Cons, 0) + ); - for idx in 2 ..= 3 { + for idx in 2..=3 { assert!(!wam.machine_st.heap[idx].get_mark_bit()); assert!(!wam.machine_st.heap[idx].get_forwarding_bit()); } @@ -2970,7 +2976,6 @@ mod tests { assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); wam.machine_st.heap.clear(); - } #[test] diff --git a/src/lib.rs b/src/lib.rs index ffd532f7..1926c7df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![recursion_limit = "4112"] #![deny(missing_docs)] - #[macro_use] extern crate static_assertions; diff --git a/src/machine/gc.rs b/src/machine/gc.rs index b18b5300..cb46f861 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -130,7 +130,7 @@ impl PStrLocValuesMap { } fn progress_pstr_marking(&mut self, heap_slice: &[u8], pstr_loc: usize) -> usize { - match self.hit_set.range(..= pstr_loc).next_back() { + match self.hit_set.range(..=pstr_loc).next_back() { Some((_prev_pstr_loc, &tail_idx)) if pstr_loc < heap_index!(tail_idx) => { return tail_idx; } @@ -142,7 +142,10 @@ impl PStrLocValuesMap { None => heap_slice.len(), }; - match heap_slice[pstr_loc..delimiter].iter().position(|b| *b == 0u8) { + match heap_slice[pstr_loc..delimiter] + .iter() + .position(|b| *b == 0u8) + { Some(zero_byte_offset) => { let tail_idx = if (zero_byte_offset + 1) % Heap::heap_cell_alignment() == 0 { cell_index!(pstr_loc + zero_byte_offset) + 2 @@ -354,7 +357,8 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { .pstr_loc_values .progress_pstr_marking(self.heap.as_slice(), pstr_loc); - self.pstr_loc_values.insert_pstr_loc_value(self.current, pstr_loc); + self.pstr_loc_values + .insert_pstr_loc_value(self.current, pstr_loc); if self.heap[tail_idx].get_forwarding_bit() { return Some(self.backward_and_return()); @@ -379,10 +383,18 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { } } HeapCellValueTag::Cons => { - match self.pstr_loc_values.hit_set.range(.. heap_index!(self.current + 1)).next_back() { + match self + .pstr_loc_values + .hit_set + .range(..heap_index!(self.current + 1)) + .next_back() + { Some((_prev_pstr_loc, &tail_idx)) if self.current + 1 == tail_idx => { let pstr_loc_loc = self.heap[self.current].get_value() as usize; - let pstr_loc_val = self.pstr_loc_values.pstr_loc_loc_value(pstr_loc_loc).unwrap(); + let pstr_loc_val = self + .pstr_loc_values + .pstr_loc_loc_value(pstr_loc_loc) + .unwrap(); self.heap[self.current].set_value(self.next); diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 71f74f0c..32c4cf59 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -439,14 +439,23 @@ mod tests { assert!(!wam.fail); - assert_eq!(wam.heap.slice_to_str(heap_index!(0), "this is a string".len()), - "this is a string"); + assert_eq!( + wam.heap + .slice_to_str(heap_index!(0), "this is a string".len()), + "this is a string" + ); assert_eq!(wam.heap[3], pstr_loc_as_cell!(heap_index!(8))); - assert_eq!(wam.heap.slice_to_str(heap_index!(4), "this is a string".len()), - "this is a string"); + assert_eq!( + wam.heap + .slice_to_str(heap_index!(4), "this is a string".len()), + "this is a string" + ); assert_eq!(wam.heap[7], pstr_loc_as_cell!(heap_index!(8))); - assert_eq!(wam.heap.slice_to_str(heap_index!(8), "this is a string".len()), - "this is a string"); + assert_eq!( + wam.heap + .slice_to_str(heap_index!(8), "this is a string".len()), + "this is a string" + ); assert_eq!(wam.heap[11], pstr_loc_as_cell!(heap_index!(8))); wam.heap.clear(); From fadcfb966e1b7f0774156cb748a528de85085b7c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 4 Mar 2025 00:17:20 -0800 Subject: [PATCH 012/122] copy partial string blocks properly in all solutions predicates --- src/machine/heap.rs | 11 ++-- src/machine/system_calls.rs | 108 +++++++++++++++++------------------- 2 files changed, 55 insertions(+), 64 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index fc517740..11d0fcea 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -225,7 +225,6 @@ impl ReservedHeapSection { ); let zero_region_idx = heap_index!(self.heap_cell_len) + str_byte_len; - let align_offset = pstr_sentinel_length(zero_region_idx); ptr::write_bytes(self.heap_ptr.add(zero_region_idx), 0u8, align_offset); @@ -266,13 +265,13 @@ impl ReservedHeapSection { } loop { - let null_char_idx = src.find('\u{0}').unwrap_or_else(|| src.len()); + let null_char_idx = src.find('\u{0}').unwrap_or(src.len()); let cells_written = self.push_pstr_segment(&src[0..null_char_idx]); - let tail_idx = self.cell_len(); if cells_written == 0 { return None; } else if null_char_idx + 1 < src.len() { + let tail_idx = self.cell_len(); self.push_cell(pstr_loc_as_cell!(heap_index!(tail_idx + 1))); src = &src[null_char_idx + 1..]; } else { @@ -311,15 +310,15 @@ impl ReservedHeapSection { &FunctorElement::Cell(cell) => { section.push_cell(cell + cell_offset); } - &FunctorElement::String(_cell_len, ref string) => { - if section.push_pstr(&string).is_some() { + FunctorElement::String(_cell_len, string) => { + if section.push_pstr(string).is_some() { section.push_cell(empty_list_as_cell!()); } } FunctorElement::InnerFunctor(_inner_size, succ_functor) => { if cursor + 1 < functor.len() { functor_stack.push(FunctorData { - functor: &functor, + functor, cell_offset, cursor: cursor + 1, }); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 0e063b36..ff2a73e4 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -570,6 +570,44 @@ pub(crate) struct FindallCopyInfo { } impl MachineState { + fn copy_lifted_heap_from_offset(&mut self, offset: usize, lh_offset: usize) { + let reserve_size = self.lifted_heap.cell_len() - lh_offset; + let mut writer = step_or_resource_error!(self, self.heap.reserve(reserve_size)); + + writer.write_with(|section| { + let mut lh_offset = lh_offset; + + while lh_offset + 4 < self.lifted_heap.cell_len() { + let cell_threshold = + cell_as_fixnum!(self.lifted_heap[lh_offset + 3]).get_num() as usize; + let pstr_upper_threshold = + cell_as_fixnum!(self.lifted_heap[lh_offset + 4]).get_num() as usize; + + for idx in lh_offset..cell_threshold { + section.push_cell(self.lifted_heap[idx] + offset); + } + + let mut pstr_threshold = heap_index!(cell_threshold); + + while pstr_threshold < heap_index!(pstr_upper_threshold) { + let HeapStringScan { string, tail_idx } = + self.lifted_heap.scan_slice_to_str(pstr_threshold); + + section.push_pstr(string); + section.push_cell(self.lifted_heap[tail_idx] + offset); + + pstr_threshold = heap_index!(tail_idx + 1); + } + + lh_offset = pstr_upper_threshold; + } + + for idx in lh_offset..self.lifted_heap.cell_len() { + section.push_cell(self.lifted_heap[idx] + offset); + } + }); + } + #[inline(always)] pub(crate) fn unattributed_var(&mut self) { let attr_var = self.store(self.deref(self.registers[1])); @@ -858,13 +896,14 @@ impl MachineState { copy_target: HeapCellValue, ) -> Result { let threshold = self.lifted_heap.cell_len() - lh_offset; - - let mut writer = self.lifted_heap.reserve(3)?; + let mut writer = self.lifted_heap.reserve(5)?; writer.write_with(|section| { section.push_cell(list_loc_as_cell!(threshold + 1)); - section.push_cell(heap_loc_as_cell!(threshold + 3)); + section.push_cell(heap_loc_as_cell!(threshold + 5)); section.push_cell(heap_loc_as_cell!(threshold + 2)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(0))); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(0))); }); let old_lifted_cell_len = self.lifted_heap.cell_len(); @@ -3931,6 +3970,12 @@ impl Machine { self.machine_st.lifted_heap[idx] -= self.machine_st.heap.cell_len() + lh_offset; } + self.machine_st.lifted_heap[old_threshold + 1] = + fixnum_as_cell!(Fixnum::build_with(pstr_threshold as i64)); + self.machine_st.lifted_heap[old_threshold + 2] = fixnum_as_cell!(Fixnum::build_with( + self.machine_st.lifted_heap.cell_len() as i64 + )); + let mut pstr_threshold = heap_index!(pstr_threshold); while pstr_threshold < heap_index!(self.machine_st.lifted_heap.cell_len()) { @@ -5708,38 +5753,7 @@ impl Machine { } }); - /* - let mut addrs = vec![]; - - for idx in 1..num_cells + 1 { - let addr = self.machine_st.stack[stack_loc!(AndFrame, e, idx)]; - let addr = self.machine_st.store(self.machine_st.deref(addr)); - - // avoid pushing stack variables to the heap where they - // must not go. - if addr.is_stack_var() { - let h = self.machine_st.heap.cell_len(); - - self.machine_st.heap.push(heap_loc_as_cell!(h)); - self.machine_st.bind(Ref::heap_cell(h), addr); - - addrs.push(heap_loc_as_cell!(h)); - } else { - addrs.push(addr); - } - } - */ - let chunk = str_loc_as_cell!(self.machine_st.heap.cell_len()); - - /* - self.machine_st - .heap - .push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); - self.machine_st.heap.push(p_functor_cell); - self.machine_st.heap.extend(addrs); - */ - unify!(self.machine_st, self.machine_st.registers[3], chunk); } @@ -5756,18 +5770,7 @@ impl Machine { unify_fn!(self.machine_st, solutions, diff); } else { let h = self.machine_st.heap.cell_len(); - let reserve_size = self.machine_st.lifted_heap.cell_len() - lh_offset; - - let mut writer = step_or_resource_error!( - self.machine_st, - self.machine_st.heap.reserve(reserve_size) - ); - - writer.write_with(|section| { - for idx in lh_offset..self.machine_st.lifted_heap.cell_len() { - section.push_cell(self.machine_st.lifted_heap[idx] + h); - } - }); + self.machine_st.copy_lifted_heap_from_offset(h, lh_offset); let diff = self.machine_st.registers[3]; unify_fn!( @@ -5794,19 +5797,8 @@ impl Machine { unify_fn!(self.machine_st, solutions, empty_list_as_cell!()); } else { let h = self.machine_st.heap.cell_len(); - let reserve_size = self.machine_st.lifted_heap.cell_len() - lh_offset; - - let mut writer = step_or_resource_error!( - self.machine_st, - self.machine_st.heap.reserve(reserve_size) - ); - - writer.write_with(|section| { - for idx in lh_offset..self.machine_st.lifted_heap.cell_len() { - section.push_cell(self.machine_st.lifted_heap[idx] + h); - } - }); + self.machine_st.copy_lifted_heap_from_offset(h, lh_offset); self.machine_st.lifted_heap.truncate(lh_offset); let solutions = self.machine_st.registers[2]; From 9daf016d6377ed5511b62731923f488b00224568 Mon Sep 17 00:00:00 2001 From: bakaq Date: Sun, 2 Mar 2025 18:51:57 -0300 Subject: [PATCH 013/122] Fix parsing of \x0\ in partial strings --- src/functor_macro.rs | 10 +++--- src/machine/heap.rs | 83 +++++++++++++++++++++++++++++++++----------- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/src/functor_macro.rs b/src/functor_macro.rs index ee419136..4f9032a7 100644 --- a/src/functor_macro.rs +++ b/src/functor_macro.rs @@ -485,7 +485,7 @@ mod tests { let mut functor_writer = Heap::functor_writer(functor); functor_writer(&mut heap).unwrap(); - assert_eq!(heap.cell_len(), 8); + assert_eq!(heap.cell_len(), 10); assert_eq!(heap[0], atom_as_cell!(atom!("second"), 1)); assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2))); @@ -493,12 +493,14 @@ mod tests { heap.slice_to_str(heap_index!(2), "a stuttered".len()), "a stuttered" ); - assert_eq!(heap[4], pstr_loc_as_cell!(heap_index!(5))); + assert_eq!(heap[4], list_loc_as_cell!(5)); + assert_eq!(heap[5], char_as_cell!('\u{0}')); + assert_eq!(heap[6], pstr_loc_as_cell!(heap_index!(7))); assert_eq!( - heap.slice_to_str(heap_index!(5), " string".len()), + heap.slice_to_str(heap_index!(7), " string".len()), " string" ); - assert_eq!(heap[7], empty_list_as_cell!()); + assert_eq!(heap[9], empty_list_as_cell!()); } #[test] diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 11d0fcea..b753809d 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -251,31 +251,73 @@ impl ReservedHeapSection { } pub(crate) fn push_pstr(&mut self, mut src: &str) -> Option { - let orig_h = self.cell_len(); - - if src.is_empty() { - return if orig_h == self.heap_cell_len { - // src is empty and always was. nothing allocated - // in this case, so nothing to point to in heap. - None - } else { - self.push_cell(heap_loc_as_cell!(orig_h)); - Some(heap_loc_as_cell!(orig_h)) - }; - } + let anchor = self.cell_len(); + let mut ret = None; loop { - let null_char_idx = src.find('\u{0}').unwrap_or(src.len()); - let cells_written = self.push_pstr_segment(&src[0..null_char_idx]); + // Eat the first null chars + while let Some('\u{0}') = src.chars().next() { + match ret { + Some(_) => { + debug_assert_ne!(anchor, self.cell_len()); + self.push_cell(list_loc_as_cell!(self.cell_len() + 1)); + } + None => { + debug_assert_eq!(anchor, self.cell_len()); + ret = Some(list_loc_as_cell!(self.cell_len())); + } + } + + self.push_cell(char_as_cell!('\u{0}')); + + src = &src[1..]; + } + + if src.is_empty() { + return ret; + } + + debug_assert!(!src.is_empty()); + + if let Some(null_char_idx) = src.find('\u{0}') { + debug_assert_ne!(null_char_idx, 0); + + match ret { + Some(_) => { + debug_assert_ne!(anchor, self.cell_len()); + self.push_cell(pstr_loc_as_cell!(heap_index!(self.cell_len() + 1))); + } + None => { + debug_assert_eq!(anchor, self.cell_len()); + ret = Some(pstr_loc_as_cell!(heap_index!(self.cell_len()))); + } + } + + self.push_pstr_segment(&src[0..null_char_idx]); + + // Put the \x0\ + self.push_cell(list_loc_as_cell!(self.cell_len() + 1)); + self.push_cell(char_as_cell!('\u{0}')); - if cells_written == 0 { - return None; - } else if null_char_idx + 1 < src.len() { - let tail_idx = self.cell_len(); - self.push_cell(pstr_loc_as_cell!(heap_index!(tail_idx + 1))); src = &src[null_char_idx + 1..]; + if src.is_empty() { + return ret; + } } else { - return Some(pstr_loc_as_cell!(heap_index!(orig_h))); + match ret { + Some(_) => { + debug_assert_ne!(anchor, self.cell_len()); + self.push_cell(pstr_loc_as_cell!(heap_index!(self.cell_len() + 1))); + } + None => { + debug_assert_eq!(anchor, self.cell_len()); + ret = Some(pstr_loc_as_cell!(heap_index!(self.cell_len()))); + } + } + + self.push_pstr_segment(&src); + + return ret; } } } @@ -812,6 +854,7 @@ impl Heap { pub fn allocate_pstr(&mut self, src: &str) -> Result, usize> { let size_in_heap = Self::compute_pstr_size(src); + let pstr_loc = heap_index!(self.cell_len()); Ok(if size_in_heap > 0 { From 3dee07f648c98aa7dd259a65b9e6e134bdadde54 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 13 Mar 2025 12:33:37 -0700 Subject: [PATCH 014/122] some fixes in response to miri --- src/lib/builtins.pl | 1 - src/machine/heap.rs | 14 ++++++++++++++ src/machine/machine_state_impl.rs | 10 ---------- src/machine/stack.rs | 2 +- src/types.rs | 12 +++++------- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 31b40a3a..bc78b711 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -568,7 +568,6 @@ parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :- % maplist isn't % declared as a % meta-predicate yet - '$debug_hook', catch(lists:maplist(Selector, Options, OptionPairs0), error(E, _), builtins:throw(error(E, Stub))) -> diff --git a/src/machine/heap.rs b/src/machine/heap.rs index b753809d..d628391c 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1281,3 +1281,17 @@ pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option *mut u8 { - let addr: u64 = self.ptr(); - addr as usize as *mut _ + unsafe { mem::transmute::<_, *mut u8>(self.ptr()) } } #[inline(always)] @@ -676,23 +675,22 @@ impl UntypedArenaPtr { } #[inline] - pub fn get_ptr(self) -> *const u8 { - let addr: u64 = self.ptr(); - addr as usize as *const u8 + pub fn get_ptr(self) -> *const ArenaHeader { + unsafe { mem::transmute::<_, *const ArenaHeader>(self.ptr()) } } #[inline] pub fn get_tag(self) -> ArenaHeaderTag { unsafe { debug_assert!(!self.get_ptr().is_null()); - let header = *(self.get_ptr() as *const ArenaHeader); + let header = *self.get_ptr(); header.get_tag() } } #[inline] pub fn payload_offset(self) -> *const u8 { - unsafe { self.get_ptr().add(mem::size_of::()) } + unsafe { self.get_ptr().byte_add(mem::size_of::()) as *const _ } } /// # Safety From 2ad870c7402342ad81d6d2a9a098739a23ef51a8 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 15 Mar 2025 02:10:04 -0700 Subject: [PATCH 015/122] read Str focus properly in build_meta_predicate_clause --- src/machine/preprocessor.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index 51e45a4a..ff64494a 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -460,7 +460,19 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( use crate::machine::heap::Heap; let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default()); - for (subterm_loc, meta_spec) in (term.focus + 1..term.focus + arity + 1).zip(meta_specs) { + let focus = { + let heap = loader.machine_heap(); + let focus_cell = + heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(term.focus))); + + if focus_cell.get_tag() == HeapCellValueTag::Str { + focus_cell.get_value() as usize + } else { + return index_ptrs; + } + }; + + for (subterm_loc, meta_spec) in (focus + 1..focus + arity + 1).zip(meta_specs) { if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec { let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); From eef7b06919202991b03172c25a2769dabc72d348 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 15 Mar 2025 02:10:56 -0700 Subject: [PATCH 016/122] make write_with forward return values, use it to correct partial string handling --- src/machine/heap.rs | 80 +++++++++++++++--------------------- src/machine/machine_state.rs | 11 +++-- src/parser/parser.rs | 58 +++++++++++++++++--------- 3 files changed, 79 insertions(+), 70 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index d628391c..efd4337c 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -183,7 +183,7 @@ impl PStrSegmentCmpResult { #[derive(Debug)] pub struct PStrWriteInfo { - pstr_loc: usize, + cell: HeapCellValue, } #[derive(Debug)] @@ -414,29 +414,40 @@ pub struct HeapWriter<'a> { heap_byte_len: &'a mut usize, } +pub(crate) struct HeapSectionWriteResult { + pub(crate) bytes_written: usize, + pub(crate) result: R, +} + impl<'a> HeapWriter<'a> { #[allow(dead_code)] - pub(crate) fn write_with_error_handling( + pub(crate) fn write_with_error_handling( &mut self, - writer: impl FnOnce(&mut ReservedHeapSection) -> Result<(), E>, - ) -> Result { + writer: impl FnOnce(&mut ReservedHeapSection) -> Result, + ) -> Result, E> { let old_section_cell_len = self.section.heap_cell_len; - writer(&mut self.section)?; + let result = writer(&mut self.section)?; *self.heap_byte_len = heap_index!(self.section.heap_cell_len); // return the number of bytes written - Ok(heap_index!( - self.section.heap_cell_len - old_section_cell_len - )) + Ok(HeapSectionWriteResult { + bytes_written: heap_index!(self.section.heap_cell_len - old_section_cell_len), + result, + }) } - pub(crate) fn write_with(&mut self, writer: impl FnOnce(&mut ReservedHeapSection)) -> usize { + pub(crate) fn write_with( + &mut self, + writer: impl FnOnce(&mut ReservedHeapSection) -> R, + ) -> HeapSectionWriteResult { let old_section_cell_len = self.section.heap_cell_len; - writer(&mut self.section); + let result = writer(&mut self.section); *self.heap_byte_len = heap_index!(self.section.heap_cell_len); - // return the number of bytes written - heap_index!(self.section.heap_cell_len - old_section_cell_len) + HeapSectionWriteResult { + bytes_written: heap_index!(self.section.heap_cell_len - old_section_cell_len), + result, + } } #[inline] @@ -854,20 +865,11 @@ impl Heap { pub fn allocate_pstr(&mut self, src: &str) -> Result, usize> { let size_in_heap = Self::compute_pstr_size(src); + let mut writer = self.reserve(size_in_heap)?; + let HeapSectionWriteResult { result, .. } = + writer.write_with(|section| section.push_pstr(src)); - let pstr_loc = heap_index!(self.cell_len()); - - Ok(if size_in_heap > 0 { - let mut writer = self.reserve(size_in_heap)?; - - writer.write_with(|section| { - section.push_pstr(src); - }); - - Some(PStrWriteInfo { pstr_loc }) - } else { - None - }) + Ok(result.map(|cell| PStrWriteInfo { cell })) } pub const fn heap_cell_alignment() -> usize { @@ -1053,7 +1055,8 @@ impl Heap { move |heap| { let mut writer = heap.reserve(size)?; let heap_byte_len = *writer.heap_byte_len; - let bytes_written = writer.write_with(&mut functor_writer); + let HeapSectionWriteResult { bytes_written, .. } = + writer.write_with(&mut functor_writer); Ok(if cell_index!(bytes_written) > 1 { str_loc_as_cell!(cell_index!(heap_byte_len)) @@ -1108,19 +1111,18 @@ impl MachineState { pub(crate) fn allocate_pstr(&mut self, src: &str) -> Result { match self.heap.allocate_pstr(src)? { None => Ok(empty_list_as_cell!()), - Some(PStrWriteInfo { pstr_loc, .. }) => Ok(pstr_loc_as_cell!(pstr_loc)), + Some(PStrWriteInfo { cell }) => Ok(cell), } } - // note that allocate_cstr does emit a tail cell to the string - // (completing it with the empty list), allocate_pstr does not, in - // any incarnation. + // note that allocate_cstr emits a tail cell to the string (completing it with the empty list) + // unlike any version of allocate_pstr. pub(crate) fn allocate_cstr(&mut self, src: &str) -> Result { match self.heap.allocate_pstr(src)? { None => Ok(empty_list_as_cell!()), - Some(PStrWriteInfo { pstr_loc, .. }) => { + Some(PStrWriteInfo { cell }) => { self.heap.push_cell(empty_list_as_cell!())?; - Ok(pstr_loc_as_cell!(pstr_loc)) + Ok(cell) } } } @@ -1281,17 +1283,3 @@ pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option Parser<'a> { match as_partial_string(&self.terms, head, tail) { Some((string_buf, tail_opt)) => { - let bytes_written = self.terms.write_with(|section| { - let pstr_cell = section.push_pstr(&string_buf).unwrap(); - section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); - section.push_cell(pstr_cell); - }); + let HeapSectionWriteResult { bytes_written, .. } = + self.terms.write_with(|section| { + if let Some(pstr_cell) = section.push_pstr(&string_buf) { + section + .push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); + section.push_cell(pstr_cell); + } else { + section.push_cell(empty_list_as_cell!()); + } + }); - let heap_loc = cell_index!(bytes_written) - 1 + cell_len; - - TokenType::Term { - heap_loc: heap_loc_as_cell!(heap_loc), + if cell_index!(bytes_written) > 1 { + TokenType::Term { + heap_loc: heap_loc_as_cell!( + cell_index!(bytes_written) - 1 + cell_len + ), + } + } else { + TokenType::Term { + heap_loc: heap_loc_as_cell!(cell_len), + } } } None => { - let bytes_written = self.terms.write_with(|section| { - section.push_cell(head); - section.push_cell(tail); - section.push_cell(list_loc_as_cell!(term_idx)); - }); + let HeapSectionWriteResult { bytes_written, .. } = + self.terms.write_with(|section| { + section.push_cell(head); + section.push_cell(tail); + section.push_cell(list_loc_as_cell!(term_idx)); + }); TokenType::Term { heap_loc: heap_loc_as_cell!( @@ -911,13 +923,19 @@ impl<'a> Parser<'a> { Some((string_buf, tail_opt)) => { self.terms.truncate(pre_terms_len); - let bytes_written = self.terms.write_with(|section| { - let pstr_cell = section.push_pstr(&string_buf).unwrap(); - section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); - section.push_cell(pstr_cell); - }); + let HeapSectionWriteResult { bytes_written, .. } = + self.terms.write_with(|section| { + if let Some(pstr_cell) = section.push_pstr(&string_buf) { + section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); + section.push_cell(pstr_cell); + } + }); - heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1) + if bytes_written > 0 { + heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1) + } else { + empty_list_as_cell!() + } } None => { heap_loc_as_cell!(list_loc) // head_term From 9e1e99f96188f484fafb3e1ee32bd656eeaaa2ab Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 15 Mar 2025 13:19:26 -0700 Subject: [PATCH 017/122] Revert "remove Term" This reverts commit 3b5879841aedecba5057c70c71da0ba23e5cd84a. --- build/instructions_template.rs | 12 +- src/allocator.rs | 17 +- src/arithmetic.rs | 228 ++++-- src/atom_table.rs | 60 +- src/codegen.rs | 982 ++++++++++------------ src/debray_allocator.rs | 259 ++---- src/forms.rs | 250 +++--- src/functor_macro.rs | 9 + src/heap_iter.rs | 78 +- src/heap_print.rs | 18 +- src/indexing.rs | 169 ++-- src/iterators.rs | 473 ++++++----- src/lib/atts.pl | 2 +- src/lib/builtins.pl | 20 +- src/lib/si.pl | 1 + src/loader.pl | 1 + src/machine/arithmetic_ops.rs | 25 +- src/machine/attributed_variables.rs | 17 +- src/machine/compile.rs | 92 +-- src/machine/disjuncts.rs | 1042 ++++++++++-------------- src/machine/dispatch.rs | 6 +- src/machine/gc.rs | 31 +- src/machine/heap.rs | 293 ++----- src/machine/lib_machine/mod.rs | 130 +-- src/machine/load_state.rs | 6 +- src/machine/loader.rs | 345 ++++---- src/machine/machine_errors.rs | 33 +- src/machine/machine_indices.rs | 34 +- src/machine/machine_state.rs | 192 ++--- src/machine/machine_state_impl.rs | 47 +- src/machine/mock_wam.rs | 85 +- src/machine/mod.rs | 1 - src/machine/partial_string.rs | 30 +- src/machine/preprocessor.rs | 734 ++++++++--------- src/machine/raw_block.rs | 16 +- src/machine/stack.rs | 7 - src/machine/streams.rs | 95 +-- src/machine/system_calls.rs | 260 +++--- src/machine/term_stream.rs | 32 +- src/machine/unify.rs | 19 +- src/macros.rs | 9 +- src/parser/ast.rs | 557 +++++-------- src/parser/lexer.rs | 136 ++-- src/parser/parser.rs | 987 +++++++++------------- src/raw_block.rs | 2 +- src/read.rs | 277 ++++++- src/targets.rs | 37 +- src/tests/builtins.pl | 2 +- src/tests/call_with_inference_limit.pl | 2 +- src/types.rs | 64 ++ src/variable_records.rs | 14 +- tests-pl/iso-conformity-tests.pl | 3 +- tests/scryer/src_tests.rs | 2 +- 53 files changed, 3726 insertions(+), 4517 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 18102af8..baa59626 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -194,9 +194,9 @@ enum ReplCodePtr { DynamicProperty, #[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))] AbolishClause, - #[strum_discriminants(strum(props(Arity = "2", Name = "$asserta")))] + #[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))] Asserta, - #[strum_discriminants(strum(props(Arity = "2", Name = "$assertz")))] + #[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))] Assertz, #[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))] Retract, @@ -3126,6 +3126,14 @@ pub fn generate_instructions_rs() -> TokenStream { } } + pub fn name(&self) -> Atom { + match self { + #( + #clause_type_name_arms, + )* + } + } + pub fn is_inbuilt(name: Atom, arity: usize) -> bool { matches!((name, arity), #(#is_inbuilt_arms)|* diff --git a/src/allocator.rs b/src/allocator.rs index 735b013f..b4529d82 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -2,9 +2,10 @@ use crate::parser::ast::*; use crate::forms::*; use crate::instructions::*; -use crate::machine::heap::Heap; use crate::targets::*; +use std::cell::Cell; + pub(crate) trait Allocator { fn new() -> Self; @@ -18,21 +19,22 @@ pub(crate) trait Allocator { fn mark_non_var<'a, Target: CompilationTarget<'a>>( &mut self, lvl: Level, - heap_loc: usize, context: GenContext, + cell: &'a Cell, code: &mut CodeDeque, - ) -> RegType; + ); #[allow(clippy::too_many_arguments)] fn mark_reserved_var<'a, Target: CompilationTarget<'a>>( &mut self, var_num: usize, lvl: Level, - context: GenContext, + cell: &Cell, + term_loc: GenContext, code: &mut CodeDeque, r: RegType, is_new_var: bool, - ) -> RegType; + ); fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType; @@ -40,13 +42,14 @@ pub(crate) trait Allocator { &mut self, var_num: usize, lvl: Level, + cell: &Cell, context: GenContext, code: &mut CodeDeque, - ) -> RegType; + ); fn reset(&mut self); fn reset_arg(&mut self, arg_num: usize); - fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize); + fn reset_at_head(&mut self, args: &[Term]); fn reset_contents(&mut self); fn advance_arg(&mut self); diff --git a/src/arithmetic.rs b/src/arithmetic.rs index dc03c8db..4863932a 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -7,8 +7,6 @@ use crate::debray_allocator::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::*; -use crate::machine::disjuncts::*; -use crate::machine::stack::Stack; use crate::targets::QueryInstruction; use crate::types::*; @@ -22,6 +20,7 @@ use dashu::base::BitTest; use num_order::NumOrd; use ordered_float::{Float, OrderedFloat}; +use std::cell::Cell; use std::cmp::{max, min, Ordering}; use std::convert::TryFrom; use std::f64; @@ -52,8 +51,89 @@ impl Default for ArithmeticTerm { } } +#[derive(Debug)] +pub(crate) struct ArithInstructionIterator<'a> { + state_stack: Vec>, +} + pub(crate) type ArithCont = (CodeDeque, Option); +impl<'a> ArithInstructionIterator<'a> { + fn push_subterm(&mut self, lvl: Level, term: &'a Term) { + self.state_stack + .push(TermIterState::subterm_to_state(lvl, term)); + } + + fn from(term: &'a Term) -> Result { + let state = match term { + Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), + Term::Clause(cell, name, terms) => { + TermIterState::Clause(Level::Shallow, 0, cell, *name, terms) + } + Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons), + Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => { + return Err(ArithmeticError::NonEvaluableFunctor( + Literal::Atom(atom!(".")), + 2, + )) + } + Term::Var(cell, var_ptr) => TermIterState::Var(Level::Shallow, cell, var_ptr.clone()), + }; + + Ok(ArithInstructionIterator { + state_stack: vec![state], + }) + } +} + +#[derive(Debug)] +pub(crate) enum ArithTermRef<'a> { + Literal(Literal), + Op(Atom, usize), // name, arity. + Var(Level, &'a Cell, VarPtr), +} + +impl<'a> Iterator for ArithInstructionIterator<'a> { + type Item = Result, ArithmeticError>; + + fn next(&mut self) -> Option { + while let Some(iter_state) = self.state_stack.pop() { + match iter_state { + TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)), + TermIterState::Clause(lvl, child_num, cell, name, subterms) => { + let arity = subterms.len(); + + if child_num == arity { + return Some(Ok(ArithTermRef::Op(name, arity))); + } else { + self.state_stack.push(TermIterState::Clause( + lvl, + child_num + 1, + cell, + name, + subterms, + )); + + self.push_subterm(lvl.child_level(), &subterms[child_num]); + } + } + TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(*c))), + TermIterState::Var(lvl, cell, var_ptr) => { + return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr))); + } + _ => { + return Some(Err(ArithmeticError::NonEvaluableFunctor( + Literal::Atom(atom!(".")), + 2, + ))); + } + }; + } + + None + } +} + #[derive(Debug)] pub(crate) struct ArithmeticEvaluator<'a> { marker: &'a mut DebrayAllocator, @@ -61,47 +141,37 @@ pub(crate) struct ArithmeticEvaluator<'a> { interm_c: usize, } -fn push_literal(interm: &mut Vec, c: HeapCellValue) -> Result<(), ArithmeticError> { - let c = unmark_cell_bits!(c); +pub(crate) trait ArithmeticTermIter<'a> { + type Iter: Iterator, ArithmeticError>>; - read_heap_cell!(c, - (HeapCellValueTag::Fixnum, n) => { - interm.push(ArithmeticTerm::Number(Number::Fixnum(n))) - } - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::Integer, n) => { - interm.push(ArithmeticTerm::Number(Number::Integer(n))); - } - (ArenaHeaderTag::Rational, n) => { - interm.push(ArithmeticTerm::Number(Number::Rational(n))); - } - _ => return Err(ArithmeticError::NonEvaluableFunctor(c, 0)), - ); - } - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); + fn iter(self) -> Result; +} - match name { - atom!("pi") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(std::f64::consts::PI)), - )), - atom!("epsilon") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(std::f64::EPSILON)), - )), - atom!("e") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(std::f64::consts::E)), - )), - _ => unreachable!(), - } - } - (HeapCellValueTag::F64, n) => { - interm.push(ArithmeticTerm::Number(Number::Float(*n))); - } - _ => { - return Err(ArithmeticError::NonEvaluableFunctor(c, 0)); - } - ); +impl<'a> ArithmeticTermIter<'a> for &'a Term { + type Iter = ArithInstructionIterator<'a>; + + fn iter(self) -> Result { + ArithInstructionIterator::from(self) + } +} + +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::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))), + Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))), + Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(std::f64::consts::E)), + )), + Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(std::f64::consts::PI)), + )), + Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(f64::EPSILON)), + )), + _ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)), + } Ok(()) } @@ -143,7 +213,7 @@ impl<'a> ArithmeticEvaluator<'a> { atom!("float_fractional_part") => Ok(Instruction::FloatFractionalPart(a1, t)), atom!("sign") => Ok(Instruction::Sign(a1, t)), atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)), - _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 1)), + _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)), } } @@ -175,7 +245,7 @@ impl<'a> ArithmeticEvaluator<'a> { atom!("rem") => Ok(Instruction::Rem(a1, a2, t)), atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)), atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)), - _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 2)), + _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)), } } @@ -231,7 +301,7 @@ impl<'a> ArithmeticEvaluator<'a> { self.get_binary_instr(name, a1, a2, ninterm) } _ => Err(ArithmeticError::NonEvaluableFunctor( - atom_as_cell!(name), + Literal::Atom(name), arity, )), } @@ -239,62 +309,44 @@ impl<'a> ArithmeticEvaluator<'a> { pub(crate) fn compile_is( &mut self, - src: &mut FocusedHeapRefMut, - term_loc: usize, - context: GenContext, + src: &'a Term, + term_loc: GenContext, arg: usize, ) -> Result { let mut code = CodeDeque::new(); - let mut stack = Stack::uninitialized(); - let mut iter = query_iterator::(&mut src.heap, &mut stack, term_loc); - let chunk_num = context.chunk_num(); + 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(); - while let Some(term) = iter.next() { - read_heap_cell!(term, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { - let lvl = iter.level(); + 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 r = match self.marker.var_data.var_locs_to_nums.get(VarPtrIndex { chunk_num, term_loc }) { - VarPtr::Numbered(var_num) => { - let old_r = self.marker.get_var_binding(var_num); - - if lvl == Level::Root { - self.marker.mark_non_callable(var_num, arg, context, &mut code) - } else if context.is_last() || old_r.reg_num() == 0 { - let r = old_r; - - if r.reg_num() == 0 { - self.marker.mark_var::( - var_num, lvl, context, &mut code, - ) - } else { - self.marker.increment_running_count(var_num); - r - } - } else { - self.marker.increment_running_count(var_num); - old_r - } - } - VarPtr::Anon => { - self.marker.mark_anon_var::(lvl, context, &mut code) + if r.reg_num() == 0 { + self.marker.mark_var::( + var_num, lvl, cell, term_loc, &mut code, + ); + cell.get().norm() + } else { + self.marker.increment_running_count(var_num); + r } + } else { + self.marker.increment_running_count(var_num); + cell.get().norm() }; self.interm.push(ArithmeticTerm::Reg(r)); } - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - push_literal(&mut self.interm, atom_as_cell!(name))?; - } else { - code.push_back(self.instr_from_clause(name, arity)?); - } + ArithTermRef::Op(name, arity) => { + code.push_back(self.instr_from_clause(name, arity)?); } - _ => { - push_literal(&mut self.interm, term)?; - } - ); + } } Ok((code, self.interm.pop())) diff --git a/src/atom_table.rs b/src/atom_table.rs index 67aaa966..09922b17 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -222,7 +222,7 @@ pub enum AtomString<'a> { Dynamic(AtomTableRef), } -fn inlined_to_str<'a>(bytes: &'a [u8; 8]) -> &'a str { +fn inlined_to_str(bytes: &[u8; 8]) -> &str { // allow the '\0\' atom to be represented as the 0-valued inlined atom let slice_len = if bytes[0] == 0 { 1 @@ -543,61 +543,3 @@ impl AtomTable { unsafe impl Send for AtomTable {} unsafe impl Sync for AtomTable {} - -/* -#[bitfield] -#[repr(u64)] -#[derive(Copy, Clone, Debug)] -pub struct AtomCell { - name: B48, - arity: B10, - #[allow(unused)] - f: bool, - #[allow(unused)] - m: bool, - #[allow(unused)] - inlined: bool, - #[allow(unused)] - tag: B3, -} - -impl AtomCell { - #[inline] - pub fn build_with(name: u64, arity: u16, tag: HeapCellValueTag) -> Self { - if arity > 0 { - debug_assert!(arity as usize <= MAX_ARITY); - - AtomCell::new() - .with_name(name) - .with_arity(arity) - .with_f(false) - .with_tag(tag as u8) - } else { - AtomCell::new() - .with_name(name) - .with_f(false) - .with_tag(tag as u8) - } - } - - #[inline] - pub fn get_index(self) -> usize { - self.name() as usize - } - - #[inline] - pub fn get_name(self) -> Atom { - Atom::from((self.get_index() as u64) << 3) - } - - #[inline] - pub fn get_arity(self) -> usize { - self.arity() as usize - } - - #[inline] - pub fn get_name_and_arity(self) -> (Atom, usize) { - (Atom::from((self.get_index() as u64) << 3), self.get_arity()) - } -} -*/ diff --git a/src/codegen.rs b/src/codegen.rs index 3118d649..41458653 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,5 +1,4 @@ use crate::allocator::*; -use crate::arena::ArenaHeaderTag; use crate::arithmetic::*; use crate::atom_table::*; use crate::debray_allocator::*; @@ -7,7 +6,6 @@ use crate::forms::*; use crate::indexing::*; use crate::instructions::*; use crate::iterators::*; -use crate::machine::heap::*; use crate::parser::ast::*; use crate::targets::*; use crate::types::*; @@ -15,15 +13,12 @@ use crate::variable_records::*; use crate::machine::disjuncts::*; use crate::machine::machine_errors::*; -use crate::machine::machine_indices::CodeIndex; -use crate::machine::stack::Stack; use fxhash::FxBuildHasher; -use indexmap::IndexMap; use indexmap::IndexSet; +use std::cell::Cell; use std::collections::VecDeque; -use std::rc::Rc; #[derive(Debug)] pub struct BranchCodeStack { @@ -281,26 +276,36 @@ pub(crate) struct CodeGenerator { } impl DebrayAllocator { + fn mark_var_in_non_callable( + &mut self, + var_num: usize, + term_loc: GenContext, + vr: &Cell, + code: &mut CodeDeque, + ) -> RegType { + self.mark_var::(var_num, Level::Shallow, vr, term_loc, code); + vr.get().norm() + } + pub(crate) fn mark_non_callable( &mut self, var_num: usize, arg: usize, - context: GenContext, + term_loc: GenContext, + vr: &Cell, code: &mut CodeDeque, ) -> RegType { - match self.get_var_binding(var_num) { + match self.get_binding(var_num) { RegType::Temp(t) if t != 0 => RegType::Temp(t), RegType::Perm(p) if p != 0 => { - if let GenContext::Last(_) = context { - self.mark_var::(var_num, Level::Shallow, context, code); + if let GenContext::Last(_) = term_loc { + self.mark_var_in_non_callable(var_num, term_loc, vr, code); temp_v!(arg) } else { - if let VarAlloc::Perm { - allocation: PermVarAllocation::Pending, - .. - } = &self.var_data.records[var_num].allocation + if let VarAlloc::Perm(_, PermVarAllocation::Pending) = + &self.var_data.records[var_num].allocation { - self.mark_var::(var_num, Level::Shallow, context, code); + self.mark_var_in_non_callable(var_num, term_loc, vr, code); } else { self.increment_running_count(var_num); } @@ -308,14 +313,14 @@ impl DebrayAllocator { RegType::Perm(p) } } - _ => self.mark_var::(var_num, Level::Shallow, context, code), + _ => self.mark_var_in_non_callable(var_num, term_loc, vr, code), } } } trait AddToFreeList<'a, Target: CompilationTarget<'a>> { fn add_term_to_free_list(&mut self, r: RegType); - fn add_subterm_to_free_list(&mut self, r: RegType); + fn add_subterm_to_free_list(&mut self, term: &Term); } impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator { @@ -323,7 +328,7 @@ impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator { self.marker.add_reg_to_free_list(r); } - fn add_subterm_to_free_list(&mut self, _r: RegType) {} + fn add_subterm_to_free_list(&mut self, _term: &Term) {} } impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator { @@ -331,27 +336,21 @@ impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator { fn add_term_to_free_list(&mut self, _r: RegType) {} #[inline(always)] - fn add_subterm_to_free_list(&mut self, r: RegType) { - self.marker.add_reg_to_free_list(r); + fn add_subterm_to_free_list(&mut self, term: &Term) { + if let Some(cell) = structure_cell(term) { + self.marker.add_reg_to_free_list(cell.get()); + } } } -fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>( - index_ptrs: &IndexMap, - heap: &Heap, - heap_loc: usize, -) -> Option { - if let Some(index_ptr) = index_ptrs.get(&heap_loc) { - let subterm = HeapCellValue::from(*index_ptr); - return Some(Target::constant_subterm(subterm)); - } else if !heap[heap_loc.saturating_sub(1)].get_mark_bit() { - if let Some(index_ptr) = fetch_index_ptr(heap, heap_loc) { - let subterm = HeapCellValue::from(index_ptr); - return Some(Target::constant_subterm(subterm)); - } +fn structure_cell(term: &Term) -> Option<&Cell> { + match term { + &Term::Cons(ref cell, ..) + | &Term::Clause(ref cell, ..) + | Term::PartialString(ref cell, ..) + | Term::CompleteString(ref cell, ..) => Some(cell), + _ => None, } - - None } impl CodeGenerator { @@ -379,13 +378,14 @@ impl CodeGenerator { fn deep_var_instr<'a, Target: crate::targets::CompilationTarget<'a>>( &mut self, + cell: &'a Cell, var_num: usize, - context: GenContext, + term_loc: GenContext, target: &mut CodeDeque, ) { if self.marker.var_data.records[var_num].num_occurrences > 1 { self.marker - .mark_var::(var_num, Level::Deep, context, target); + .mark_var::(var_num, Level::Deep, cell, term_loc, target); } else { Self::add_or_increment_void_instr::(target); } @@ -393,212 +393,134 @@ impl CodeGenerator { fn subterm_to_instr<'a, Target: crate::targets::CompilationTarget<'a>>( &mut self, - subterm: HeapCellValue, - heap_loc: usize, - context: GenContext, - index_ptrs: &IndexMap, + subterm: &'a Term, + term_loc: GenContext, target: &mut CodeDeque, - ) -> Option { - let subterm = unmark_cell_bits!(subterm); - let chunk_num = context.chunk_num(); - - read_heap_cell!(subterm, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { - match self.marker.var_data.var_locs_to_nums.get(VarPtrIndex { chunk_num, term_loc }) { - VarPtr::Numbered(var_num) => { - self.deep_var_instr::( - var_num, - context, - target, - ); - } - VarPtr::Anon => { - Self::add_or_increment_void_instr::(target); - } - } - - None + ) { + match subterm { + &Term::AnonVar => { + Self::add_or_increment_void_instr::(target); } - (HeapCellValueTag::Atom, (name, _arity)) => { - 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(atom_as_cell!(name))); - } - - None + &Term::Cons(ref cell, ..) + | &Term::Clause(ref cell, ..) + | Term::PartialString(ref cell, ..) + | Term::CompleteString(ref cell, ..) => { + self.marker + .mark_non_var::(Level::Deep, term_loc, cell, target); + target.push_back(Target::clause_arg_to_instr(cell.get())); } - (HeapCellValueTag::Str - | HeapCellValueTag::Lis - | HeapCellValueTag::PStrLoc) => { - let r = self.marker.mark_non_var::(Level::Deep, heap_loc, context, target); - target.push_back(Target::clause_arg_to_instr(r)); - return Some(r); + Term::Literal(_, ref constant) => { + target.push_back(Target::constant_subterm(*constant)); } - _ => { - target.push_back(Target::constant_subterm(subterm)); - None + Term::Var(ref cell, ref var_ptr) => { + self.deep_var_instr::( + cell, + var_ptr.to_var_num().unwrap(), + term_loc, + target, + ); } - ) + }; } - fn compile_target<'a, Target, Iter>( - &mut self, - mut iter: Iter, - index_ptrs: &IndexMap, - context: GenContext, - ) -> CodeDeque + fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, context: GenContext) -> CodeDeque where Target: crate::targets::CompilationTarget<'a>, - Iter: TermIterator, + Iter: Iterator>, CodeGenerator: AddToFreeList<'a, Target>, { let mut target = CodeDeque::new(); - let chunk_num = context.chunk_num(); - while let Some(term) = iter.next() { - let lvl = iter.level(); - let term = unmark_cell_bits!(term); - - read_heap_cell!(term, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { - if lvl == Level::Shallow { - match self.marker.var_data.var_locs_to_nums.get( - VarPtrIndex { chunk_num, term_loc } - ) { - VarPtr::Numbered(var_num) => { - self.marker.mark_var::( - var_num, - lvl, - context, - &mut target, - ); - } - VarPtr::Anon => { - if let GenContext::Head = context { - self.marker.advance_arg(); - } else { - self.marker.mark_anon_var::(lvl, context, &mut target); - } - } - } - } - } - (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, heap_loc) { - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(instr); - target.push_back(Target::to_structure(lvl, name, 0, r)); - } else if lvl == Level::Shallow { - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(Target::to_constant(lvl, atom_as_cell!(name), r)); - } + for term in iter { + match term { + TermRef::AnonVar(lvl @ Level::Shallow) => { + if let GenContext::Head = context { + self.marker.advance_arg(); } else { - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - - >::add_term_to_free_list( - self, - r, - ); - - if let Some(instr) = add_index_ptr::(index_ptrs, &iter, heap_loc) { - target.push_back(instr); - } - - target.push_back(Target::to_structure(lvl, name, arity, 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, subterm_loc, context, index_ptrs, &mut target, - ) - }) - .collect(); - - for r_opt in free_list_regs { - if let Some(r) = r_opt { - >::add_subterm_to_free_list( - self, r, - ); - } - } + self.marker + .mark_anon_var::(lvl, context, &mut target); } } - (HeapCellValueTag::Lis, l) => { - let heap_loc = iter.focus().value() as usize; - let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); + TermRef::Clause(lvl, cell, name, terms) => { + let terms_range = + if let Some(subterm @ Term::Literal(_, Literal::CodeIndex(_))) = + terms.last() + { + self.subterm_to_instr::(subterm, context, &mut target); + 0..terms.len() - 1 + } else { + 0..terms.len() + }; - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - - target.push_back(Target::to_list(lvl, r)); + self.marker + .mark_non_var::(lvl, context, cell, &mut target); + target.push_back(Target::to_structure(lvl, name, terms_range.end, cell.get())); >::add_term_to_free_list( self, - r, + cell.get(), ); - let (head_loc, head) = subterm_index(iter.deref(), l); - let (tail_loc, tail) = subterm_index(iter.deref(), l+1); - - let head_r_opt = self.subterm_to_instr::( - head, - head_loc, - context, - index_ptrs, - &mut target, - ); - - let tail_r_opt = self.subterm_to_instr::( - tail, - tail_loc, - context, - index_ptrs, - &mut target, - ); - - if let Some(r) = head_r_opt { - >::add_subterm_to_free_list( - self, r, - ); + for subterm in &terms[terms_range.clone()] { + self.subterm_to_instr::(subterm, context, &mut target); } - if let Some(r) = tail_r_opt { + for subterm in &terms[terms_range] { >::add_subterm_to_free_list( - self, r, + self, subterm, ); } } - (HeapCellValueTag::PStrLoc, pstr_loc) => { - let heap_loc = iter.focus().value() as usize; - let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - let HeapStringScan { string, tail_idx } = iter.scan_slice_to_str(pstr_loc); + TermRef::Cons(lvl, cell, head, tail) => { + self.marker + .mark_non_var::(lvl, context, cell, &mut target); + target.push_back(Target::to_list(lvl, cell.get())); - target.push_back(Target::to_pstr(lvl, Rc::new(string.to_owned()), r)); + >::add_term_to_free_list( + self, + cell.get(), + ); - let (tail_loc, tail) = subterm_index(iter.deref(), tail_idx); - self.subterm_to_instr::( - tail, tail_loc, context, index_ptrs, &mut target, + self.subterm_to_instr::(head, context, &mut target); + self.subterm_to_instr::(tail, context, &mut target); + + >::add_subterm_to_free_list( + self, head, + ); + >::add_subterm_to_free_list( + self, tail, ); } - _ if lvl == Level::Shallow => { - if term.is_constant() { - let heap_loc = iter.focus().value() as usize; - let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(Target::to_constant(lvl, term, r)); - } + TermRef::Literal(lvl @ Level::Shallow, cell, constant) => { + self.marker + .mark_non_var::(lvl, context, cell, &mut target); + target.push_back(Target::to_constant(lvl, *constant, cell.get())); + } + TermRef::PartialString(lvl, cell, string, tail) => { + self.marker + .mark_non_var::(lvl, context, cell, &mut target); + + target.push_back(Target::to_pstr(lvl, string.clone(), cell.get())); + self.subterm_to_instr::(tail, context, &mut target); + } + TermRef::CompleteString(lvl, cell, string) => { + self.marker + .mark_non_var::(lvl, context, cell, &mut target); + + target.push_back(Target::to_pstr(lvl, string.clone(), cell.get())); + target.push_back(Target::constant_subterm(Literal::Atom(atom!("[]")))); + } + TermRef::Var(lvl @ Level::Shallow, cell, var) => { + self.marker.mark_var::( + var.to_var_num().unwrap(), + lvl, + cell, + context, + &mut target, + ); } _ => {} - ); + }; } target @@ -630,57 +552,21 @@ impl CodeGenerator { fn compile_inlined( &mut self, ct: &InlinedClauseType, - terms: &mut FocusedHeapRefMut, - term_loc: usize, - context: GenContext, + terms: &'_ [Term], + term_loc: GenContext, code: &mut CodeDeque, ) -> Result<(), CompilationError> { - let first_arg_loc = terms.nth_arg(term_loc, 1).unwrap(); - let first_arg = terms.deref_loc(first_arg_loc); - - let chunk_num = context.chunk_num(); - let mut variable_marker = |marker: &mut DebrayAllocator| { - read_heap_cell!(first_arg, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, first_arg_loc) => { - match marker.var_data.var_locs_to_nums.get( - VarPtrIndex { chunk_num, term_loc: first_arg_loc }, - ) { - VarPtr::Numbered(var_num) => { - Some(marker.mark_non_callable( - var_num, - 1, - context, - code, - )) - } - VarPtr::Anon => { - Some(marker.mark_anon_var::( - Level::Shallow, - context, - code, - )) - } - } - } - _ => { - marker.advance_arg(); - None - } - ) - }; - let call_instr = match ct { &InlinedClauseType::CompareNumber(mut cmp) => { self.marker.reset_arg(2); - let (mut lcode, at_1) = if let Some(r) = variable_marker(&mut self.marker) { - (CodeDeque::default(), Some(ArithmeticTerm::Reg(r))) - } else { - self.compile_arith_expr(terms, first_arg_loc, 1, context, 1)? - }; + let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc, 1)?; - let (mut rcode, at_2) = - self.compile_arith_expr(terms, first_arg_loc + 1, 2, context, 2)?; + if !matches!(terms[0], Term::Var(..)) { + self.marker.advance_arg(); + } + + let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc, 2)?; code.append(&mut lcode); code.append(&mut rcode); @@ -690,184 +576,207 @@ impl CodeGenerator { compare_number_instr!(cmp, at_1, at_2) } - InlinedClauseType::IsAtom(..) => { - self.marker.reset_arg(1); + InlinedClauseType::IsAtom(..) => match &terms[0] { + Term::Literal(_, Literal::Atom(..)) => { + instr!("$succeed") + } + Term::Var(ref vr, ref name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); - if let Some(r) = variable_marker(&mut self.marker) { instr!("atom", r) - } else { - read_heap_cell!(first_arg, - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity == 0 { - instr!("$succeed") - } else { - instr!("$fail") - } - } - _ => { - instr!("$fail") - } - ) } - } - InlinedClauseType::IsAtomic(..) => { - self.marker.reset_arg(1); + _ => { + instr!("$fail") + } + }, + InlinedClauseType::IsAtomic(..) => match &terms[0] { + Term::AnonVar + | Term::Clause(..) + | Term::Cons(..) + | Term::PartialString(..) + | Term::CompleteString(..) => { + instr!("$fail") + } + Term::Literal(..) => { + instr!("$succeed") + } + Term::Var(ref vr, ref name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); - if let Some(r) = variable_marker(&mut self.marker) { instr!("atomic", r) - } else { - read_heap_cell!(first_arg, - (HeapCellValueTag::Fixnum | - HeapCellValueTag::F64) => { - instr!("$succeed") - } - (HeapCellValueTag::Cons, cons_ptr) => { - match cons_ptr.get_tag() { - ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => { - instr!("$succeed") - } - _ => { - instr!("$fail") - } - } - } - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity == 0 { - instr!("$succeed") - } else { - instr!("$fail") - } - } - (HeapCellValueTag::Lis - | HeapCellValueTag::Str - | HeapCellValueTag::PStrLoc) => { - instr!("$fail") - } - _ => { - if first_arg.is_constant() { - instr!("$succeed") - } else { - instr!("$fail") - } - } - ) } - } - InlinedClauseType::IsCompound(..) => { - self.marker.reset_arg(1); + }, + InlinedClauseType::IsCompound(..) => match &terms[0] { + Term::Clause(..) + | Term::Cons(..) + | Term::PartialString(..) + | Term::CompleteString(..) => { + instr!("$succeed") + } + Term::Var(ref vr, ref name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); - if let Some(r) = variable_marker(&mut self.marker) { instr!("compound", r) - } else { - read_heap_cell!(first_arg, - (HeapCellValueTag::Atom, (_, arity)) => { - if arity > 0 { - instr!("$succeed") - } else { - instr!("$fail") - } - } - (HeapCellValueTag::Lis - | HeapCellValueTag::Str - | HeapCellValueTag::PStrLoc) => { - instr!("$succeed") - } - _ => { - instr!("$fail") - } - ) } - } - InlinedClauseType::IsRational(..) => { - self.marker.reset_arg(1); - - if let Some(r) = variable_marker(&mut self.marker) { + _ => { + instr!("$fail") + } + }, + InlinedClauseType::IsRational(..) => match terms[0] { + Term::Literal(_, Literal::Rational(_)) => { + instr!("$succeed") + } + Term::Var(ref vr, ref name) => { + self.marker.reset_arg(1); + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); instr!("rational", r) - } else { - read_heap_cell!(first_arg, - (HeapCellValueTag::Cons, cons_ptr) => { - match cons_ptr.get_tag() { - ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => { - instr!("$succeed") - } - _ => { - instr!("$fail") - } - } - } - (HeapCellValueTag::Fixnum) => { - instr!("$succeed") - } - _ => { - instr!("$fail") - } - ) } - } - InlinedClauseType::IsFloat(..) => { - self.marker.reset_arg(1); + _ => { + instr!("$fail") + } + }, + InlinedClauseType::IsFloat(..) => match terms[0] { + Term::Literal(_, Literal::Float(_)) => { + instr!("$succeed") + } + Term::Var(ref vr, ref name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); - if let Some(r) = variable_marker(&mut self.marker) { instr!("float", r) - } else { - read_heap_cell!(first_arg, - (HeapCellValueTag::F64) => { - instr!("$succeed") - } - _ => { - instr!("$fail") - } - ) } - } - InlinedClauseType::IsNumber(..) => { - self.marker.reset_arg(1); - if let Some(r) = variable_marker(&mut self.marker) { + _ => { + instr!("$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) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); + instr!("number", r) - } else if Number::try_from(first_arg).is_ok() { - instr!("$succeed") - } else { + } + _ => { instr!("$fail") } - } - InlinedClauseType::IsNonVar(..) => { - self.marker.reset_arg(1); + }, + InlinedClauseType::IsNonVar(..) => match terms[0] { + Term::AnonVar => { + instr!("$fail") + } + Term::Var(ref vr, ref name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); - if let Some(r) = variable_marker(&mut self.marker) { instr!("nonvar", r) - } else if first_arg.is_var() { - instr!("$fail") - } else { + } + _ => { instr!("$succeed") } - } - InlinedClauseType::IsInteger(..) => { - self.marker.reset_arg(1); + }, + InlinedClauseType::IsInteger(..) => match &terms[0] { + Term::Literal(_, Literal::Integer(_)) | Term::Literal(_, Literal::Fixnum(_)) => { + instr!("$succeed") + } + Term::Var(ref vr, name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); - if let Some(r) = variable_marker(&mut self.marker) { instr!("integer", r) - } else { - match Number::try_from(first_arg) { - Ok(Number::Integer(_) | Number::Fixnum(_)) => { - instr!("$succeed") - } - _ => { - instr!("$fail") - } - } } - } - InlinedClauseType::IsVar(..) => { - self.marker.reset_arg(1); - - if let Some(r) = variable_marker(&mut self.marker) { - instr!("var", r) - } else if first_arg.is_var() { - instr!("$succeed") - } else { + _ => { 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. @@ -877,27 +786,25 @@ impl CodeGenerator { fn compile_arith_expr( &mut self, - terms: &mut FocusedHeapRefMut, - term_loc: usize, + term: &Term, target_int: usize, - context: GenContext, + term_loc: GenContext, arg: usize, ) -> Result { let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int); - evaluator.compile_is(terms, term_loc, context, arg) + evaluator.compile_is(term, term_loc, arg) } fn compile_is_call( &mut self, - terms: &mut FocusedHeapRefMut, - term_loc: usize, + terms: &[Term], code: &mut CodeDeque, - context: GenContext, + term_loc: GenContext, call_policy: CallPolicy, ) -> Result<(), CompilationError> { macro_rules! compile_expr { - ($self:expr, $terms:expr, $context:expr, $code:expr) => {{ - let (acode, at) = $self.compile_arith_expr($terms, term_loc + 2, 1, $context, 2)?; + ($self:expr, $terms:expr, $term_loc:expr, $code:expr) => {{ + let (acode, at) = $self.compile_arith_expr($terms, 1, $term_loc, 2)?; $code.extend(acode.into_iter()); at }}; @@ -905,48 +812,70 @@ impl CodeGenerator { self.marker.reset_arg(2); - let var = heap_bound_store( - terms.heap, - heap_bound_deref(terms.heap, heap_loc_as_cell!(term_loc + 1)), - ); + let at = match terms[0] { + Term::Var(ref vr, ref name) => { + let var_num = name.to_var_num().unwrap(); - let at = read_heap_cell!(var, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { - let chunk_num = context.chunk_num(); + if self.marker.var_data.records[var_num].num_occurrences > 1 { + self.marker.mark_var::( + var_num, + Level::Shallow, + vr, + term_loc, + code, + ); - match self.marker.var_data.var_locs_to_nums.get( - VarPtrIndex { chunk_num, term_loc }, - ) { - VarPtr::Numbered(var_num) => { + self.marker.mark_safe_var_unconditionally(var_num); + compile_expr!(self, &terms[1], term_loc, code) + } else { + self.marker + .mark_anon_var::(Level::Shallow, term_loc, code); + + if let Term::Var(ref vr, ref var) = &terms[1] { + let var_num = var.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::( var_num, Level::Shallow, - context, + vr, + term_loc, code, ); self.marker.mark_safe_var_unconditionally(var_num); + + let at = ArithmeticTerm::Reg(vr.get().norm()); + self.add_call(code, instr!("$get_number", at), call_policy); + + return Ok(()); } } - VarPtr::Anon => {} - }; - compile_expr!(self, terms, context, code) - } - _ => { - 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(()); + compile_expr!(self, &terms[1], term_loc, code) } } - ); + Term::Literal( + _, + c @ Literal::Integer(_) + | c @ Literal::Float(_) + | c @ Literal::Rational(_) + | c @ Literal::Fixnum(_), + ) => { + let v = HeapCellValue::from(c); + code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1))); + + self.marker.advance_arg(); + compile_expr!(self, &terms[1], term_loc, code) + } + _ => { + code.push_back(instr!("$fail")); + return Ok(()); + } + }; let at = at.unwrap_or(interm!(1)); self.add_call(code, instr!("is", temp_v!(1), at), call_policy); @@ -955,18 +884,18 @@ impl CodeGenerator { fn compile_seq( &mut self, - mut focused_heap: FocusedHeapRefMut, clauses: &ChunkedTermVec, code: &mut CodeDeque, ) -> Result<(), CompilationError> { + let mut chunk_num = 0; let mut branch_code_stack = BranchCodeStack::new(); let mut clause_iter = ClauseIterator::new(clauses); while let Some(clause_item) = clause_iter.next() { match clause_item { - ClauseItem::Chunk { chunk_num, terms } => { + ClauseItem::Chunk { terms } => { for (idx, term) in terms.iter().enumerate() { - let context = if idx + 1 < terms.len() { + let term_loc = if idx + 1 < terms.len() { GenContext::Mid(chunk_num) } else { self.marker.in_tail_position = clause_iter.in_tail_position(); @@ -995,7 +924,7 @@ impl CodeGenerator { if chunk_num == 0 { code.push_back(instr!("neck_cut")); } else { - let r = self.marker.get_var_binding(var_num); + let r = self.marker.get_binding(var_num); code.push_back(instr!("cut", r)); } @@ -1009,7 +938,7 @@ impl CodeGenerator { } &QueryTerm::LocalCut { var_num, cut_prev } => { let code = branch_code_stack.code(code); - let r = self.marker.get_var_binding(var_num); + let r = self.marker.get_binding(var_num); code.push_back(if cut_prev { instr!("cut_prev", r) @@ -1028,51 +957,31 @@ impl CodeGenerator { } } &QueryTerm::Clause( - ref clause @ QueryClause { - ct: ClauseType::BuiltIn(BuiltInClauseType::Is(..)), - call_policy, - .. - }, + _, + ClauseType::BuiltIn(BuiltInClauseType::Is(..)), + ref terms, + call_policy, ) => self.compile_is_call( - &mut focused_heap, - clause.term_loc(), + terms, branch_code_stack.code(code), - context, + term_loc, call_policy, )?, - &QueryTerm::Clause( - ref clause @ QueryClause { - ct: ClauseType::Inlined(ref ct), - .. - }, - ) => self.compile_inlined( - ct, - &mut focused_heap, - clause.term_loc(), - context, - branch_code_stack.code(code), - )?, + &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => { + self.compile_inlined( + ct, + terms, + term_loc, + branch_code_stack.code(code), + )? + } &QueryTerm::Fail => { branch_code_stack.code(code).push_back(instr!("$fail")); } - &QueryTerm::Succeed => { - let code = branch_code_stack.code(code); - - if self.marker.in_tail_position && self.marker.var_data.allocates { - code.push_back(instr!("deallocate")); - } - - code.push_back(if self.marker.in_tail_position { - instr!("$succeed").into_execute() - } else { - instr!("$succeed") - }); - } - QueryTerm::Clause(clause) => { + term @ &QueryTerm::Clause(..) => { self.compile_query_line( - &mut focused_heap, - clause, - context, + term, + term_loc, branch_code_stack.code(code), ); @@ -1083,6 +992,7 @@ impl CodeGenerator { } } + chunk_num += 1; self.marker.in_tail_position = false; self.marker.reset_contents(); } @@ -1130,32 +1040,20 @@ impl CodeGenerator { pub(crate) fn compile_rule( &mut self, - heap: &mut Heap, - rule: &mut Rule, + rule: &Rule, var_data: VarData, ) -> Result { - let Rule { term_loc, clauses } = rule; - + let Rule { + head: (_, args), + clauses, + } = rule; self.marker.var_data = var_data; - - let term = FocusedHeapRefMut { - heap, - focus: *term_loc, - }; let mut code = VecDeque::new(); - let head_loc = term.nth_arg(term.focus, 1).unwrap(); + self.marker.reset_at_head(args); - self.marker.reset_at_head(term.heap, head_loc); - - let mut stack = Stack::uninitialized(); - let iter = fact_iterator::(term.heap, &mut stack, head_loc); - - let fact = self.compile_target::( - iter, - &IndexMap::with_hasher(FxBuildHasher::default()), - GenContext::Head, - ); + let iter = FactIterator::from_rule_head_clause(args); + let fact = self.compile_target::(iter, GenContext::Head); if self.marker.max_reg_allocated() > MAX_ARITY { return Err(CompilationError::ExceededMaxArity); @@ -1164,72 +1062,61 @@ impl CodeGenerator { self.marker.reset_free_list(); code.extend(fact); - self.compile_seq(term, &clauses, &mut code)?; + self.compile_seq(clauses, &mut code)?; Ok(Vec::from(code)) } pub(crate) fn compile_fact( &mut self, - heap: &mut Heap, - fact: &mut Fact, + fact: &Fact, var_data: VarData, ) -> Result { let mut code = Vec::new(); - - let mut stack = Stack::uninitialized(); - self.marker.var_data = var_data; - self.marker.reset_at_head(heap, fact.term_loc); - let iter = fact_iterator::(heap, &mut stack, fact.term_loc); + if let Term::Clause(_, _, args) = &fact.head { + self.marker.reset_at_head(args); - let compiled_fact = self.compile_target::( - iter, - &IndexMap::with_hasher(FxBuildHasher::default()), - GenContext::Head, - ); + let iter = FactInstruction::iter(&fact.head); + let compiled_fact = self.compile_target::(iter, GenContext::Head); - if self.marker.max_reg_allocated() > MAX_ARITY { - return Err(CompilationError::ExceededMaxArity); + if self.marker.max_reg_allocated() > MAX_ARITY { + return Err(CompilationError::ExceededMaxArity); + } + + code.extend(compiled_fact); } - code.extend(compiled_fact); code.push(instr!("proceed")); - Ok(code) } - fn compile_query_line( - &mut self, - term: &mut FocusedHeapRefMut, - clause: &QueryClause, - context: GenContext, - code: &mut CodeDeque, - ) { - self.marker.reset_arg(term.arity(clause.term_loc())); + fn compile_query_line(&mut self, term: &QueryTerm, term_loc: GenContext, code: &mut CodeDeque) { + self.marker.reset_arg(term.arity()); - let mut stack = Stack::uninitialized(); - let iter = query_iterator::(&mut term.heap, &mut stack, clause.term_loc()); - - let query = self.compile_target::(iter, &clause.code_indices, context); + let iter = QueryIterator::new(term); + let query = self.compile_target::(iter, term_loc); code.extend(query); - self.add_call(code, clause.ct.to_instr(), clause.call_policy); + + match term { + &QueryTerm::Clause(_, ref ct, _, call_policy) => { + self.add_call(code, ct.to_instr(), call_policy); + } + _ => unreachable!(), + }; } - fn split_predicate(heap: &mut Heap, clauses: &[PredicateClause]) -> Vec { + fn split_predicate(clauses: &[PredicateClause]) -> Vec { let mut subseqs = Vec::new(); let mut left = 0; let mut optimal_index = 0; 'outer: for (right, clause) in clauses.iter().enumerate() { - if let Some(args) = clause.args(heap) { - for (instantiated_arg_index, arg_idx) in args.enumerate() { - let arg = heap[arg_idx]; - let arg = heap_bound_store(heap, heap_bound_deref(heap, arg)); - - if !arg.is_var() { + if let Some(args) = clause.args() { + for (instantiated_arg_index, arg) in args.iter().enumerate() { + if !matches!(arg, Term::Var(..) | Term::AnonVar) { if optimal_index != instantiated_arg_index { if left >= right { optimal_index = instantiated_arg_index; @@ -1283,7 +1170,6 @@ impl CodeGenerator { fn compile_pred_subseq( &mut self, - heap: &mut Heap, clauses: &mut [PredicateClause], optimal_index: usize, ) -> Result { @@ -1302,11 +1188,11 @@ impl CodeGenerator { let clause_code = match clause { PredicateClause::Fact(fact, var_data) => { let var_data = std::mem::take(var_data); - self.compile_fact(heap, fact, var_data)? + self.compile_fact(fact, var_data)? } PredicateClause::Rule(rule, var_data) => { let var_data = std::mem::take(var_data); - self.compile_rule(heap, rule, var_data)? + self.compile_rule(rule, var_data)? } }; @@ -1334,14 +1220,13 @@ impl CodeGenerator { skip_stub_try_me_else = !self.settings.is_dynamic(); } - let arg = clause.args(heap).map(|r| heap[r.start() + optimal_index]); + let arg = clause.args().and_then(|args| args.get(optimal_index)); if let Some(arg) = arg { let index = code.len(); if clauses_len > 1 || self.settings.is_extensible { - let arg = heap_bound_store(heap, heap_bound_deref(heap, arg)); - code_offsets.index_term(heap, arg, index, &mut clause_index_info); + code_offsets.index_term(arg, index, &mut clause_index_info); } } @@ -1371,12 +1256,11 @@ impl CodeGenerator { pub(crate) fn compile_predicate( &mut self, - heap: &mut Heap, mut clauses: Vec, ) -> Result { let mut code = Code::new(); - let split_pred = Self::split_predicate(heap, &clauses); + let split_pred = Self::split_predicate(&clauses); let multi_seq = split_pred.len() > 1; for ClauseSpan { @@ -1388,13 +1272,11 @@ impl CodeGenerator { let skel_lower_bound = self.skeleton.clauses.len(); let code_segment = if self.settings.is_dynamic() { self.compile_pred_subseq::( - heap, &mut clauses[left..right], instantiated_arg_index, )? } else { self.compile_pred_subseq::( - heap, &mut clauses[left..right], instantiated_arg_index, )? diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 7c86bb88..3bc96dfc 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -1,13 +1,10 @@ use crate::allocator::*; -use crate::atom_table::*; use crate::codegen::SubsumedBranchHits; use crate::forms::{GenContext, Level}; use crate::instructions::*; -use crate::machine::disjuncts::*; -use crate::machine::heap::*; +use crate::machine::disjuncts::VarData; use crate::parser::ast::*; use crate::targets::*; -use crate::types::*; use crate::variable_records::*; use bit_set::*; @@ -15,6 +12,7 @@ use bitvec::prelude::*; use fxhash::FxBuildHasher; use indexmap::IndexMap; +use std::cell::Cell; use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; @@ -154,8 +152,6 @@ pub(crate) struct DebrayAllocator { in_use: BitSet, // 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 { @@ -172,9 +168,7 @@ impl DebrayAllocator { for var_num in subsumed_hits { match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { - ref mut allocation, .. - } => { + VarAlloc::Perm(_, ref mut allocation) => { if let PermVarAllocation::Done { shallow_safety, deep_safety, @@ -235,7 +229,7 @@ impl DebrayAllocator { let num_occurrences = self.var_data.records[var_num].num_occurrences; match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { allocation, .. } => { + VarAlloc::Perm(_, allocation) => { let shallow_safety = VarSafetyStatus::needed_if( shallow_safety.contains(var_num), branch_designator, @@ -372,7 +366,7 @@ impl DebrayAllocator { &mut self, chunk_num: usize, code: &mut CodeDeque, - ) -> Option { + ) { if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) { let k = self.arg_c; @@ -388,12 +382,8 @@ impl DebrayAllocator { .allocation .set_register(r.reg_num()); self.in_use.insert(r.reg_num()); - - return Some(r); } }; - - None } fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>( @@ -443,7 +433,6 @@ impl DebrayAllocator { } self.temp_lb = final_index + 1; - final_index } @@ -467,11 +456,7 @@ impl DebrayAllocator { p }; - self.var_data.records[var_num].allocation = VarAlloc::Perm { - reg: p, - allocation: PermVarAllocation::done(), - }; - + self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done()); p } @@ -487,15 +472,10 @@ impl DebrayAllocator { } #[inline(always)] - pub fn get_var_binding(&self, var_num: usize) -> RegType { + pub fn get_binding(&self, var_num: usize) -> RegType { self.var_data.records[var_num].allocation.as_reg_type() } - #[inline(always)] - pub fn get_non_var_binding(&self, heap_loc: usize) -> RegType { - RegType::Temp(self.non_var_registers.get(&heap_loc).cloned().unwrap_or(0)) - } - pub fn num_perm_vars(&self) -> usize { self.perm_lb - 1 } @@ -505,7 +485,7 @@ impl DebrayAllocator { } fn add_perm_to_free_list(&mut self, chunk_num: usize, var_num: usize) { - if let VarAlloc::Perm { .. } = &self.var_data.records[var_num].allocation { + if let VarAlloc::Perm(..) = &self.var_data.records[var_num].allocation { self.perm_free_list.push_back((chunk_num, var_num)); } } @@ -516,10 +496,7 @@ impl DebrayAllocator { self.perm_free_list.pop_front(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { - reg: p, - allocation: PermVarAllocation::Pending, - } if *p > 0 => { + VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => { return Some(std::mem::replace(p, 0)); } _ => {} @@ -533,12 +510,9 @@ impl DebrayAllocator { } pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) { - match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { allocation, .. } => { - *allocation = PermVarAllocation::Pending; - self.add_perm_to_free_list(chunk_num, var_num); - } - _ => {} + if let VarAlloc::Perm(_, allocation) = &mut self.var_data.records[var_num].allocation { + *allocation = PermVarAllocation::Pending; + self.add_perm_to_free_list(chunk_num, var_num); } } @@ -546,15 +520,14 @@ impl DebrayAllocator { let branch_designator = self.branch_stack.current_branch_designator(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { - allocation: - PermVarAllocation::Done { - deep_safety, - shallow_safety, - .. - }, - .. - } => { + VarAlloc::Perm( + _, + PermVarAllocation::Done { + deep_safety, + shallow_safety, + .. + }, + ) => { *deep_safety = VarSafetyStatus::unneeded(branch_designator); *shallow_safety = VarSafetyStatus::unneeded(branch_designator); } @@ -562,8 +535,7 @@ impl DebrayAllocator { *safety = VarSafetyStatus::unneeded(branch_designator); } _ => { - // the (permanent) variable might have been freed by - // this point, in which case we do nothing. + unreachable!() } } } @@ -572,15 +544,14 @@ impl DebrayAllocator { let branch_designator = self.branch_stack.current_branch_designator(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { - allocation: - PermVarAllocation::Done { - deep_safety, - shallow_safety, - .. - }, - .. - } => { + VarAlloc::Perm( + _, + PermVarAllocation::Done { + deep_safety, + shallow_safety, + .. + }, + ) => { // GetVariable in head chunk is considered safe. if lvl == Level::Deep { *deep_safety = VarSafetyStatus::unneeded(branch_designator); @@ -617,14 +588,13 @@ impl DebrayAllocator { let branch_designator = self.branch_stack.current_branch_designator(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { - allocation: - PermVarAllocation::Done { - ref mut shallow_safety, - .. - }, - .. - } => { + VarAlloc::Perm( + _, + PermVarAllocation::Done { + ref mut shallow_safety, + .. + }, + ) => { if !self.in_tail_position || self .branch_stack @@ -654,14 +624,13 @@ impl DebrayAllocator { let branch_designator = self.branch_stack.current_branch_designator(); match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { - allocation: - PermVarAllocation::Done { - ref mut deep_safety, - .. - }, - .. - } => { + VarAlloc::Perm( + _, + PermVarAllocation::Done { + ref mut deep_safety, + .. + }, + ) => { if self .branch_stack .safety_unneeded_in_branch(deep_safety, &branch_designator) @@ -704,15 +673,13 @@ impl Allocator for DebrayAllocator { temp_free_list: vec![], perm_free_list: VecDeque::new(), branch_stack: BranchStack { stack: vec![] }, - non_var_registers: IndexMap::with_hasher(FxBuildHasher::default()), - non_var_register_heap_locs: IndexMap::with_hasher(FxBuildHasher::default()), } } fn mark_anon_var<'a, Target: CompilationTarget<'a>>( &mut self, lvl: Level, - context: GenContext, + term_loc: GenContext, code: &mut CodeDeque, ) -> RegType { let r = RegType::Temp(self.alloc_reg_to_non_var()); @@ -722,7 +689,7 @@ impl Allocator for DebrayAllocator { Level::Root | Level::Shallow => { let k = self.arg_c; - if let GenContext::Last(chunk_num) = context { + if let GenContext::Last(chunk_num) = term_loc { self.evacuate_arg::(chunk_num, code); } @@ -738,69 +705,55 @@ impl Allocator for DebrayAllocator { fn mark_non_var<'a, Target: CompilationTarget<'a>>( &mut self, lvl: Level, - heap_loc: usize, - context: GenContext, + term_loc: GenContext, + cell: &'a Cell, code: &mut CodeDeque, - ) -> RegType { - let r = self.get_non_var_binding(heap_loc); + ) { + let r = cell.get(); let r = match lvl { Level::Shallow => { let k = self.arg_c; - if let GenContext::Last(chunk_num) = context { - if let Some(new_r) = self.evacuate_arg::(chunk_num, code) { - self.non_var_register_heap_locs - .swap_remove(&k) - .map(|old_heap_loc| { - self.non_var_registers.insert(old_heap_loc, new_r.reg_num()); - self.non_var_register_heap_locs - .insert(new_r.reg_num(), old_heap_loc); - }); - - self.non_var_registers.insert(heap_loc, k); - self.non_var_register_heap_locs.insert(k, heap_loc); - } + if let GenContext::Last(chunk_num) = term_loc { + self.evacuate_arg::(chunk_num, code); } self.arg_c += 1; RegType::Temp(k) } - _ if r.reg_num() == 0 => { - let r = RegType::Temp(self.alloc_reg_to_non_var()); - self.non_var_registers.insert(heap_loc, r.reg_num()); - self.non_var_register_heap_locs - .insert(r.reg_num(), heap_loc); - r - } + _ if r.reg_num() == 0 => RegType::Temp(self.alloc_reg_to_non_var()), _ => { self.in_use.insert(r.reg_num()); r } }; - r + cell.set(r); } fn mark_var<'a, Target: CompilationTarget<'a>>( &mut self, var_num: usize, lvl: Level, - context: GenContext, + cell: &Cell, + term_loc: GenContext, code: &mut CodeDeque, - ) -> RegType { - let (r, is_new_var) = match self.get_var_binding(var_num) { + ) { + let (r, is_new_var) = match self.get_binding(var_num) { RegType::Temp(0) => { - let o = self.alloc_reg_to_var::(var_num, lvl, context, code); + let o = self.alloc_reg_to_var::(var_num, lvl, term_loc, code); + cell.set(VarReg::Norm(RegType::Temp(o))); (RegType::Temp(o), true) } RegType::Perm(0) => { - let p = self.alloc_perm_var(var_num, context.chunk_num()); + let p = self.alloc_perm_var(var_num, term_loc.chunk_num()); + cell.set(VarReg::Norm(RegType::Perm(p))); (RegType::Perm(p), true) } r @ RegType::Perm(_) => { let is_new_var = match &mut self.var_data.records[var_num].allocation { - VarAlloc::Perm { allocation, .. } => { + VarAlloc::Perm(_, allocation) => { if allocation.pending() { *allocation = PermVarAllocation::done(); true @@ -816,29 +769,32 @@ impl Allocator for DebrayAllocator { r => (r, false), }; - self.mark_reserved_var::(var_num, lvl, context, code, r, is_new_var) + self.mark_reserved_var::(var_num, lvl, cell, term_loc, code, r, is_new_var); } fn mark_reserved_var<'a, Target: CompilationTarget<'a>>( &mut self, var_num: usize, lvl: Level, - context: GenContext, + cell: &Cell, + term_loc: GenContext, code: &mut CodeDeque, r: RegType, is_new_var: bool, - ) -> RegType { + ) { match lvl { Level::Root | Level::Shallow => { let k = self.arg_c; if self.is_curr_arg_distinct_from(var_num) { - self.evacuate_arg::(context.chunk_num(), code); + self.evacuate_arg::(term_loc.chunk_num(), code); } - if !self.in_place(var_num, context, r, k) { + cell.set(VarReg::ArgAndNorm(r, k)); + + if !self.in_place(var_num, term_loc, r, k) { if is_new_var { - self.mark_safe_var(var_num, lvl, context); + self.mark_safe_var(var_num, lvl, term_loc); code.push_back(Target::argument_to_variable(r, k)); } else { code.push_back(self.argument_to_value::(var_num, r, k)); @@ -848,15 +804,15 @@ impl Allocator for DebrayAllocator { self.arg_c += 1; } Level::Deep if is_new_var => { - if let GenContext::Head = context { + if let GenContext::Head = term_loc { if self.occurs_shallowly_in_head(var_num, r.reg_num()) { code.push_back(self.subterm_to_value::(var_num, r)); } else { - self.mark_safe_var(var_num, lvl, context); + self.mark_safe_var(var_num, lvl, term_loc); code.push_back(Target::subterm_to_variable(r)); } } else { - self.mark_safe_var(var_num, lvl, context); + self.mark_safe_var(var_num, lvl, term_loc); code.push_back(Target::subterm_to_variable(r)); } } @@ -878,15 +834,14 @@ impl Allocator for DebrayAllocator { if record.running_count < record.num_occurrences { record.running_count += 1; } else { - self.free_var(context.chunk_num(), var_num); + self.free_var(term_loc.chunk_num(), var_num); } self.in_use.insert(o); - r } fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType { - match self.get_var_binding(var_num) { + match self.get_binding(var_num) { RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)), RegType::Temp(0) => { let t = self.alloc_reg_to_non_var(); @@ -910,8 +865,6 @@ impl Allocator for DebrayAllocator { fn reset(&mut self) { self.perm_lb = 1; self.shallow_temp_mappings.clear(); - self.non_var_registers.clear(); - self.non_var_register_heap_locs.clear(); self.in_use.clear(); self.temp_free_list.clear(); } @@ -919,8 +872,6 @@ impl Allocator for DebrayAllocator { fn reset_contents(&mut self) { self.in_use.clear(); self.shallow_temp_mappings.clear(); - self.non_var_registers.clear(); - self.non_var_register_heap_locs.clear(); self.temp_free_list.clear(); } @@ -928,54 +879,24 @@ impl Allocator for DebrayAllocator { self.arg_c += 1; } - fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize) { - let head_cell = heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(head_loc))); + fn reset_at_head(&mut self, args: &[Term]) { + self.reset_arg(args.len()); + self.arity = args.len(); - read_heap_cell!(head_cell, - (HeapCellValueTag::Str, s) => { - let arity = cell_as_atom_cell!(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; - - for (c_idx, heap_idx) in (s+1 ..= s+arity).enumerate() { - let arg = heap[heap_idx]; - - if arg.is_var() { - let var = heap_bound_store( - heap, - heap_bound_deref(heap, arg), - ); - - if !var.is_var() { - continue; - } - - let term_loc = var.get_value() as usize; - - match self.var_data.var_locs_to_nums.get( - VarPtrIndex { chunk_num: 0, term_loc }, - ) { - VarPtr::Numbered(var_num) => { - let r = self.get_var_binding(var_num); - - if !r.is_perm() && r.reg_num() == 0 { - self.in_use.insert(c_idx + 1); - self.shallow_temp_mappings.insert(c_idx + 1, var_num); - self.var_data.records[var_num] - .allocation - .set_register(c_idx + 1); - } - } - VarPtr::Anon => {} - } - } + if !r.is_perm() && r.reg_num() == 0 { + self.in_use.insert(idx + 1); + self.shallow_temp_mappings.insert(idx + 1, var_num); + self.var_data.records[var_num] + .allocation + .set_register(idx + 1); } } - _ => { - self.reset_arg(0); - } - ); + } } fn reset_arg(&mut self, arity: usize) { diff --git a/src/forms.rs b/src/forms.rs index 6e9608df..21a5cc91 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -3,8 +3,7 @@ use crate::atom_table::*; use crate::functor_macro::*; use crate::instructions::*; use crate::machine::disjuncts::VarData; -use crate::machine::heap::*; -// use crate::machine::loader::PredicateQueue; +use crate::machine::loader::PredicateQueue; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::parser::ast::*; @@ -18,6 +17,7 @@ use fxhash::FxBuildHasher; use indexmap::{IndexMap, IndexSet}; use ordered_float::OrderedFloat; +use std::cell::Cell; use std::collections::VecDeque; use std::convert::TryFrom; use std::fmt; @@ -55,6 +55,15 @@ pub enum Level { Shallow, } +impl Level { + pub(crate) fn child_level(self) -> Level { + match self { + Level::Root => Level::Shallow, + _ => Level::Deep, + } + } +} + #[derive(Debug, Clone, Copy)] pub enum CallPolicy { Default, @@ -77,15 +86,6 @@ impl GenContext { } } - #[inline] - pub fn chunk_type(&self) -> ChunkType { - match self { - GenContext::Head => ChunkType::Head, - GenContext::Mid(_) => ChunkType::Mid, - GenContext::Last(_) => ChunkType::Last, - } - } - #[inline] pub fn is_last(self) -> bool { matches!(self, GenContext::Last(_)) @@ -99,6 +99,19 @@ pub enum ChunkType { Last, } +#[derive(Debug)] +pub enum RootIterationPolicy { + Iterated, + NotIterated, +} + +impl RootIterationPolicy { + #[inline(always)] + pub fn iterable(&self) -> bool { + matches!(self, RootIterationPolicy::Iterated) + } +} + impl ChunkType { #[inline(always)] pub fn to_gen_context(self, chunk_num: usize) -> GenContext { @@ -118,17 +131,12 @@ impl ChunkType { #[derive(Debug)] pub enum ChunkedTerms { Branch(Vec>), - Chunk { - chunk_num: usize, - terms: VecDeque, - }, + Chunk { terms: VecDeque }, } #[derive(Debug)] pub struct ChunkedTermVec { pub chunk_vec: VecDeque, - pub current_chunk_num: usize, - pub current_chunk_type: ChunkType, } impl Deref for ChunkedTermVec { @@ -153,8 +161,6 @@ impl ChunkedTermVec { pub fn new() -> Self { Self { chunk_vec: VecDeque::new(), - current_chunk_num: 0, - current_chunk_type: ChunkType::Mid, } } @@ -163,45 +169,18 @@ impl ChunkedTermVec { .push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity))); } - pub fn try_set_chunk_at_inlined_boundary(&mut self) -> bool { - if self.current_chunk_type.is_last() { - self.current_chunk_type = ChunkType::Mid; - self.current_chunk_num += 1; - true - } else { - false - } - } - - pub fn try_set_chunk_at_call_boundary(&mut self) -> bool { - if self.current_chunk_type.is_last() { - self.current_chunk_num += 1; - true - } else { - self.current_chunk_type = ChunkType::Last; - false - } - } - #[inline] pub fn add_chunk(&mut self) { let chunk = ChunkedTerms::Chunk { - chunk_num: self.current_chunk_num, terms: VecDeque::from(vec![]), }; self.chunk_vec.push_back(chunk); } - pub fn current_gen_context(&self) -> GenContext { - self.current_chunk_type - .to_gen_context(self.current_chunk_num) - } - pub fn push_chunk_term(&mut self, term: QueryTerm) { match self.chunk_vec.back_mut() { Some(ChunkedTerms::Branch(_)) => { let chunk = ChunkedTerms::Chunk { - chunk_num: self.current_chunk_num, terms: VecDeque::from(vec![term]), }; @@ -212,7 +191,6 @@ impl ChunkedTermVec { } None => { let chunk = ChunkedTerms::Chunk { - chunk_num: self.current_chunk_num, terms: VecDeque::from(vec![term]), }; @@ -222,39 +200,35 @@ impl ChunkedTermVec { } } -#[derive(Debug)] -pub struct QueryClause { - pub ct: ClauseType, - pub term: HeapCellValue, - pub code_indices: IndexMap, - pub call_policy: CallPolicy, -} - -impl QueryClause { - pub fn term_loc(&self) -> usize { - self.term.get_value() as usize - } -} - #[derive(Debug)] pub enum QueryTerm { - Clause(QueryClause), + // register, clause type, subterms, clause call policy. + Clause(Cell, ClauseType, Vec, CallPolicy), Fail, - Succeed, - LocalCut { var_num: usize, cut_prev: bool }, - GlobalCut(usize), // var_num + LocalCut { var_num: usize, cut_prev: bool }, // var_num + GlobalCut(usize), // var_num GetCutPoint { var_num: usize, prev_b: bool }, GetLevel(usize), // var_num } -#[derive(Clone, Copy, Debug)] +impl QueryTerm { + pub(crate) fn arity(&self) -> usize { + match self { + QueryTerm::Clause(_, _, subterms, ..) => subterms.len(), + &QueryTerm::GetLevel(_) | &QueryTerm::GetCutPoint { .. } => 1, + _ => 0, + } + } +} + +#[derive(Debug)] pub struct Fact { - pub(crate) term_loc: usize, + pub(crate) head: Term, } #[derive(Debug)] pub struct Rule { - pub(crate) term_loc: usize, + pub(crate) head: (Atom, Vec), pub(crate) clauses: ChunkedTermVec, } @@ -271,32 +245,90 @@ impl ListingSource { } } -pub fn clause_predicate_key_from_heap( - heap: &impl SizedHeap, - value: HeapCellValue, -) -> Option { - read_heap_cell!(value, - (HeapCellValueTag::Atom, (name, _arity)) => { - debug_assert_eq!(_arity, 0); - Some((name, 0)) - } - _ => { - if value.is_ref() { - clause_predicate_key(heap, value.get_value() as usize) - } else { - None +pub trait ClauseInfo { + fn is_consistent(&self, clauses: &PredicateQueue) -> bool { + match clauses.first() { + Some(cl) => { + self.name() == ClauseInfo::name(cl) && self.arity() == ClauseInfo::arity(cl) } + None => true, } - ) + } + + fn name(&self) -> Option; + fn arity(&self) -> usize; } -pub fn clause_predicate_key(heap: &impl SizedHeap, term_loc: usize) -> Option { - let key_opt = term_predicate_key(heap, term_loc); +impl ClauseInfo for PredicateKey { + #[inline] + fn name(&self) -> Option { + Some(self.0) + } - if Some((atom!(":-"), 2)) == key_opt { - term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| term_predicate_key(heap, arg_loc)) - } else { - key_opt + #[inline] + fn arity(&self) -> usize { + self.1 + } +} + +impl ClauseInfo for Term { + fn name(&self) -> Option { + match self { + Term::Clause(_, name, terms) => { + match name { + atom!(":-") => { + match terms.len() { + 1 => None, // a declaration. + 2 => terms[0].name(), + _ => Some(*name), + } + } + _ => Some(*name), //str_buf), + } + } + Term::Literal(_, Literal::Atom(name)) => Some(*name), + _ => None, + } + } + + fn arity(&self) -> usize { + match self { + Term::Clause(_, name, terms) => match &*name.as_str() { + ":-" => match terms.len() { + 1 => 0, + 2 => terms[0].arity(), + _ => terms.len(), + }, + _ => terms.len(), + }, + _ => 0, + } + } +} + +impl ClauseInfo for Rule { + fn name(&self) -> Option { + Some(self.head.0) + } + + fn arity(&self) -> usize { + self.head.1.len() + } +} + +impl ClauseInfo for PredicateClause { + fn name(&self) -> Option { + match self { + PredicateClause::Fact(ref term, ..) => term.head.name(), + PredicateClause::Rule(ref rule, ..) => rule.name(), + } + } + + fn arity(&self) -> usize { + match self { + PredicateClause::Fact(ref term, ..) => term.head.arity(), + PredicateClause::Rule(ref rule, ..) => rule.arity(), + } } } @@ -307,26 +339,20 @@ pub enum PredicateClause { } impl PredicateClause { - pub(crate) fn args<'a>(&self, heap: &'a Heap) -> Option> { - let focus = match self { - &PredicateClause::Fact(Fact { term_loc }, _) => term_loc, - &PredicateClause::Rule(Rule { term_loc, .. }, _) => { - term_nth_arg(heap, term_loc, 1).unwrap() + 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) + } } - }; - - let arity = clause_predicate_key(heap, focus) - .map(|(_name, arity)| arity) - .unwrap_or(0); - - read_heap_cell!(heap_bound_store(heap, heap_bound_deref(heap, heap[focus])), - (HeapCellValueTag::Str, s) => { - Some(s+1 ..= s+arity) - } - _ => { - None - } - ) + } } } @@ -699,7 +725,7 @@ impl ArenaFrom for Literal { impl ArenaFrom for HeapCellValue { #[inline] fn arena_from(value: u64, arena: &mut Arena) -> HeapCellValue { - fixnum!(value as i64, arena) + HeapCellValue::from(fixnum!(Literal, value as i64, arena)) } } @@ -779,10 +805,10 @@ impl Number { } } -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] pub(crate) enum OptArgIndexKey { - Literal(usize, usize, HeapCellValue, Vec), // index, IndexingCode location, opt arg, alternatives - List(usize, usize), // index, IndexingCode location + Literal(usize, usize, Literal, Option), // index, IndexingCode location, opt arg, alternatives + List(usize, usize), // index, IndexingCode location None, Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity } diff --git a/src/functor_macro.rs b/src/functor_macro.rs index 4f9032a7..ee69679f 100644 --- a/src/functor_macro.rs +++ b/src/functor_macro.rs @@ -84,6 +84,15 @@ macro_rules! build_functor { 1 + $res_len, [$($subfunctor),*]) }); + ([literal($e:expr) $(, $dt:ident($($value:tt),*))*], + [$($res:expr),*], + $res_len:expr, + [$($subfunctor:expr),*]) => ({ + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::AbsoluteCell(HeapCellValue::from($e))], + 1 + $res_len, + [$($subfunctor),*]) + }); ([number($n:expr, $arena:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, diff --git a/src/heap_iter.rs b/src/heap_iter.rs index 2b0e44c1..97489a6b 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, - pub heap: &'a mut Heap, + heap: &'a mut Heap, } impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> { @@ -253,7 +253,7 @@ impl<'a, ElideLists> Drop for StackfulPreOrderHeapIter<'a, ElideLists> { } } -pub trait FocusedHeapIter: Deref + Iterator { +pub trait FocusedHeapIter: Iterator { fn focus(&self) -> IterStackLoc; } @@ -266,14 +266,6 @@ impl<'a, ElideLists: ListElisionPolicy> FocusedHeapIter } } -impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> { - type Target = Heap; - - fn deref(&self) -> &Self::Target { - &self.heap - } -} - impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> { #[inline] pub fn read_cell_mut(&mut self, loc: IterStackLoc) -> &mut HeapCellValue { @@ -352,7 +344,6 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> #[inline] fn new(heap: &'a mut Heap, stack: &'a mut Stack, root_loc: usize) -> Self { let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap); - // heap.push(cell); Self { heap, @@ -539,7 +530,7 @@ pub(crate) struct PostOrderIterator { } impl Deref for PostOrderIterator { - type Target = Heap; + type Target = Iter; fn deref(&self) -> &Self::Target { &self.base_iter @@ -611,34 +602,10 @@ 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 - * self.stack.last(). this function is used to determine, e.g., - * ownership of inlined code indices. - */ - #[inline] - pub(crate) fn direct_subterm_of_str(&self, idx_loc: usize) -> bool { - if let Some((_child_count, item, focus)) = self.parent_stack.last() { - read_heap_cell!(item, - (HeapCellValueTag::Atom, (_name, arity)) => { - let focus = focus.value() as usize; - return focus + arity >= idx_loc && focus < idx_loc; - } - _ => {} - ); - } - - false - } -} -*/ - pub(crate) type LeftistPostOrderHeapIter<'a, ElideLists> = PostOrderIterator>; -impl<'a, ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'a, ElideLists> { +impl LeftistPostOrderHeapIter<'_, ElideLists> { #[inline] pub fn pop_stack(&mut self) { if let Some((child_count, ..)) = self.parent_stack.last() { @@ -870,7 +837,7 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - wam.machine_st.allocate_pstr("abc ").unwrap(); + wam.machine_st.heap.allocate_pstr("abc ").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); @@ -891,7 +858,7 @@ mod tests { wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.allocate_pstr("def").unwrap(); + wam.machine_st.heap.allocate_pstr("def").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); @@ -1795,12 +1762,12 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 1, + 0, ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(0) + heap_loc_as_cell!(1) ); assert_eq!(iter.next(), None); @@ -1857,7 +1824,7 @@ mod tests { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 0, + 4, ); // the cycle will be iterated twice before being detected. @@ -1879,15 +1846,7 @@ mod tests { ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - list_loc_as_cell!(1) - ); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - atom_as_cell!(a_atom) - ); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - list_loc_as_cell!(3) + heap_loc_as_cell!(0) ); assert_eq!(iter.next(), None); @@ -1928,7 +1887,7 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - wam.machine_st.allocate_pstr("abc ").unwrap(); + wam.machine_st.heap.allocate_pstr("abc ").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); @@ -1952,7 +1911,7 @@ mod tests { } wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.allocate_pstr("def").unwrap(); + wam.machine_st.heap.allocate_pstr("def").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); @@ -2208,14 +2167,17 @@ mod tests { section.push_cell(pstr_loc_as_cell!(0)); }); + assert_eq!(wam.machine_st.heap.cell_len(), 4); + { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 2, + 3, ); assert_eq!(iter.heap.slice_to_str(0, "a string".len()), "a string"); + assert_eq!(iter.next().unwrap(), pstr_loc_as_cell!(0)); assert_eq!(iter.next().unwrap(), empty_list_as_cell!()); assert_eq!(iter.next(), None); } @@ -2528,7 +2490,7 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - wam.machine_st.allocate_pstr("abc ").unwrap(); + wam.machine_st.heap.allocate_pstr("abc ").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); @@ -2552,7 +2514,7 @@ mod tests { } wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.allocate_pstr("def").unwrap(); + wam.machine_st.heap.allocate_pstr("def").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); @@ -2993,7 +2955,7 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - wam.machine_st.allocate_pstr("abc ").unwrap(); + wam.machine_st.heap.allocate_pstr("abc ").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); @@ -3016,7 +2978,7 @@ mod tests { wam.machine_st.heap[2] = heap_loc_as_cell!(2); assert_eq!(wam.machine_st.heap.cell_len(), 3); - wam.machine_st.allocate_pstr("def").unwrap(); + wam.machine_st.heap.allocate_pstr("def").unwrap(); assert_eq!(wam.machine_st.heap.cell_len(), 4); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); diff --git a/src/heap_print.rs b/src/heap_print.rs index cdd166c8..8c39b41e 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -477,7 +477,7 @@ pub struct HCPrinter<'a, Outputter> { toplevel_spec: Option, last_item_idx: usize, parent_of_first_op: Option<(DirectedOp, usize)>, - pub var_names: IndexMap, + pub var_names: IndexMap, pub numbervars_offset: Integer, pub numbervars: bool, pub quoted: bool, @@ -544,11 +544,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { stack: &'a mut Stack, op_dir: &'a OpDir, output: Outputter, - root_loc: usize, + term_loc: usize, ) -> Self { HCPrinter { outputter: output, - iter: stackful_preorder_iter(heap, stack, root_loc), + iter: stackful_preorder_iter(heap, stack, term_loc), op_dir, state_stack: vec![], toplevel_spec: None, @@ -795,7 +795,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if let Some(var) = self.var_names.get(&cell) { read_heap_cell!(cell, (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - return Some(var.to_string()); + return Some(var.borrow().to_string()); } _ => { self.iter.push_stack(h); @@ -837,7 +837,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { // short-circuits handle_heap_term. // self.iter.pop_stack(); - let var_str = var.to_string(); + let var_str = var.borrow().to_string(); push_space_if_amb!(self, &var_str, { append_str!(self, &var_str); @@ -865,7 +865,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { Some(var) => { // If the term is bound to a named variable, // print the variable's name to output. - let var_str = var.to_string(); + let var_str = var.borrow().to_string(); push_space_if_amb!(self, &var_str, { append_str!(self, &var_str); @@ -1956,7 +1956,7 @@ mod tests { printer .var_names - .insert(list_loc_as_cell!(1), Rc::new("L".to_string())); + .insert(list_loc_as_cell!(1), VarPtr::from("L")); let output = printer.print(); @@ -2033,7 +2033,7 @@ mod tests { printer .var_names - .insert(list_loc_as_cell!(1), Rc::new("L".to_string())); + .insert(list_loc_as_cell!(1), VarPtr::from("L")); let output = printer.print(); @@ -2078,7 +2078,7 @@ mod tests { wam.machine_st.heap.clear(); - wam.machine_st.allocate_pstr("abc").unwrap(); + wam.machine_st.heap.allocate_pstr("abc").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); diff --git a/src/indexing.rs b/src/indexing.rs index 344155d8..b9bdfc28 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1,9 +1,9 @@ use crate::atom_table::*; +use crate::parser::ast::*; + use crate::forms::*; use crate::instructions::*; -use crate::machine::heap::*; -use crate::parser::ast::Fixnum; -use crate::types::*; +use crate::types::HeapCellValue; use fxhash::FxBuildHasher; use indexmap::IndexMap; @@ -113,7 +113,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { match constant_key { Some(OptArgIndexKey::Literal(_, _, constant, _)) => { - constants.insert(*constant, constant_ptr); + constants.insert(HeapCellValue::from(*constant), constant_ptr); } _ if constant_ptr.is_external() => { // this must be a defunct clause, because it's been deleted @@ -634,12 +634,15 @@ pub(crate) fn merge_clause_index( match &opt_arg_index_key { OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => { let offset = new_clause_loc - index_loc + 1; - merging_ptr.index_constant(*constant, offset); + merging_ptr.index_constant(HeapCellValue::from(*constant), offset); - for overlapping_constant in overlapping_constants { + if let Some(overlapping_constant) = overlapping_constants { merging_ptr.offset = 0; - - merging_ptr.index_overlapping_constant(*constant, *overlapping_constant, offset); + merging_ptr.index_overlapping_constant( + HeapCellValue::from(*constant), + HeapCellValue::from(*overlapping_constant), + offset, + ); } } OptArgIndexKey::Structure(_, index_loc, name, arity) => { @@ -664,8 +667,8 @@ pub(crate) fn merge_clause_index( } pub(crate) fn remove_constant_indices( - constant: HeapCellValue, - overlapping_constants: &[HeapCellValue], + constant: Literal, + overlapping_constants: Option, indexing_code: &mut [IndexingLine], offset: usize, ) { @@ -694,7 +697,7 @@ pub(crate) fn remove_constant_indices( let mut constants_index = 0; - for constant in iter { + for constant in iter.map(|l| HeapCellValue::from(*l)) { loop { match &mut indexing_code[index] { IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( @@ -702,8 +705,6 @@ pub(crate) fn remove_constant_indices( )) => { constants_index = index; - let constant = *constant; - match constants.get(&constant).cloned() { Some(IndexingCodePtr::DynamicExternal(_)) | Some(IndexingCodePtr::External(_)) @@ -741,7 +742,7 @@ pub(crate) fn remove_constant_indices( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( ref mut constants, )) => { - constants.insert(*constant, ext); + constants.insert(constant, ext); } _ => { unreachable!() @@ -774,7 +775,7 @@ pub(crate) fn remove_constant_indices( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( ref mut constants, )) => { - constants.insert(*constant, ext); + constants.insert(constant, ext); } _ => { unreachable!() @@ -1034,7 +1035,7 @@ pub(crate) fn remove_index( ) { match opt_arg_index_key { OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => { - remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc); + remove_constant_indices(*constant, *overlapping_constants, indexing_code, clause_loc); } OptArgIndexKey::Structure(_, _, name, arity) => { remove_structure_index(*name, *arity, indexing_code, clause_loc); @@ -1096,60 +1097,18 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) { } } -pub(crate) fn constant_key_alternatives( - constant: HeapCellValue, - // atom_tbl: &AtomTable, - // arena: &mut Arena, -) -> Vec { - let mut constants = vec![]; +pub(crate) fn constant_key_alternatives(constant: Literal) -> Option { + let n = match &constant { + Literal::Rational(n) if n.denominator().is_one() => n.numerator(), + Literal::Integer(n) => n, + _ => return None, + }; - match Number::try_from(constant) { - Ok(Number::Integer(n)) => { - let result = (&*n).try_into(); - if let Ok(value) = result { - constants.push( - Fixnum::build_with_checked(value) - .map(|n| fixnum_as_cell!(n)) - .unwrap(), - ); - } - } - _ => {} + if let Ok(n) = n.try_into() { + Fixnum::build_with_checked(n).map(Literal::Fixnum).ok() + } else { + None } - - /* - match constant { - Literal::Atom(ref name) => { - if let Some(c) = name.as_char() { - constants.push(Literal::Char(c)); - } - } - Literal::Char(c) => { - let atom = AtomTable::build_with(atom_tbl, &c.to_string()); - constants.push(Literal::Atom(atom)); - } - /* - // constant_to_literal takes care of the downward conversion from Integer to Fixnum - // if possible. - Literal::Fixnum(ref n) => { - constants.push(Literal::Integer(arena_alloc!(n, arena))); - } - */ - Literal::Integer(ref n) => { - let result = (&**n).try_into(); - if let Ok(value) = result { - Fixnum::build_with_checked(value) - .map(|n| { - constants.push(Literal::Fixnum(n)); - }) - .unwrap(); - } - } - _ => {} - } - */ - - constants } #[derive(Debug)] @@ -1464,9 +1423,13 @@ impl CodeOffsets { self.indices.lists().push_back(index); } - fn index_constant(&mut self, constant: HeapCellValue, index: usize) -> Vec { - let overlapping_constants = constant_key_alternatives(constant); - let code = self.indices.constants().entry(constant).or_default(); + fn index_constant(&mut self, constant: Literal, index: usize) -> Option { + let overlapping_constant_opt = constant_key_alternatives(constant); + let code = self + .indices + .constants() + .entry(HeapCellValue::from(constant)) + .or_default(); let is_initial_index = code.is_empty(); code.push_back(I::compute_index( @@ -1475,8 +1438,8 @@ impl CodeOffsets { self.non_counted_bt, )); - for constant in &overlapping_constants { - let code = self.indices.constants().entry(*constant).or_default(); + if let Some(constant) = overlapping_constant_opt.map(HeapCellValue::from) { + let code = self.indices.constants().entry(constant).or_default(); let is_initial_index = code.is_empty(); let index = I::compute_index(is_initial_index, index, self.non_counted_bt); @@ -1484,7 +1447,7 @@ impl CodeOffsets { code.push_back(index); } - overlapping_constants + overlapping_constant_opt } fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize { @@ -1503,55 +1466,33 @@ impl CodeOffsets { pub(crate) fn index_term( &mut self, - heap: &Heap, - optimal_arg: HeapCellValue, + optimal_arg: &Term, index: usize, clause_index_info: &mut ClauseIndexInfo, ) { - read_heap_cell!(optimal_arg, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); - - if (name, arity) == (atom!("."), 2) { - clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); - self.index_list(index); - } else { - clause_index_info.opt_arg_index_key = - OptArgIndexKey::Structure(self.optimal_index, 0, name, arity); - - self.index_structure(name, arity, index); - } - } - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); - - let overlapping_constants = self.index_constant(atom_as_cell!(name), index); - - clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( - self.optimal_index, - 0, - atom_as_cell!(name), - overlapping_constants, - ); - } - (HeapCellValueTag::Lis - // | HeapCellValueTag::CStr - | HeapCellValueTag::PStrLoc) => { + 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); } - _ if optimal_arg.is_constant() => { - let overlapping_constants = self.index_constant(optimal_arg, index); + &Term::Cons(..) | &Term::PartialString(..) | &Term::CompleteString(..) => { + 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()); - clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( - self.optimal_index, - 0, - optimal_arg, - overlapping_constants, - ); + self.index_structure(name, terms.len(), index); + } + &Term::Literal(_, constant) => { + let overlapping_constants = self.index_constant(constant, index); + + clause_index_info.opt_arg_index_key = + OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants); } _ => {} - ); + } } pub(crate) fn no_indices(&mut self) -> bool { diff --git a/src/iterators.rs b/src/iterators.rs index 1de7541b..5bd51d99 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -1,222 +1,319 @@ -use crate::atom_table::AtomCell; +use crate::atom_table::*; use crate::forms::*; -use crate::heap_iter::*; -use crate::machine::heap::*; -use crate::machine::stack::*; -use crate::types::*; - -use bit_set::*; -use fxhash::FxBuildHasher; -use indexmap::IndexMap; +use crate::instructions::*; +use crate::parser::ast::*; +use std::cell::Cell; use std::collections::VecDeque; use std::iter::*; -use std::ops::Deref; +use std::rc::Rc; use std::vec::Vec; -pub(crate) trait TermIterator: - Deref + Iterator -{ - fn focus(&self) -> IterStackLoc; - fn level(&mut self) -> Level; +#[allow(clippy::borrowed_box)] +#[derive(Debug, Clone)] +pub(crate) enum TermRef<'a> { + AnonVar(Level), + Cons(Level, &'a Cell, &'a Term, &'a Term), + Literal(Level, &'a Cell, &'a Literal), + Clause(Level, &'a Cell, Atom, &'a Vec), + PartialString(Level, &'a Cell, Rc, &'a Box), + CompleteString(Level, &'a Cell, Rc), + Var(Level, &'a Cell, VarPtr), +} + +#[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, Rc, &'a Box), + FinalPartialString(Level, &'a Cell, Rc, &'a Box), + CompleteString(Level, &'a Cell, Rc), + Var(Level, &'a Cell, VarPtr), +} + +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()) + } + Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant), + Term::PartialString(cell, string_buf, tail) => { + TermIterState::InitialPartialString(lvl, cell, string_buf.clone(), tail) + } + Term::CompleteString(cell, string) => { + TermIterState::CompleteString(lvl, cell, string.clone()) + } + Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()), + } + } } #[derive(Debug)] -pub(crate) struct TargetIterator { - shallow_terms: IndexMap, FxBuildHasher>, - root_terms: BitSet, - iter: I, - arg_c: usize, +pub(crate) struct QueryIterator<'a> { + state_stack: Vec>, } -fn record_path( - heap: &impl SizedHeap, - root_terms: &mut BitSet, - mut root_loc: usize, -) -> usize { - loop { - let cell = heap[root_loc]; - root_terms.insert(root_loc); +impl<'a> QueryIterator<'a> { + fn push_subterm(&mut self, lvl: Level, term: &'a Term) { + self.state_stack + .push(TermIterState::subterm_to_state(lvl, term)); + } - read_heap_cell!(cell, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h == root_loc { - break; - } else { - root_loc = h; + /* + 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(); + + QueryIterator { state_stack } + } + */ + + fn from_term(term: &'a Term) -> Self { + let state = match term { + Term::AnonVar + | Term::Cons(..) + | Term::Literal(..) + | Term::PartialString(..) + | Term::CompleteString(..) => { + return QueryIterator { + state_stack: vec![], } } - (HeapCellValueTag::Lis) => { - root_terms.insert(root_loc); - break; + 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], + } + } + + 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)); } - _ => { - if cell.is_ref() { - root_terms.insert(cell.get_value() as usize); - } - - break; + QueryTerm::Clause(ref cell, ref ct, ref terms, _) => { + self.state_stack + .push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms)); } - ); - } - - root_loc -} - -fn find_root_terms(heap: &impl SizedHeap, 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) -} - -fn find_shallow_terms( - heap: &impl SizedHeap, - root_loc: usize, -) -> IndexMap, FxBuildHasher> { - let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default()); - - let (h, arity) = read_heap_cell!(heap[root_loc], - (HeapCellValueTag::Str, s) => { - (s+1, cell_as_atom_cell!(heap[s]).get_arity()) - } - (HeapCellValueTag::Lis, l) => { - (l, 2) - } - (HeapCellValueTag::Atom, (_name, arity)) => { - (root_loc + 1, arity) - } - _ => { - (root_loc, 0) - } - ); - - for idx in 0..arity { - let mut shallow_terms = BitSet::default(); - record_path(heap, &mut shallow_terms, h + idx); - shallow_terms_map.insert(idx + 1, shallow_terms); - } - - 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.deref(), root_loc); - let shallow_terms = find_shallow_terms(iter.deref(), derefed_root_loc); - - Self { - shallow_terms, - root_terms, - iter, - arg_c, + _ => {} } } - 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; - } - } - - Level::Deep + pub fn new(term: &'a QueryTerm) -> Self { + let mut iter = QueryIterator { + state_stack: vec![], + }; + iter.extend_state(Level::Root, term); + iter } } -impl<'a, const SKIP_ROOT: bool> TermIterator for FactIterator<'a, SKIP_ROOT> { - fn focus(&self) -> IterStackLoc { - self.iter.focus() - } - - fn level(&mut self) -> Level { - let lvl = self.current_level(1); - - if let Level::Shallow = lvl { - self.arg_c += 1; - } - - lvl - } -} - -impl<'a, const SKIP_ROOT: bool> TermIterator for QueryIterator<'a, SKIP_ROOT> { - fn focus(&self) -> IterStackLoc { - self.iter.focus() - } - - fn level(&mut self) -> Level { - let lvl = self.current_level(0); - - if let Level::Shallow = lvl { - self.arg_c += 1; - } - - lvl - } -} - -impl Iterator for TargetIterator { - type Item = HeapCellValue; +impl<'a> Iterator for QueryIterator<'a> { + type Item = TermRef<'a>; fn next(&mut self) -> Option { - loop { - let next_term = self.iter.next(); + 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, + )); - if next_term.is_none() { - return None; + 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)); + + self.push_subterm(lvl.child_level(), tail); + self.push_subterm(lvl.child_level(), head); + } + TermIterState::InitialPartialString(lvl, cell, string, tail) => { + self.state_stack + .push(TermIterState::FinalPartialString(lvl, cell, string, tail)); + self.push_subterm(lvl.child_level(), tail); + } + TermIterState::FinalPartialString(lvl, cell, string, tail) => { + return Some(TermRef::PartialString(lvl, cell, string, tail)); + } + TermIterState::CompleteString(lvl, cell, string) => { + return Some(TermRef::CompleteString(lvl, cell, string)); + } + TermIterState::FinalCons(lvl, cell, head, tail) => { + return Some(TermRef::Cons(lvl, cell, head, tail)); + } + TermIterState::Literal(lvl, cell, constant) => { + return Some(TermRef::Literal(lvl, cell, constant)); + } + TermIterState::Var(lvl, cell, var_ptr) => { + return Some(TermRef::Var(lvl, cell, var_ptr)); + } + }; + } + + None + } +} + +#[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)); + } + + 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(); + + FactIterator { + state_queue, + iterable_root: RootIterationPolicy::NotIterated, + } + } + + fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self { + let states = match term { + Term::AnonVar => { + vec![TermIterState::AnonVar(Level::Root)] } - - let focus = self.iter.focus().value() as usize; - - if SKIP_ROOT && self.root_terms.contains(focus) { - continue; - } else { - return next_term; + Term::Clause(cell, name, terms) => { + vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)] } + Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons( + Level::Root, + cell, + head.as_ref(), + tail.as_ref(), + )], + Term::PartialString(cell, string, tail) => { + vec![TermIterState::InitialPartialString( + Level::Root, + cell, + string.clone(), + tail, + )] + } + Term::CompleteString(cell, string) => { + vec![TermIterState::CompleteString( + Level::Root, + cell, + string.clone(), + )] + } + Term::Literal(cell, constant) => { + vec![TermIterState::Literal(Level::Root, cell, constant)] + } + Term::Var(cell, var_ptr) => { + vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())] + } + }; + + FactIterator { + state_queue: VecDeque::from(states), + iterable_root, } } } -impl Deref for TargetIterator { - type Target = Heap; +impl<'a> Iterator for FactIterator<'a> { + type Item = TermRef<'a>; - fn deref(&self) -> &Self::Target { - self.iter.deref() + 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); + } + + 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); + + 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)); + } + _ => {} + } + } + + None } } -impl FocusedHeapIter for TargetIterator { - fn focus(&self) -> IterStackLoc { - self.iter.focus() - } +pub(crate) fn post_order_iter(term: &'_ Term) -> QueryIterator { + QueryIterator::from_term(term) } -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> { - 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> { - TargetIterator::new(stackful_post_order_iter(heap, stack, root_loc), root_loc, 1) +pub(crate) fn breadth_first_iter( + term: &'_ Term, + iterable_root: RootIterationPolicy, +) -> FactIterator { + FactIterator::new(term, iterable_root) } #[derive(Debug, Copy, Clone)] @@ -230,10 +327,7 @@ pub(crate) enum ClauseItem<'a> { FirstBranch(usize), NextBranch, BranchEnd(usize), - Chunk { - chunk_num: usize, - terms: &'a VecDeque, - }, + Chunk { terms: &'a VecDeque }, } #[derive(Debug)] @@ -309,11 +403,8 @@ impl<'a> Iterator for ClauseIterator<'a> { self.state_stack .push(ClauseIteratorState::RemainingBranches(branches, 0)); } - &ChunkedTerms::Chunk { - chunk_num, - ref terms, - } => { - return Some(ClauseItem::Chunk { chunk_num, terms }); + &ChunkedTerms::Chunk { ref terms } => { + return Some(ClauseItem::Chunk { terms }); } } } diff --git a/src/lib/atts.pl b/src/lib/atts.pl index 6d18b447..f251b57d 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 bc78b711..ca07e0c6 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1175,8 +1175,14 @@ clause(H, B) :- % Asserts (inserts) a new clause (rule or fact) into the current module. % The clause will be inserted at the beginning of the module. asserta(Clause0) :- - loader:strip_subst_module(Clause0, user, Module, Clause), - '$asserta'(Module, Clause). + loader:strip_module(Clause0, Module, Clause), + asserta_(Module, Clause). + +asserta_(Module, (Head :- Body)) :- + !, + '$asserta'(Module, Head, Body). +asserta_(Module, Fact) :- + '$asserta'(Module, Fact, true). :- meta_predicate assertz(:). @@ -1185,8 +1191,14 @@ asserta(Clause0) :- % Asserts (inserts) a new clause (rule or fact) into the current module. % The clase will be inserted at the end of the module. assertz(Clause0) :- - loader:strip_subst_module(Clause0, user, Module, Clause), - '$assertz'(Module, Clause). + loader:strip_module(Clause0, Module, Clause), + assertz_(Module, Clause). + +assertz_(Module, (Head :- Body)) :- + !, + '$assertz'(Module, Head, Body). +assertz_(Module, Fact) :- + '$assertz'(Module, Fact, true). :- meta_predicate retract(:). diff --git a/src/lib/si.pl b/src/lib/si.pl index 90cc4d3f..0e29c190 100644 --- a/src/lib/si.pl +++ b/src/lib/si.pl @@ -126,3 +126,4 @@ 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 f2d77009..2a5e9fb8 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -177,6 +177,7 @@ print_comma_separated_list([VN=_, VNEq | VNEqs]) :- filter_anonymous_vars([], []). filter_anonymous_vars([VN=V | VNEqs0], VNEqs) :- + '$debug_hook', ( atom_concat('_', _, VN) -> filter_anonymous_vars(VNEqs0, VNEqs) ; VNEqs = [VN=V | VNEqs1], diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 86470097..f7bd69ef 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1126,7 +1126,10 @@ impl MachineState { match Number::try_from(value) { Ok(n) => Ok(n), - Err(_) => self.arith_eval_by_metacall(value), + Err(_) => { + self.heap[0] = value; + self.arith_eval_by_metacall(0) + } } } &ArithmeticTerm::Interm(i) => Ok(mem::replace( @@ -1152,21 +1155,11 @@ impl MachineState { pub(crate) fn arith_eval_by_metacall( &mut self, - value: HeapCellValue, + term_loc: usize, ) -> Result { - debug_assert!(value.is_ref()); - let stub_gen = || functor_stub(atom!("is"), 2); - - let root_loc = if value.is_ref() && !value.is_stack_var() { - value.get_value() as usize - } else { - let type_error = self.type_error(ValidType::Evaluable, value); - return Err(self.error_form(type_error, stub_gen())); - }; - let mut iter = - stackful_post_order_iter::(&mut self.heap, &mut self.stack, root_loc); + stackful_post_order_iter::(&mut self.heap, &mut self.stack, term_loc); while let Some(value) = iter.next() { if value.get_forwarding_bit() { @@ -1459,7 +1452,7 @@ mod tests { parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap(); assert_eq!( - wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)), + wam.arith_eval_by_metacall(term_write_result.heap_loc), Ok(Number::Fixnum(Fixnum::build_with(8))), ); @@ -1469,7 +1462,7 @@ mod tests { parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap(); assert_eq!( - wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)), + wam.arith_eval_by_metacall(term_write_result.heap_loc), Ok(Number::Fixnum(Fixnum::build_with(19))), ); @@ -1479,7 +1472,7 @@ mod tests { parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap(); assert_eq!( - wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)), + wam.arith_eval_by_metacall(term_write_result.heap_loc), Ok(Number::Fixnum(Fixnum::build_with(-1))) ); } diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 368152f5..34e4755d 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -10,8 +10,8 @@ use std::cmp::Ordering; pub(super) type Bindings = Vec<(usize, HeapCellValue)>; #[derive(Debug)] -pub(crate) struct AttrVarInitializer { - pub(crate) attr_var_queue: Vec, +pub(super) struct AttrVarInitializer { + pub(super) attr_var_queue: Vec, pub(super) bindings: Bindings, pub(super) p: usize, pub(super) cp: usize, @@ -138,17 +138,10 @@ impl MachineState { let mut seen_set = IndexSet::new(); let mut seen_vars = vec![]; - let root_loc = if cell.is_ref() { - cell.get_value() as usize - } else { - return vec![]; - }; - let mut iter = stackful_preorder_iter::( - &mut self.heap, - &mut self.stack, - root_loc, // cell, - ); + self.heap[0] = cell; + + let mut iter = stackful_preorder_iter::(&mut self.heap, &mut self.stack, 0); while let Some(value) = iter.next() { read_heap_cell!(value, diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 84b89c39..4f0fb1b6 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -11,6 +11,7 @@ use crate::machine::term_stream::*; use crate::machine::*; use crate::parser::ast::*; +use std::cell::Cell; use std::collections::VecDeque; use std::mem; use std::ops::Range; @@ -1232,16 +1233,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { fn compile_standalone_clause( &mut self, - term: TermWriteResult, + term: Term, settings: CodeGenSettings, ) -> Result { let mut preprocessor = Preprocessor::new(settings); - let clause = preprocessor.try_term_to_tl(self, term)?; - let machine_st = LS::machine_st(&mut self.payload); - let mut cg = CodeGenerator::new(settings); - let clause_code = cg.compile_predicate(&mut machine_st.heap, vec![clause])?; + let mut cg = CodeGenerator::new(settings); + let clause_code = cg.compile_predicate(vec![clause])?; Ok(StandaloneCompileResult { clause_code, @@ -1262,6 +1261,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let code_len = self.wam_prelude.code.len(); let mut code_ptr = code_len; + if key == (atom!("..."), 2) { + print!(""); + } + let mut clauses = vec![]; let mut preprocessor = Preprocessor::new(settings); @@ -1269,10 +1272,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { clauses.push(preprocessor.try_term_to_tl(self, term)?); } - let machine_st = LS::machine_st(&mut self.payload); - let mut cg = CodeGenerator::new(settings); - let mut code = cg.compile_predicate(&mut machine_st.heap, clauses)?; + let mut code = cg.compile_predicate(clauses)?; if settings.is_extensible { let mut clause_clause_locs = VecDeque::new(); @@ -1469,7 +1470,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { pub(super) fn incremental_compile_clause( &mut self, key: PredicateKey, - clause: TermWriteResult, + clause: Term, compilation_target: CompilationTarget, non_counted_bt: bool, append_or_prepend: AppendOrPrepend, @@ -2004,13 +2005,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } impl<'a, LS: LoadState<'a>> Loader<'a, LS> { - pub(super) fn compile_clause_clauses( + pub(super) fn compile_clause_clauses>( &mut self, key: PredicateKey, compilation_target: CompilationTarget, - clause_clauses: Vec, + clause_clauses: ClauseIter, append_or_prepend: AppendOrPrepend, ) -> Result<(), SessionError> { + let clause_predicates = clause_clauses + .map(|(head, body)| Term::Clause(Cell::default(), atom!("$clause"), vec![head, body])); + let clause_clause_compilation_target = match compilation_target { CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), _ => compilation_target, @@ -2018,7 +2022,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let mut num_clause_predicates = 0; - for clause_term in clause_clauses { + for clause_term in clause_predicates { self.incremental_compile_clause( (atom!("$clause"), 2), clause_term, @@ -2102,13 +2106,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> { - let key = match self.payload.predicates.first().map(|term| term.focus) { - Some(focus) => clause_predicate_key(self.machine_heap(), focus) - .ok_or(SessionError::NamelessEntry)?, - None => { - return Err(SessionError::NamelessEntry); - } - }; + let key = self + .payload + .predicates + .first() + .and_then(|cl| { + let arity = ClauseInfo::arity(cl); + ClauseInfo::name(cl).map(|name| (name, arity)) + }) + .ok_or(SessionError::NamelessEntry)?; let listing_src_file_name = self.listing_src_file_name(); @@ -2247,12 +2253,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .clause_clauses .drain(0..std::cmp::min(predicates_len, clause_clauses_len)) .collect(); + let compilation_target = self.payload.predicates.compilation_target; self.compile_clause_clauses( key, compilation_target, - clauses_vec, + clauses_vec.into_iter(), AppendOrPrepend::Append, )?; } @@ -2281,50 +2288,15 @@ impl Machine { pub(crate) fn compile_standalone_clause( &mut self, - term_reg: RegType, - vars: Vec, + term_loc: RegType, + vars: &[Term], ) -> Result<(), SessionError> { - let body_cell = self - .machine_st - .store(self.machine_st.deref(self.machine_st[term_reg])); - - let new_header_loc = self.machine_st.heap.cell_len(); - let arity = vars.len(); - let term_loc = self.machine_st.heap.cell_len() + 1 + arity; - - let mut writer = self - .machine_st - .heap - .reserve(4 + arity) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - - writer.write_with(move |section| { - section.push_cell(atom_as_cell!(atom!(""), arity)); - - for var in vars { - section.push_cell(var); - } - - let head_loc = if arity > 0 { - str_loc_as_cell!(new_header_loc) - } else { - heap_loc_as_cell!(new_header_loc) - }; - - section.push_cell(atom_as_cell!(atom!(":-"), 2)); - section.push_cell(head_loc); - section.push_cell(body_cell); - }); - let mut compile = || { let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(self, InlineTermStream {}); - let machine_st = InlineLoadState::machine_st(&mut loader.payload); - - let term_loc = str_loc_as_cell!(term_loc); - let term = TermWriteResult::from(&mut machine_st.heap, term_loc) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + let term = loader.read_term_from_heap(term_loc); + let clause = build_rule_body(vars, term); let settings = CodeGenSettings { global_clock_tick: None, @@ -2332,7 +2304,7 @@ impl Machine { non_counted_bt: true, }; - loader.compile_standalone_clause(term, settings) + loader.compile_standalone_clause(clause, settings) }; let StandaloneCompileResult { clause_code, .. } = compile()?; diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index ad4460d4..2187e7b8 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -1,20 +1,18 @@ use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; -use crate::iterators::fact_iterator; -use crate::machine::heap::*; +use crate::iterators::*; use crate::machine::loader::*; use crate::machine::machine_errors::CompilationError; use crate::machine::preprocessor::*; -use crate::machine::Stack; use crate::parser::ast::*; use crate::parser::dashu::Rational; -use crate::types::*; use crate::variable_records::*; use dashu::Integer; use indexmap::{IndexMap, IndexSet}; +use std::cell::Cell; use std::cmp::Ordering; use std::collections::VecDeque; use std::hash::{Hash, Hasher}; @@ -81,34 +79,9 @@ impl BranchNumber { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum ClassifiedVar { - Anon { term_loc: usize }, - InSitu { var_num: usize }, - Generated { term_loc: usize }, -} - -impl ClassifiedVar { - fn term_loc(&self) -> Option { - if let &ClassifiedVar::Generated { term_loc } = self { - Some(term_loc) - } else { - None - } - } -} - -fn to_classified_var(inverse_var_locs: &InverseVarLocs, term_loc: usize) -> ClassifiedVar { - if inverse_var_locs.contains_key(&term_loc) { - ClassifiedVar::Generated { term_loc } - } else { - ClassifiedVar::Anon { term_loc } - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct VarInfo { - var: ClassifiedVar, + var_ptr: VarPtr, chunk_type: ChunkType, classify_info: ClassifyInfo, lvl: Level, @@ -116,6 +89,7 @@ pub struct VarInfo { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ChunkInfo { + chunk_num: usize, term_loc: GenContext, // pointer to incidence, term occurrence arity. vars: Vec, @@ -136,7 +110,7 @@ impl BranchInfo { } } -type BranchMapInt = IndexMap>; +type BranchMapInt = IndexMap>; #[derive(Debug, Clone)] pub struct BranchMap(BranchMapInt); @@ -173,21 +147,11 @@ enum TraversalState { // where it leaves off. BuildFinalDisjunct(usize), Fail, - Succeed, - GetCutPoint { - var_num: usize, - prev_b: bool, - }, - Cut { - var_num: usize, - is_global: bool, - }, + GetCutPoint { var_num: usize, prev_b: bool }, + Cut { var_num: usize, is_global: bool }, CutPrev(usize), ResetCallPolicy(CallPolicy), - Term { - subterm: HeapCellValue, - term_loc: usize, - }, + Term(Term), OverrideGlobalCutVar(usize), ResetGlobalCutVarOverride(Option), RemoveBranchNum, // pop the current_branch_num and from the root set. @@ -199,6 +163,8 @@ enum TraversalState { pub struct VariableClassifier { call_policy: CallPolicy, current_branch_num: BranchNumber, + current_chunk_num: usize, + current_chunk_type: ChunkType, branch_map: BranchMap, var_num: usize, root_set: RootSet, @@ -206,50 +172,18 @@ pub struct VariableClassifier { global_cut_var_num_override: Option, } -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub struct VarPtrIndex { - pub chunk_num: usize, - pub term_loc: usize, -} - -#[derive(Debug)] -pub enum VarPtr { - Numbered(usize), - Anon, -} - -#[derive(Debug, Default)] -pub struct VarLocsToNums { - map: IndexMap, -} - -impl VarLocsToNums { - pub fn insert(&mut self, key: VarPtrIndex, var_num: usize) { - self.map.insert(key, var_num); - } - - pub fn get(&self, idx: VarPtrIndex) -> VarPtr { - self.map - .get(&idx) - .cloned() - .map(VarPtr::Numbered) - .unwrap_or_else(|| VarPtr::Anon) - } -} - #[derive(Debug, Default)] pub struct VarData { pub records: VariableRecords, pub global_cut_var_num: Option, pub allocates: bool, - pub var_locs_to_nums: VarLocsToNums, } impl VarData { fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) { let global_cut_var_num = if let &Some(global_cut_var_num) = &self.global_cut_var_num { match &self.records[global_cut_var_num].allocation { - VarAlloc::Perm { .. } => Some(global_cut_var_num), + VarAlloc::Perm(..) => Some(global_cut_var_num), VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => { Some(global_cut_var_num) } @@ -261,15 +195,12 @@ impl VarData { if let Some(global_cut_var_num) = global_cut_var_num { let term = QueryTerm::GetLevel(global_cut_var_num); - self.records[global_cut_var_num].allocation = VarAlloc::Perm { - reg: 0, - allocation: PermVarAllocation::Pending, - }; + self.records[global_cut_var_num].allocation = + VarAlloc::Perm(0, PermVarAllocation::Pending); match build_stack.front_mut() { Some(ChunkedTerms::Branch(_)) => { build_stack.push_front(ChunkedTerms::Chunk { - chunk_num: 0, terms: VecDeque::from(vec![term]), }); } @@ -284,8 +215,8 @@ impl VarData { } } -pub type ClassifyFactResult = VarData; -pub type ClassifyRuleResult = (ChunkedTermVec, VarData); +pub type ClassifyFactResult = (Term, VarData); +pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData); fn merge_branch_seq(branches: impl Iterator) -> BranchInfo { let mut branch_info = BranchInfo::new(BranchNumber::default()); @@ -316,6 +247,8 @@ impl VariableClassifier { Self { call_policy, current_branch_num: BranchNumber::default(), + current_chunk_num: 0, + current_chunk_type: ChunkType::Head, branch_map: BranchMap(BranchMapInt::new()), root_set: RootSet::new(), var_num: 0, @@ -324,45 +257,40 @@ impl VariableClassifier { } } - pub fn classify_fact<'a, LS: LoadState<'a>>( - mut self, - loader: &mut Loader<'a, LS>, - term: &TermWriteResult, - ) -> Result { - self.classify_head_variables(loader, &term, term.focus)?; - Ok(self.branch_map.separate_and_classify_variables( - self.var_num, - self.global_cut_var_num, - 0, + pub fn classify_fact(mut self, term: Term) -> Result { + self.classify_head_variables(&term)?; + Ok(( + term, + self.branch_map.separate_and_classify_variables( + self.var_num, + self.global_cut_var_num, + self.current_chunk_num, + ), )) } pub fn classify_rule<'a, LS: LoadState<'a>>( mut self, loader: &mut Loader<'a, LS>, - term: &TermWriteResult, + head: Term, + body: Term, ) -> Result { - let heap = &mut LS::machine_st(&mut loader.payload).heap; - - let head_loc = term_nth_arg(heap, term.focus, 1).unwrap(); - let body_loc = term_nth_arg(heap, term.focus, 2).unwrap(); - - self.classify_head_variables(loader, &term, head_loc)?; + self.classify_head_variables(&head)?; self.root_set.insert(self.current_branch_num.clone()); - let mut query_terms = self.classify_body_variables(loader, term, body_loc)?; + let mut query_terms = self.classify_body_variables(loader, body)?; self.merge_branches(); let mut var_data = self.branch_map.separate_and_classify_variables( self.var_num, self.global_cut_var_num, - query_terms.current_chunk_num, + self.current_chunk_num, ); var_data.emit_initial_get_level(&mut query_terms); - Ok((query_terms, var_data)) + Ok((head, query_terms, var_data)) } fn merge_branches(&mut self) { @@ -386,45 +314,51 @@ impl VariableClassifier { } } - fn probe_body_term( - &mut self, - arg_c: usize, - arity: usize, - term: &mut FocusedHeapRefMut, - inverse_var_locs: &InverseVarLocs, - context: GenContext, - ) { - let classify_info = ClassifyInfo { arg_c, arity }; - - let mut lvl = Level::Shallow; - let mut stack = Stack::uninitialized(); - let mut iter = fact_iterator::(term.heap, &mut stack, term.focus); - - // second arg is true to iterate the root, which may be a variable - while let Some(subterm) = iter.next() { - if !subterm.is_var() { - lvl = Level::Deep; - continue; - } - - let var_loc = subterm.get_value() as usize; - let var = to_classified_var(inverse_var_locs, var_loc); - - self.probe_body_var( - context, - VarInfo { - var, - lvl, - classify_info, - chunk_type: context.chunk_type(), - }, - ); + fn try_set_chunk_at_inlined_boundary(&mut self) -> bool { + if self.current_chunk_type.is_last() { + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; + true + } else { + false } } - fn probe_body_var(&mut self, context: GenContext, var_info: VarInfo) { - let chunk_num = context.chunk_num(); - let branch_info_v = self.branch_map.entry(var_info.var).or_default(); + fn try_set_chunk_at_call_boundary(&mut self) -> bool { + if self.current_chunk_type.is_last() { + self.current_chunk_num += 1; + true + } else { + self.current_chunk_type = ChunkType::Last; + false + } + } + + fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) { + let classify_info = ClassifyInfo { arg_c, arity }; + + // 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, + }); + } + } + } + + fn probe_body_var(&mut self, var_info: VarInfo) { + let term_loc = self + .current_chunk_type + .to_gen_context(self.current_chunk_num); + + let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone()).or_default(); let needs_new_branch = if let Some(last_bi) = branch_info_v.last() { !self.root_set.contains(&last_bi.branch_num) @@ -439,14 +373,15 @@ impl VariableClassifier { let branch_info = branch_info_v.last_mut().unwrap(); let needs_new_chunk = if let Some(last_ci) = branch_info.chunks.last() { - last_ci.term_loc.chunk_num() != chunk_num + last_ci.chunk_num != self.current_chunk_num } else { true }; if needs_new_chunk { branch_info.chunks.push(ChunkInfo { - term_loc: context, + chunk_num: self.current_chunk_num, + term_loc, vars: vec![], }); } @@ -455,81 +390,68 @@ impl VariableClassifier { chunk_info.vars.push(var_info); } - fn probe_in_situ_var(&mut self, context: GenContext, var_num: usize) { + fn probe_in_situ_var(&mut self, var_num: usize) { let classify_info = ClassifyInfo { arg_c: 1, arity: 1 }; let var_info = VarInfo { - var: ClassifiedVar::InSitu { var_num }, + var_ptr: VarPtr::from(Var::InSitu(var_num)), classify_info, - chunk_type: context.chunk_type(), + chunk_type: self.current_chunk_type, lvl: Level::Shallow, }; - self.probe_body_var(context, var_info); + self.probe_body_var(var_info); } - fn classify_head_variables<'a, LS: LoadState<'a>>( - &mut self, - loader: &mut Loader<'a, LS>, - term: &TermWriteResult, - head_loc: usize, - ) -> Result<(), CompilationError> { - let heap = &mut LS::machine_st(&mut loader.payload).heap; - let arity = term_predicate_key(heap, head_loc) - .and_then(|(_, arity)| Some(arity)) - .ok_or(CompilationError::InvalidRuleHead)?; + fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> { + match term { + Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {} + _ => return Err(CompilationError::InvalidRuleHead), + } - let mut classify_info = ClassifyInfo { arg_c: 1, arity }; + let mut classify_info = ClassifyInfo { + arg_c: 1, + arity: term.arity(), + }; - if arity > 0 { - let (_term_loc, value) = subterm_index(heap, head_loc); - let str_offset = value.get_value() as usize; + 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(); - debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str); + // 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(); - for idx in str_offset + 1..=str_offset + arity { - let mut lvl = Level::Shallow; - let mut stack = Stack::uninitialized(); - let mut iter = fact_iterator::(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(); + + 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); } - - let term_loc = subterm.get_value() as usize; - let var = to_classified_var(&term.inverse_var_locs, term_loc); - - // the body of the if let here is an inlined - // "probe_head_var". note the difference between it - // and "probe_body_var". - let branch_info_v = self.branch_map.entry(var).or_default(); - let needs_new_branch = branch_info_v.is_empty(); - - if needs_new_branch { - branch_info_v.push(BranchInfo::new(self.current_branch_num.clone())); - } - - let branch_info = branch_info_v.last_mut().unwrap(); - let needs_new_chunk = branch_info.chunks.is_empty(); - - if needs_new_chunk { - branch_info.chunks.push(ChunkInfo { - term_loc: GenContext::Head, - vars: vec![], - }); - } - - let chunk_info = branch_info.chunks.last_mut().unwrap(); - let var_info = VarInfo { - var, - classify_info, - chunk_type: ChunkType::Head, - lvl, - }; - - chunk_info.vars.push(var_info); } classify_info.arg_c += 1; @@ -539,38 +461,17 @@ impl VariableClassifier { Ok(()) } - fn new_cut_state(&mut self, context: GenContext) -> TraversalState { - let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override { - (var_num, false) - } else if let Some(var_num) = self.global_cut_var_num { - (var_num, true) - } else { - let var_num = self.var_num; - - self.global_cut_var_num = Some(var_num); - self.var_num += 1; - - (var_num, true) - }; - - self.probe_in_situ_var(context, var_num); - - TraversalState::Cut { var_num, is_global } - } - fn classify_body_variables<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - terms: &TermWriteResult, - term_loc: usize, + term: Term, ) -> Result { - let mut state_stack = vec![TraversalState::Term { - subterm: loader.machine_heap()[term_loc], - term_loc, - }]; + let mut state_stack = vec![TraversalState::Term(term)]; let mut build_stack = ChunkedTermVec::new(); - 'outer: while let Some(traversal_st) = state_stack.pop() { + self.current_chunk_type = ChunkType::Mid; + + while let Some(traversal_st) = state_stack.pop() { match traversal_st { TraversalState::AddBranchNum(branch_num) => { self.root_set.insert(branch_num.clone()); @@ -590,22 +491,21 @@ impl VariableClassifier { TraversalState::BuildDisjunct(preceding_len) => { flatten_into_disjunct(&mut build_stack, preceding_len); - build_stack.current_chunk_type = ChunkType::Mid; - build_stack.current_chunk_num += 1; + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; } TraversalState::BuildFinalDisjunct(preceding_len) => { flatten_into_disjunct(&mut build_stack, preceding_len); - build_stack.current_chunk_type = ChunkType::Mid; - build_stack.current_chunk_num += 1; + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; } TraversalState::GetCutPoint { var_num, prev_b } => { - if build_stack.try_set_chunk_at_inlined_boundary() { + if self.try_set_chunk_at_inlined_boundary() { build_stack.add_chunk(); } - let context = build_stack.current_gen_context(); - self.probe_in_situ_var(context, var_num); + self.probe_in_situ_var(var_num); build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b }); } TraversalState::OverrideGlobalCutVar(var_num) => { @@ -615,12 +515,11 @@ impl VariableClassifier { self.global_cut_var_num_override = old_override; } TraversalState::Cut { var_num, is_global } => { - if build_stack.try_set_chunk_at_inlined_boundary() { + if self.try_set_chunk_at_inlined_boundary() { build_stack.add_chunk(); } - let context = build_stack.current_gen_context(); - self.probe_in_situ_var(context, var_num); + self.probe_in_situ_var(var_num); build_stack.push_chunk_term(if is_global { QueryTerm::GlobalCut(var_num) @@ -632,12 +531,11 @@ impl VariableClassifier { }); } TraversalState::CutPrev(var_num) => { - if build_stack.try_set_chunk_at_inlined_boundary() { + if self.try_set_chunk_at_inlined_boundary() { build_stack.add_chunk(); } - let context = build_stack.current_gen_context(); - self.probe_in_situ_var(context, var_num); + self.probe_in_situ_var(var_num); build_stack.push_chunk_term(QueryTerm::LocalCut { var_num, @@ -647,374 +545,297 @@ impl VariableClassifier { TraversalState::Fail => { build_stack.push_chunk_term(QueryTerm::Fail); } - TraversalState::Succeed => { - build_stack.push_chunk_term(QueryTerm::Succeed); - } - TraversalState::Term { - mut subterm, - mut term_loc, - } => { + TraversalState::Term(term) => { // return true iff new chunk should be added. - let update_chunk_data = - |build_stack: &mut ChunkedTermVec, key: PredicateKey| { - if ClauseType::is_inlined(key.0, key.1) { - build_stack.try_set_chunk_at_inlined_boundary() - } else { - build_stack.try_set_chunk_at_call_boundary() - } - }; + let update_chunk_data = |classifier: &mut Self, predicate_name, arity| { + if ClauseType::is_inlined(predicate_name, arity) { + classifier.try_set_chunk_at_inlined_boundary() + } else { + classifier.try_set_chunk_at_call_boundary() + } + }; - macro_rules! add_chunk { - ($key:expr, $tag:expr, $term_loc:expr) => {{ - if update_chunk_data(&mut build_stack, $key) { - build_stack.add_chunk(); - } + let mut add_chunk = |classifier: &mut Self, name: Atom, terms: Vec| { + if update_chunk_data(classifier, name, terms.len()) { + build_stack.add_chunk(); + } - let context = build_stack.current_gen_context(); + for (arg_c, term) in terms.iter().enumerate() { + classifier.probe_body_term(arg_c + 1, terms.len(), term); + } - for (arg_c, term_loc) in - ($term_loc + 1..=$term_loc + $key.1).enumerate() - { - let mut term = - FocusedHeapRefMut::from(loader.machine_heap(), term_loc); + build_stack.push_chunk_term(clause_to_query_term( + loader, + name, + terms, + classifier.call_policy, + )); + }; - self.probe_body_term( - arg_c + 1, - $key.1, - &mut term, - &terms.inverse_var_locs, - context, - ); - } - - build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( - loader, - $key, - &terms, - HeapCellValue::build_with($tag, $term_loc as u64), - self.call_policy, - ))); - }}; - } - - macro_rules! add_qualified_chunk { - ($module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{ - if update_chunk_data(&mut build_stack, $key) { - build_stack.add_chunk(); - } - - let context = build_stack.current_gen_context(); - - for (arg_c, term_loc) in - ($term_loc + 1..=$term_loc + $key.1).enumerate() - { - let mut term = - FocusedHeapRefMut::from(loader.machine_heap(), term_loc); - - self.probe_body_term( - arg_c + 1, - $key.1, - &mut term, - &terms.inverse_var_locs, - context, - ); - } - - build_stack.push_chunk_term(QueryTerm::Clause( - qualified_clause_to_query_term( - loader, - $key, - $module_name, - &terms, - HeapCellValue::build_with($tag, $term_loc as u64), - self.call_policy, - ), - )); - }}; - } - - loop { - let heap = loader.machine_heap(); - - read_heap_cell!(subterm, - (HeapCellValueTag::Str, subterm_loc) => { - let (name, arity) = cell_as_atom_cell!(heap[subterm_loc]) - .get_name_and_arity(); - - match (name, arity) { - (atom!("->") | atom!(";") | atom!(","), 3) => { - if blunt_index_ptr(heap, (name, 2), subterm_loc) { - subterm = heap[subterm_loc]; - continue; - } - - add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc); - } - (atom!(","), 2) => { - let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - let head = heap[head_loc]; - - let iter = unfold_by_str_locs(heap, tail_loc, atom!(",")) - .into_iter() - .rev() - .chain(std::iter::once((head, head_loc))) - .map(|(subterm, term_loc)| { - TraversalState::Term { subterm, term_loc } - }); - state_stack.extend(iter); - } - (atom!(";"), 2) => { - let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - - let head = heap[head_loc]; - - let first_branch_num = self.current_branch_num.split(); - let branches: Vec<_> = std::iter::once((head, head_loc)) - .chain( - unfold_by_str_locs(heap, tail_loc, atom!(";")) - .into_iter(), - ) - .collect(); - - let mut branch_numbers = vec![first_branch_num]; - - for idx in 1..branches.len() { - let succ_branch_number = branch_numbers[idx - 1].incr_by_delta(); - - branch_numbers.push(if idx + 1 < branches.len() { - succ_branch_number.split() - } else { - succ_branch_number - }); - } - - let build_stack_len = build_stack.len(); - build_stack.reserve_branch(branches.len()); - - state_stack.push(TraversalState::RepBranchNum( - self.current_branch_num.halve_delta(), - )); - - let iter = branches.into_iter().zip(branch_numbers.into_iter()); - let final_disjunct_loc = state_stack.len(); - - for ((subterm, term_loc), branch_num) in iter.rev() { - state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); - state_stack.push(TraversalState::RemoveBranchNum); - state_stack.push(TraversalState::Term { subterm, term_loc }); - state_stack.push(TraversalState::AddBranchNum(branch_num)); - } - - if let TraversalState::BuildDisjunct(build_stack_len) = - state_stack[final_disjunct_loc] - { - state_stack[final_disjunct_loc] = - TraversalState::BuildFinalDisjunct(build_stack_len); - } - - build_stack.current_chunk_type = ChunkType::Mid; - build_stack.current_chunk_num += 1; - } - (atom!("->"), 2) => { - let if_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let then_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - - let if_term = heap[if_term_loc]; - let then_term = heap[then_term_loc]; - - let prev_b = if matches!( - state_stack.last(), - Some(TraversalState::RemoveBranchNum) - ) { - // check if the second-to-last element - // is a regular BuildDisjunct, as we - // don't want to add GetPrevLevel in - // case of a TrustMe. - match state_stack.iter().rev().nth(1) { - Some(&TraversalState::BuildDisjunct(preceding_len)) => { - preceding_len + 1 == build_stack.len() - } - _ => false, - } - } else { - false - }; - - state_stack.push(TraversalState::Term { - subterm: then_term, - term_loc: then_term_loc, - }); - state_stack.push(TraversalState::Cut { - var_num: self.var_num, - is_global: false, - }); - state_stack.push(TraversalState::Term { - subterm: if_term, - term_loc: if_term_loc, - }); - state_stack.push(TraversalState::GetCutPoint { - var_num: self.var_num, - prev_b, - }); - - self.var_num += 1; - } - (atom!("\\+"), 1) => { - let not_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let not_term = heap[not_term_loc]; - let build_stack_len = build_stack.len(); - - build_stack.reserve_branch(2); - - let branch_num = self.current_branch_num.split(); - let succ_branch_num = branch_num.incr_by_delta(); - - state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len)); - state_stack.push(TraversalState::Succeed); - state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); - state_stack.push(TraversalState::RepBranchNum(succ_branch_num)); - state_stack.push(TraversalState::Fail); - state_stack.push(TraversalState::CutPrev(self.var_num)); - state_stack.push(TraversalState::ResetGlobalCutVarOverride( - self.global_cut_var_num_override, - )); - state_stack.push(TraversalState::Term { - subterm: not_term, - term_loc: not_term_loc, - }); - state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num)); - state_stack.push(TraversalState::GetCutPoint { - var_num: self.var_num, - prev_b: false, - }); - state_stack.push(TraversalState::AddBranchNum(branch_num)); - - build_stack.current_chunk_type = ChunkType::Mid; - build_stack.current_chunk_num += 1; - - self.var_num += 1; - } - (atom!(":"), 2) => { - let module_name_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let predicate_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - let mut focused = FocusedHeapRefMut::from(heap, module_name_loc); - - let module_name = focused.deref_loc(module_name_loc); - let predicate_term = focused.deref_loc(predicate_term_loc); - - read_heap_cell!(module_name, - (HeapCellValueTag::Atom, (module_name, arity)) => { - if arity == 0 { - read_heap_cell!(predicate_term, - (HeapCellValueTag::Str, s) => { - let key = cell_as_atom_cell!(heap[s]) - .get_name_and_arity(); - - add_qualified_chunk!( - module_name, - key, - HeapCellValueTag::Str, - s - ); - } - (HeapCellValueTag::Atom, (predicate_name, predicate_arity)) => { - debug_assert_eq!(predicate_arity, 0); - let key = (predicate_name, predicate_arity); - - add_qualified_chunk!( - module_name, - key, - HeapCellValueTag::Str, - predicate_term_loc - ); - } - _ => {} - ); - - continue 'outer; - } - } - _ => {} - ); - - if update_chunk_data(&mut build_stack, (atom!("call"), 2)) { - build_stack.add_chunk(); - } - - let context = build_stack.current_gen_context(); - - focused.focus = module_name_loc; - - self.probe_body_term( - 1, 0, &mut focused, &terms.inverse_var_locs, context, - ); - - focused.focus = predicate_term_loc; - - self.probe_body_term( - 2, 0, &mut focused, &terms.inverse_var_locs, context, - ); - - let h = heap.cell_len(); - - heap.push_cell(atom_as_cell!(atom!("call"), 1)) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - heap.push_cell(str_loc_as_cell!(subterm_loc)) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - - build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( - loader, - (atom!("call"), 1), - terms, - str_loc_as_cell!(h), - self.call_policy, - ))); - } - (atom!("$call_with_inference_counting"), 1) => { - let term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let heap = loader.machine_heap(); - let subterm = heap_bound_store( - heap, - heap_bound_deref(heap, heap[term_loc]), - ); - - state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); - state_stack.push(TraversalState::Term { subterm, term_loc }); - - self.call_policy = CallPolicy::Counted; - } - (name, arity) => { - add_chunk!((name, arity), HeapCellValueTag::Str, subterm_loc); - } - } - } - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); - - if name == atom!("!") { - let context = build_stack.current_gen_context(); - state_stack.push(self.new_cut_state(context)); + match term { + Term::Clause( + _, + name @ (atom!("->") | atom!(";") | atom!(",")), + mut terms, + ) if terms.len() == 3 => { + if let Some(last_arg) = terms.last() { + if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { + terms.pop(); + state_stack.push(TraversalState::Term(Term::Clause( + Cell::default(), + name, + terms, + ))); } else { - add_chunk!((name, 0), HeapCellValueTag::Var, term_loc); + add_chunk(self, name, terms); } } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h != term_loc { - subterm = heap[h]; - term_loc = h; - continue; + } + 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 + }); + } + + 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 (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)); + } + + 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; + } + 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 + }; - add_chunk!((atom!("call"), 1), HeapCellValueTag::Var, h); - } - _ => { - return Err(CompilationError::InadmissibleQueryTerm); - } - ); + 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, + }); - break; + self.var_num += 1; + } + Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => { + let not_term = terms.pop().unwrap(); + let build_stack_len = build_stack.len(); + + build_stack.reserve_branch(2); + + state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len)); + state_stack.push(TraversalState::Term(Term::Clause( + Cell::default(), + atom!("$succeed"), + vec![], + ))); + state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); + state_stack.push(TraversalState::Fail); + state_stack.push(TraversalState::CutPrev(self.var_num)); + state_stack.push(TraversalState::ResetGlobalCutVarOverride( + self.global_cut_var_num_override, + )); + state_stack.push(TraversalState::Term(not_term)); + state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num)); + state_stack.push(TraversalState::GetCutPoint { + var_num: self.var_num, + prev_b: false, + }); + + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; + + self.var_num += 1; + } + Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => { + let predicate_name = terms.pop().unwrap(); + let module_name = terms.pop().unwrap(); + + match (module_name, predicate_name) { + ( + Term::Literal(_, Literal::Atom(module_name)), + Term::Literal(_, Literal::Atom(predicate_name)), + ) => { + if update_chunk_data(self, predicate_name, 0) { + build_stack.add_chunk(); + } + + 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(); + } + + for (arg_c, term) in terms.iter().enumerate() { + self.probe_body_term(arg_c + 1, terms.len(), term); + } + + build_stack.push_chunk_term(qualified_clause_to_query_term( + loader, + module_name, + name, + terms, + self.call_policy, + )); + } + (module_name, predicate_name) => { + if update_chunk_data(self, atom!("call"), 2) { + build_stack.add_chunk(); + } + + self.probe_body_term(1, 0, &module_name); + self.probe_body_term(2, 0, &predicate_name); + + terms.push(module_name); + terms.push(predicate_name); + + build_stack.push_chunk_term(clause_to_query_term( + loader, + atom!("call"), + vec![Term::Clause(Cell::default(), atom!(":"), terms)], + self.call_policy, + )); + } + } + } + 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())); + + 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(); + } + + self.probe_body_term(1, 1, &var); + + build_stack.push_chunk_term(clause_to_query_term( + loader, + atom!("call"), + vec![var], + self.call_policy, + )); + } + Term::Literal(_, Literal::Atom(atom!("!"))) => { + let (var_num, is_global) = + if let Some(var_num) = self.global_cut_var_num_override { + (var_num, false) + } else if let Some(var_num) = self.global_cut_var_num { + (var_num, true) + } else { + let var_num = self.var_num; + + self.global_cut_var_num = Some(var_num); + self.var_num += 1; + + (var_num, true) + }; + + self.probe_in_situ_var(var_num); + + state_stack.push(TraversalState::Cut { var_num, is_global }); + } + Term::Literal(_, Literal::Atom(name)) => { + if update_chunk_data(self, name, 0) { + build_stack.add_chunk(); + } + + build_stack.push_chunk_term(clause_to_query_term( + loader, + name, + vec![], + self.call_policy, + )); + } + _ => { + return Err(CompilationError::InadmissibleQueryTerm); + } } } } @@ -1035,13 +856,13 @@ impl BranchMap { records: VariableRecords::new(var_num), global_cut_var_num, allocates: current_chunk_num > 0, - var_locs_to_nums: VarLocsToNums::default(), }; for (var, branches) in self.iter_mut() { - let (mut var_num, var_num_incr) = match var { - &ClassifiedVar::InSitu { var_num } => (var_num, false), - _ => (var_data.records.len(), true), + let (mut var_num, var_num_incr) = if let Var::InSitu(var_num) = *var.borrow() { + (var_num, false) + } else { + (var_data.records.len(), true) }; for branch in branches.iter_mut() { @@ -1059,10 +880,7 @@ impl BranchMap { for var_info in chunk.vars.iter_mut() { if var_info.lvl == Level::Shallow { - let context = var_info - .chunk_type - .to_gen_context(chunk.term_loc.chunk_num()); - + let context = var_info.chunk_type.to_gen_context(chunk.chunk_num); temp_var_data .use_set .insert((context, var_info.classify_info.arg_c)); @@ -1081,16 +899,8 @@ impl BranchMap { for chunk in branch.chunks.iter_mut() { var_data.records[var_num].num_occurrences += chunk.vars.len(); - if let Some(term_loc) = var.term_loc() { - let chunk_num = chunk.term_loc.chunk_num(); - - var_data.var_locs_to_nums.insert( - VarPtrIndex { - chunk_num, - term_loc, - }, - var_num, - ); + for var_info in chunk.vars.iter_mut() { + var_info.var_ptr.set(Var::Generated(var_num)); } } } diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index cd672320..f1519986 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -2829,7 +2829,7 @@ impl Machine { Some(PStrCmpResult::PartialPStrMatch { string, var_loc }) => { let cell = backtrack_on_resource_error!( self.machine_st, - self.machine_st.allocate_pstr(string) + self.machine_st.heap.allocate_pstr(string) ); self.machine_st.mode = MachineMode::Write; @@ -2851,7 +2851,7 @@ impl Machine { HeapCellValueTag::Var) => { let target_cell = backtrack_on_resource_error!( self.machine_st, - self.machine_st.allocate_pstr(string) + self.machine_st.heap.allocate_pstr(string) ); self.machine_st.bind( @@ -3196,7 +3196,7 @@ impl Machine { &Instruction::PutPartialString(_, ref string, reg) => { self.machine_st[reg] = backtrack_on_resource_error!( self.machine_st, - self.machine_st.allocate_pstr(&string) + self.machine_st.heap.allocate_pstr(&string) ); self.machine_st.p += 1; diff --git a/src/machine/gc.rs b/src/machine/gc.rs index cb46f861..7c79eba0 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -1,3 +1,10 @@ +#[cfg(test)] +use fxhash::FxBuildHasher; +#[cfg(test)] +use indexmap::IndexMap; +#[cfg(test)] +use std::collections::BTreeMap; + #[cfg(test)] use crate::atom_table::*; #[cfg(test)] @@ -8,17 +15,6 @@ use crate::types::*; #[cfg(test)] use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc}; -#[cfg(test)] -use std::collections::BTreeMap; -#[cfg(test)] -use std::ops::Deref; - -#[cfg(test)] -use fxhash::FxBuildHasher; - -#[cfg(test)] -use indexmap::IndexMap; - #[cfg(test)] pub(crate) trait UnmarkPolicy { fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option @@ -185,15 +181,6 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> { pstr_loc_values: PStrLocValuesMap, } -#[cfg(test)] -impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> { - type Target = Heap; - - fn deref(&self) -> &Self::Target { - self.heap - } -} - #[cfg(test)] impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> { #[inline] @@ -778,7 +765,7 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap(); + let pstr_cell = wam.machine_st.heap.allocate_pstr("abc ").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); @@ -812,7 +799,7 @@ mod tests { wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.allocate_pstr("abcdef ").unwrap(); + wam.machine_st.heap.allocate_pstr("abcdef ").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap(); mark_cells(&mut wam.machine_st.heap, 2); diff --git a/src/machine/heap.rs b/src/machine/heap.rs index efd4337c..0c754baf 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -4,13 +4,12 @@ use crate::functor_macro::*; use crate::types::*; use std::alloc; +use std::cmp::Ordering; use std::convert::TryFrom; use std::ops::{Bound, Index, IndexMut, Range, RangeBounds}; use std::ptr; use std::sync::Once; -use super::MachineState; - const ALIGN: usize = Heap::heap_cell_alignment(); #[derive(Debug)] @@ -92,9 +91,10 @@ pub struct HeapStringScan<'a> { } // return the string at ptr and the tail location relative to ptr. -unsafe fn scan_slice_to_str<'a>(heap_slice: &'a [u8]) -> HeapStringScan<'a> { +unsafe fn scan_slice_to_str(heap_slice: &[u8]) -> HeapStringScan { let string_len = heap_slice.iter().position(|b| *b == 0u8).unwrap(); let zero_byte_addr = heap_slice.as_ptr().add(string_len); + let sentinel_len = pstr_sentinel_length(zero_byte_addr as usize); let tail_idx = cell_index!( (string_len + sentinel_len).next_multiple_of(ALIGN) @@ -111,79 +111,9 @@ unsafe fn scan_slice_to_str<'a>(heap_slice: &'a [u8]) -> HeapStringScan<'a> { #[derive(Debug, Clone, Copy)] pub(crate) enum PStrSegmentCmpResult { - Mismatch { - c1: char, - c2: char, - }, - FirstMatch { - pstr_loc1: usize, - pstr_loc2: usize, - l1_offset: usize, - }, - SecondMatch { - pstr_loc1: usize, - pstr_loc2: usize, - l2_offset: usize, - }, - BothMatch { - pstr_loc1: usize, - pstr_loc2: usize, - null_offset: usize, - }, -} - -impl PStrSegmentCmpResult { - pub(crate) fn continue_pstr_compare( - self, - pdl: &mut Vec, - ) -> Option { - match self { - PStrSegmentCmpResult::FirstMatch { - pstr_loc1, - pstr_loc2, - l1_offset, - } => { - let tail1 = Heap::pstr_tail_idx(pstr_loc1 + l1_offset); - let rest_of_l2 = pstr_loc_as_cell!(pstr_loc2 + l1_offset); - - pdl.push(heap_loc_as_cell!(tail1)); - pdl.push(rest_of_l2); - } - PStrSegmentCmpResult::SecondMatch { - pstr_loc1, - pstr_loc2, - l2_offset, - } => { - let tail2 = Heap::pstr_tail_idx(pstr_loc2 + l2_offset); - let rest_of_l1 = pstr_loc_as_cell!(pstr_loc1 + l2_offset); - - pdl.push(rest_of_l1); - pdl.push(heap_loc_as_cell!(tail2)); - } - PStrSegmentCmpResult::BothMatch { - pstr_loc1, - pstr_loc2, - null_offset, - } => { - // exhaustive match - let tail1 = Heap::pstr_tail_idx(pstr_loc1 + null_offset); - let tail2 = Heap::pstr_tail_idx(pstr_loc2 + null_offset); - - pdl.push(heap_loc_as_cell!(tail1)); - pdl.push(heap_loc_as_cell!(tail2)); - } - PStrSegmentCmpResult::Mismatch { c1, c2 } => { - return Some(c1.cmp(&c2)); - } - } - - None - } -} - -#[derive(Debug)] -pub struct PStrWriteInfo { - cell: HeapCellValue, + Less, + Greater, + Continue(HeapCellValue, HeapCellValue), } #[derive(Debug)] @@ -269,7 +199,6 @@ impl ReservedHeapSection { } self.push_cell(char_as_cell!('\u{0}')); - src = &src[1..]; } @@ -277,8 +206,6 @@ impl ReservedHeapSection { return ret; } - debug_assert!(!src.is_empty()); - if let Some(null_char_idx) = src.find('\u{0}') { debug_assert_ne!(null_char_idx, 0); @@ -300,6 +227,7 @@ impl ReservedHeapSection { self.push_cell(char_as_cell!('\u{0}')); src = &src[null_char_idx + 1..]; + if src.is_empty() { return ret; } @@ -316,7 +244,6 @@ impl ReservedHeapSection { } self.push_pstr_segment(&src); - return ret; } } @@ -449,23 +376,6 @@ impl<'a> HeapWriter<'a> { result, } } - - #[inline] - pub(crate) fn truncate(&mut self, cell_offset: usize) { - self.section.heap_cell_len = cell_offset; - // self.section.pstr_vec.truncate(cell_offset); - *self.heap_byte_len = heap_index!(cell_offset); - } - - #[inline] - pub(crate) fn is_empty(&self) -> bool { - self.section.heap_cell_len == 0 - } - - #[inline] - pub(crate) fn cell_len(&self) -> usize { - self.section.heap_cell_len - } } impl<'a> Index for HeapWriter<'a> { @@ -517,8 +427,6 @@ impl<'a> SizedHeap for HeapWriter<'a> { } } -impl<'a> SizedHeapMut for HeapWriter<'a> {} - impl Heap { pub(crate) fn new() -> Self { Self { @@ -638,16 +546,6 @@ impl Heap { self.inner.byte_len == 0 } - pub(crate) fn index_of(&mut self, cell: HeapCellValue) -> Result { - Ok(if cell.is_var() { - cell.get_value() as usize - } else { - let focus = self.cell_len(); - self.push_cell(cell)?; - focus - }) - } - pub(crate) fn clear(&mut self) { unsafe { let layout = alloc::Layout::array::(self.inner.byte_cap).unwrap(); @@ -699,48 +597,69 @@ impl Heap { pstr_loc1: usize, pstr_loc2: usize, ) -> PStrSegmentCmpResult { - unsafe { - let slice1 = std::slice::from_raw_parts( - self.inner.ptr.add(pstr_loc1), - self.inner.byte_len - pstr_loc1, - ); + let slice1 = &self.as_slice()[pstr_loc1..]; + let slice2 = &self.as_slice()[pstr_loc2..]; - let slice2 = std::slice::from_raw_parts( - self.inner.ptr.add(pstr_loc2), - self.inner.byte_len - pstr_loc2, - ); + let find_tail = |null_idx: usize| -> usize { self.scan_slice_to_str(null_idx).tail_idx }; - let str1 = std::str::from_utf8_unchecked(&slice1); - let str2 = std::str::from_utf8_unchecked(&slice2); + match slice1 + .iter() + .zip(slice2.iter()) + .position(|(b1, b2)| b1 != b2 || *b1 == 0 || *b2 == 0) + { + Some(pos) => { + if slice1[pos] == 0 { + // subtract 1 from pos to offset the increment of scan_slice_to_str if the + // string is "\0\". + let tail1_idx = find_tail(pstr_loc1 + pos); - debug_assert!(!str1.is_empty()); - debug_assert!(!str2.is_empty()); + if slice2[pos] == 0 { + let tail2_idx = find_tail(pstr_loc2 + pos); - for ((idx, c1), c2) in str1.char_indices().zip(str2.chars()) { - if c1 == '\u{0}' && c2 == '\u{0}' { - return PStrSegmentCmpResult::BothMatch { - pstr_loc1, - pstr_loc2, - null_offset: idx, - }; - } else if c1 == '\u{0}' { - return PStrSegmentCmpResult::FirstMatch { - pstr_loc1, - pstr_loc2, - l1_offset: idx, - }; - } else if c2 == '\u{0}' { - return PStrSegmentCmpResult::SecondMatch { - pstr_loc1, - pstr_loc2, - l2_offset: idx, - }; - } else if c1 != c2 { - return PStrSegmentCmpResult::Mismatch { c1, c2 }; + PStrSegmentCmpResult::Continue( + heap_loc_as_cell!(tail1_idx), + heap_loc_as_cell!(tail2_idx), + ) + } else { + PStrSegmentCmpResult::Continue( + heap_loc_as_cell!(tail1_idx), + pstr_loc_as_cell!(pstr_loc2 + pos), + ) + } + } else if slice2[pos] == 0 { + let tail2_idx = find_tail(pstr_loc2 + pos); + + PStrSegmentCmpResult::Continue( + pstr_loc_as_cell!(pstr_loc1 + pos), + heap_loc_as_cell!(tail2_idx), + ) + } else { + // Compute 7-byte chunks with the mismatching character at pos in the middle of + // each. This way, the character of which the byte at pos is a part will be + // validated and reached eventually by the utf8_chunks() iterator. + + let slice1_range = pos.saturating_sub(3)..(pos + 4).min(slice1.len()); + let slice2_range = pos.saturating_sub(3)..(pos + 4).min(slice2.len()); + + let chars1_iter = slice1[slice1_range].utf8_chunks(); + let chars2_iter = slice2[slice2_range].utf8_chunks(); + + for (chunk1, chunk2) in chars1_iter.zip(chars2_iter) { + let result = chunk1.valid().cmp(chunk2.valid()); + + if result == Ordering::Greater { + return PStrSegmentCmpResult::Greater; + } else if result == Ordering::Less { + return PStrSegmentCmpResult::Less; + } + } + + unreachable!() } } - - unreachable!() // PStrSegmentCmpResult::Match(std::cmp::min(str1.len(), str2.len())) + None => { + unreachable!() + } } } @@ -833,43 +752,34 @@ impl Heap { Range { start, end } } - /* - pub(crate) fn splice>( - &self, - range: R, - ) -> HeapView { - let range = self.slice_range(range); - - HeapView { - slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, - cell_offset: range.start, - slice_cell_len: range.end - range.start, - // pstr_slice: &self.pstr_vec.as_bitslice()[range], - } - } - - pub(crate) fn splice_mut>( - &self, - range: R, - ) -> HeapViewMut { - let range = self.slice_range(range); - - HeapViewMut { - slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, - cell_offset: range.start, - slice_cell_len: range.end - range.start, - // pstr_slice: &self.pstr_vec.as_bitslice()[range], - } - } - */ - - pub fn allocate_pstr(&mut self, src: &str) -> Result, usize> { + pub fn allocate_pstr(&mut self, src: &str) -> Result { let size_in_heap = Self::compute_pstr_size(src); let mut writer = self.reserve(size_in_heap)?; let HeapSectionWriteResult { result, .. } = - writer.write_with(|section| section.push_pstr(src)); + writer.write_with(|section| match section.push_pstr(src) { + None => empty_list_as_cell!(), + Some(cell) => cell, + }); - Ok(result.map(|cell| PStrWriteInfo { cell })) + Ok(result) + } + + // note that allocate_cstr emits a tail cell to the string (completing it with the empty list) + // unlike any version of allocate_pstr. + + pub fn allocate_cstr(&mut self, src: &str) -> Result { + let size_in_heap = Self::compute_pstr_size(src); + let mut writer = self.reserve(size_in_heap + 1)?; + let HeapSectionWriteResult { result, .. } = + writer.write_with(|section| match section.push_pstr(src) { + None => empty_list_as_cell!(), + Some(cell) => { + section.push_cell(empty_list_as_cell!()); + cell + } + }); + + Ok(result) } pub const fn heap_cell_alignment() -> usize { @@ -1007,7 +917,7 @@ impl Heap { // by at least two null bytes so one of them may be used // to mark partial strings e.g. during iteration - if (null_idx + 1) % ALIGN == 0 { + if (null_idx + 1).next_multiple_of(ALIGN) == null_idx + 1 { byte_size += 2 * size_of::(); } else { byte_size += size_of::(); @@ -1107,27 +1017,6 @@ impl<'a> Iterator for PStrSegmentIter<'a> { } } -impl MachineState { - pub(crate) fn allocate_pstr(&mut self, src: &str) -> Result { - match self.heap.allocate_pstr(src)? { - None => Ok(empty_list_as_cell!()), - Some(PStrWriteInfo { cell }) => Ok(cell), - } - } - - // note that allocate_cstr emits a tail cell to the string (completing it with the empty list) - // unlike any version of allocate_pstr. - pub(crate) fn allocate_cstr(&mut self, src: &str) -> Result { - match self.heap.allocate_pstr(src)? { - None => Ok(empty_list_as_cell!()), - Some(PStrWriteInfo { cell }) => { - self.heap.push_cell(empty_list_as_cell!())?; - Ok(cell) - } - } - } -} - pub trait SizedHeap: Index { // return the size of the instance in cells fn cell_len(&self) -> usize; @@ -1141,8 +1030,6 @@ pub trait SizedHeap: Index { // fn pstr_at(&self, cell_offset: usize) -> bool; } -pub trait SizedHeapMut: IndexMut + SizedHeap {} - impl Index for Heap { type Output = HeapCellValue; @@ -1183,8 +1070,6 @@ impl SizedHeap for Heap { } } -impl SizedHeapMut for Heap {} - // sometimes we need to dereference variables that are found only in // the heap without access to the full WAM (e.g., while detecting // cycles in terms), and which therefore may only point other cells in diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index c139bc12..66c1783a 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -1,15 +1,18 @@ +use std::cmp::Ordering; use std::collections::BTreeMap; +use std::rc::Rc; use crate::atom_table; use crate::heap_iter::{stackful_post_order_iter, NonListElider}; +use crate::machine::machine_indices::VarKey; use crate::machine::mock_wam::CompositeOpDir; use crate::machine::{ ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS, }; -use crate::parser::ast::{TermWriteResult, Var}; -use crate::parser::lexer::LexerParser; -use crate::parser::parser::Tokens; +use crate::parser::ast::{Var, VarPtr}; +use crate::parser::parser::{Parser, Tokens}; +use crate::read::{write_term_to_heap, TermWriteResult}; use crate::types::UntypedArenaPtr; use dashu::{Integer, Rational}; @@ -169,7 +172,7 @@ impl Term { pub(crate) fn from_heapcell( machine: &mut Machine, heap_cell: HeapCellValue, - var_names: &mut IndexMap, + var_names: &mut IndexMap, ) -> Self { // Adapted from MachineState::read_term_from_heap let mut term_stack = vec![]; @@ -183,6 +186,16 @@ impl Term { ); let mut anon_count: usize = 0; + let var_ptr_cmp = |a, b| match a { + Var::Named(name_a) => match b { + Var::Named(name_b) => name_a.cmp(&name_b), + _ => Ordering::Less, + }, + _ => match b { + Var::Named(_) => Ordering::Greater, + _ => Ordering::Equal, + }, + }; while let Some(addr) = iter.next() { let addr = unmark_cell_bits!(addr); @@ -233,33 +246,34 @@ impl Term { term_stack.push(list); } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - let var = var_names.get(&addr).cloned(); + let var = var_names.get(&addr).map(|x| x.borrow().clone()); match var { - Some(name) => term_stack.push(Term::Var(name.to_string())), + Some(Var::Named(name)) => term_stack.push(Term::Var(name.as_ref().to_owned())), _ => { let anon_name = loop { // Generate a name for the anonymous variable - let anon_name = count_to_letter_code(anon_count); + let anon_name = Rc::new(count_to_letter_code(anon_count)); // Find if this name is already being used - var_names.sort_by(|_, a, _, b| a.cmp(b)); - + var_names.sort_by(|_, a, _, b| { + var_ptr_cmp(a.borrow().clone(), b.borrow().clone()) + }); let binary_result = var_names.binary_search_by(|_,a| { - let a: &String = a.as_ref(); - a.cmp(&anon_name) + let var_ptr = Var::Named(anon_name.clone()); + var_ptr_cmp(a.borrow().clone(), var_ptr.clone()) }); match binary_result { Ok(_) => anon_count += 1, // Name already used Err(_) => { // Name not used, assign it to this variable - let var = anon_name.clone(); - var_names.insert(addr, Var::from(var)); + let var_ptr = VarPtr::from(Var::Named(anon_name.clone())); + var_names.insert(addr, var_ptr); break anon_name; }, } }; - term_stack.push(Term::Var(anon_name)); + term_stack.push(Term::Var(anon_name.as_ref().to_owned())); }, } } @@ -401,7 +415,7 @@ pub struct QueryState<'a> { machine: &'a mut Machine, term: TermWriteResult, stub_b: usize, - var_names: IndexMap, + var_names: IndexMap, called: bool, } @@ -465,7 +479,7 @@ impl Iterator for QueryState<'_> { } if machine.machine_st.p == LIB_QUERY_SUCCESS { - if term_write_result.inverse_var_locs.is_empty() { + if term_write_result.var_dict.is_empty() { self.machine.machine_st.backtrack(); return Some(Ok(LeafAnswer::True)); } @@ -474,39 +488,47 @@ impl Iterator for QueryState<'_> { } let mut bindings: BTreeMap = BTreeMap::new(); - let inverse_var_locs = &term_write_result.inverse_var_locs; - for (var_loc, var_name) in inverse_var_locs.iter() { + let var_dict = &term_write_result.var_dict; + + for (var_key, term_to_be_printed) in var_dict.iter() { + let mut var_name = var_key.to_string(); if var_name.starts_with('_') { - let should_print = var_names.values().any(|v| v == var_name); + let should_print = var_names.values().any(|x| match x.borrow().clone() { + Var::Named(v) => *v == *var_name, + _ => false, + }); if !should_print { continue; } } - let var_loc = *var_loc; - let term = - Term::from_heapcell(machine, heap_loc_as_cell!(var_loc), &mut var_names.clone()); + let mut term = + Term::from_heapcell(machine, *term_to_be_printed, &mut var_names.clone()); if let Term::Var(ref term_str) = term { - if *term_str == **var_name { + if *term_str == var_name { continue; } - // inverse_var_locs is in the order things appear in - // the query. If var_name appears after term in the - // query, switch their places. - let var_cell = machine - .machine_st - .store(machine.machine_st.deref(machine.machine_st.heap[var_loc])); - - if (var_cell.get_value() as usize) < var_loc { - bindings.insert(term_str.clone(), Term::Var(var_name.to_string())); - continue; + // Var dict is in the order things appear in the query. If var_name appears + // after term in the query, switch their places. + let var_name_idx = var_dict + .get_index_of(&VarKey::VarPtr(Var::from(var_name.clone()).into())) + .unwrap(); + let term_idx = + var_dict.get_index_of(&VarKey::VarPtr(Var::from(term_str.clone()).into())); + if let Some(idx) = term_idx { + if idx < var_name_idx { + let new_term = Term::Var(var_name); + let new_var_name = term_str.into(); + term = new_term; + var_name = new_var_name; + } } } - bindings.insert(var_name.to_string(), term); + bindings.insert(var_name, term); } // NOTE: there are outstanding choicepoints, backtrack @@ -530,9 +552,9 @@ impl Machine { pub fn consult_module_string(&mut self, module_name: &str, program: impl Into) { let stream = Stream::from_owned_string(program.into(), &mut self.machine_st.arena); self.machine_st.registers[1] = stream_as_cell!(stream); - self.machine_st.registers[2] = atom_as_cell!(atom_table::AtomTable::build_with( + self.machine_st.registers[2] = atom_as_cell!(&atom_table::AtomTable::build_with( &self.machine_st.atom_tbl, - module_name, + module_name )); self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2)); @@ -564,7 +586,7 @@ impl Machine { /// Runs a query. pub fn run_query(&mut self, query: impl Into) -> QueryState { - let mut parser = LexerParser::new( + let mut parser = Parser::new( Stream::from_owned_string(query.into(), &mut self.machine_st.arena), &mut self.machine_st, ); @@ -575,10 +597,26 @@ impl Machine { self.allocate_stub_choice_point(); - // Write term to heap - self.machine_st.registers[1] = self.machine_st.heap[term.focus]; - self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC; + // Write parsed term to heap + let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap) + .expect("couldn't write term to heap"); + let var_names: IndexMap<_, _> = term_write_result + .var_dict + .iter() + .map(|(var_key, cell)| match var_key { + // NOTE: not the intention behind Var::InSitu here but + // we can hijack it to store anonymous variables + // without creating problems. + VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))), + VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()), + }) + .collect(); + + // Write term to heap + self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc]; + + self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC; let call_index_p = self .indices .code_dir @@ -587,22 +625,12 @@ impl Machine { .local() .unwrap(); - let var_names: IndexMap<_, _> = term - .inverse_var_locs - .iter() - .map(|(var_loc, var)| { - let cell = self.machine_st.heap[*var_loc]; - (cell, var.clone()) - }) - .collect(); - self.machine_st.execute_at_index(1, call_index_p); let stub_b = self.machine_st.b; - QueryState { machine: self, - term, + term: term_write_result, stub_b, var_names, called: false, diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 9ac56972..64d0bb82 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -1150,8 +1150,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let mut path_buf = PathBuf::from(&*filename.as_str()); path_buf.set_extension("pl"); - let file = File::open(&path_buf) - .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?; + let file = File::open(&path_buf)?; ( Stream::from_file_as_input( @@ -1232,8 +1231,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ModuleSource::File(filename) => { let mut path_buf = PathBuf::from(&*filename.as_str()); path_buf.set_extension("pl"); - let file = File::open(&path_buf) - .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?; + let file = File::open(&path_buf)?; ( Stream::from_file_as_input( diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 0d850150..c117887b 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -15,28 +15,12 @@ use crate::types::*; use indexmap::IndexSet; +use std::cell::Cell; use std::collections::VecDeque; use std::convert::TryFrom; use std::fmt; use std::ops::{Deref, DerefMut}; - -impl TermWriteResult { - pub(super) fn from(heap: &mut Heap, value: HeapCellValue) -> Result { - let focus = heap.index_of(value)?; - let mut stack = Stack::uninitialized(); - - heap[0] = value; - - let inverse_var_locs = inverse_var_locs_from_iter(stackful_preorder_iter::( - heap, &mut stack, 0, - )); - - Ok(Self { - focus, - inverse_var_locs, - }) - } -} +use std::rc::Rc; /* * The loader compiles Prolog terms read from a TermStream instance, @@ -194,18 +178,18 @@ impl CompilationTarget { } pub struct PredicateQueue { - pub predicates: Vec, - pub compilation_target: CompilationTarget, + pub(super) predicates: Vec, + pub(super) compilation_target: CompilationTarget, } impl PredicateQueue { #[inline] - pub(super) fn push(&mut self, term_write_result: TermWriteResult) { - self.predicates.push(term_write_result); + pub(super) fn push(&mut self, clause: Term) { + self.predicates.push(clause); } #[inline] - pub(crate) fn first(&self) -> Option<&TermWriteResult> { + pub(crate) fn first(&self) -> Option<&Term> { self.predicates.first() } @@ -416,7 +400,7 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { #[inline(always)] fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { - loader.term_stream.lexer_parser.machine_st + loader.term_stream.parser.lexer.machine_st } #[inline(always)] @@ -508,9 +492,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } - #[inline] - pub(super) fn machine_heap(&mut self) -> &mut Heap { - &mut LS::machine_st(&mut self.payload).heap + pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Term { + let machine_st = LS::machine_st(&mut self.payload); + let cell = machine_st[r]; + + machine_st.read_term_from_heap(cell) } pub(crate) fn load(mut self) -> Result { @@ -527,30 +513,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let compilation_target = &load_state.compilation_target; let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target); - let mut term = load_state.term_stream.next(&composite_op_dir)?; - let predicate_focus_opt = load_state - .predicates - .first() - .map(|term_write_result| term_write_result.focus); + let term = load_state.term_stream.next(&composite_op_dir)?; - let machine_st = LS::machine_st(&mut self.payload); - let term_key_opt = clause_predicate_key(&machine_st.heap, term.focus); + if !term.is_consistent(&load_state.predicates) { + self.compile_and_submit()?; + } - if let Some(predicate_focus) = predicate_focus_opt { - let predicate_key_opt = clause_predicate_key(&machine_st.heap, predicate_focus); - - debug_assert!(predicate_key_opt.is_some()); - - if term_key_opt != predicate_key_opt { - self.compile_and_submit()?; + let term = match term { + Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => { + return Ok(Some(setup_declaration(self, terms)?)); } - } - - if Some((atom!(":-"), 1)) == term_key_opt { - let machine_st = LS::machine_st(&mut self.payload); - term.focus = term_nth_arg(&machine_st.heap, term.focus, 1).unwrap(); - return Ok(Some(setup_declaration(self, term)?)); - } + term => term, + }; self.payload.predicates.push(term); } @@ -788,7 +762,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ) => { remove_constant_indices( constant, - &overlapping_constants, + overlapping_constants, indexing_code, clause_loc - index_loc, // WAS: &inner_index_locs, ); @@ -1071,73 +1045,30 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let machine_st = LS::machine_st(&mut self.payload); let cell = machine_st[r]; - let focus = machine_st.heap.cell_len(); - machine_st - .heap - .push_cell(cell) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - - let export_list = FocusedHeapRefMut { - heap: &mut machine_st.heap, - focus, - }; + let export_list = machine_st.read_term_from_heap(cell); let export_list = setup_module_export_list(export_list)?; Ok(export_list.into_iter().collect()) } - fn clause_clause(&mut self, cell: HeapCellValue) -> Result { - let machine_st = LS::machine_st(&mut self.payload); - let focus = machine_st.heap.cell_len(); + 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(); - read_heap_cell!(cell, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) - .get_name_and_arity(); - - let mut writer = machine_st.heap.reserve(4) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - - writer.write_with(|section| { - section.push_cell(str_loc_as_cell!(focus+1)); - section.push_cell(atom_as_cell!(atom!("clause"), 2)); - - match (name, arity) { - (atom!(":-"), 2) => { - section.push_cell(heap_loc_as_cell!(s+1)); - section.push_cell(heap_loc_as_cell!(s+2)); - } - _ => { - section.push_cell(str_loc_as_cell!(s)); - section.push_cell(atom_as_cell!(atom!("true"))); - } - } - }); + self.payload.clause_clauses.push((head, body)); } - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - let mut writer = machine_st.heap.reserve(4) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - - writer.write_with(|section| { - section.push_cell(str_loc_as_cell!(focus+1)); - section.push_cell(atom_as_cell!(atom!("clause"), 2)); - section.push_cell(atom_as_cell!(name)); - section.push_cell(atom_as_cell!(atom!("true"))); - }); - } else { - return Err(CompilationError::InadmissibleFact); - } + head @ (Term::Clause(..) | Term::Literal(_, Literal::Atom(_))) => { + let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true"))); + self.payload.clause_clauses.push((head, body)); } _ => { return Err(CompilationError::InadmissibleFact); } - ); + } - Ok( - TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus)) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?, - ) + Ok(()) } fn add_extensible_predicate_declaration( @@ -1355,11 +1286,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ) } - fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> { - let machine_st = LS::machine_st(&mut self.payload); - let key_opt = clause_predicate_key_from_heap(&machine_st.heap, value); - - if let Some((predicate_name, predicate_arity)) = key_opt { + fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> { + if let Some(predicate_name) = ClauseInfo::name(term) { + let predicate_arity = ClauseInfo::arity(term); let predicates_compilation_target = self.payload.predicates.compilation_target; let is_dynamic = self @@ -1373,8 +1302,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .unwrap_or(false); if is_dynamic { - let clause_clause_term = self.clause_clause(value)?; - self.payload.clause_clauses.push(clause_clause_term); + self.add_clause_clause(term.clone())?; } } @@ -1440,6 +1368,90 @@ impl<'a> MachinePreludeView<'a> { } } +impl MachineState { + pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term { + let mut term_stack = vec![]; + self.heap[0] = term_addr; + let mut iter = + stackful_post_order_iter::(&mut self.heap, &mut self.stack, 0); + + while let Some(addr) = iter.next() { + let addr = unmark_cell_bits!(addr); + + if let Ok(literal) = Literal::try_from(addr) { + term_stack.push(Term::Literal(Cell::default(), literal)); + } else { + read_heap_cell!(addr, + (HeapCellValueTag::Lis) => { + use crate::parser::parser::as_partial_string; + + let tail = term_stack.pop().unwrap(); + let head = term_stack.pop().unwrap(); + + match as_partial_string(head, tail) { + Ok((string, Some(tail))) => { + term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail)); + } + Ok((string, None)) => { + term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string))); + } + Err(cons_term) => term_stack.push(cons_term), + } + } + (HeapCellValueTag::StackVar, h) => { + term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h)))); + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { + term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h)))); + } + (HeapCellValueTag::Atom, (name, arity)) => { + let h = iter.focus().value() as usize; + let mut arity = arity; + let value = iter.heap[h.saturating_sub(1)]; + + if let Some(idx) = get_structure_index(value) { + term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx))); + arity += 1; + } + + if arity == 0 { + term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); + } else { + let subterms = term_stack + .drain(term_stack.len() - arity ..) + .collect(); + + term_stack.push(Term::Clause(Cell::default(), name, subterms)); + } + } + (HeapCellValueTag::PStrLoc, h) => { + let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h); + let tail = term_stack.pop().unwrap(); + + term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) { + Term::CompleteString( + Cell::default(), + Rc::new(string.to_owned()), + ) + } else { + Term::PartialString( + Cell::default(), + Rc::new(string.to_owned()), + Box::new(tail), + ) + }); + } + _ => { + } + ); + } + } + + debug_assert!(term_stack.len() == 1); + term_stack.pop().unwrap() + } +} + impl Machine { pub(crate) fn use_module(&mut self) -> CallResult { let subevacuable_addr = self @@ -1600,15 +1612,11 @@ impl Machine { } pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult { - let value = self.machine_st.registers[1]; - let term = resource_error_call_result!( - self.machine_st, - TermWriteResult::from(&mut self.machine_st.heap, value) - ); - let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let add_clause = || { + let term = loader.read_term_from_heap(temp_v!(1)); + loader.incremental_compile_clause( (atom!("term_expansion"), 2), term, @@ -1629,37 +1637,30 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st.registers[1]))); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); + let compilation_target = match target_module_name { atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(target_module_name), }; - let value = self.machine_st.registers[2]; - let term = resource_error_call_result!( - self.machine_st, - TermWriteResult::from(&mut self.machine_st.heap, value) - ); - let add_clause = || { - let indexing_arg_opt = match term_predicate_key(&self.machine_st.heap, term.focus) { - Some((atom!(":-"), _)) => term_nth_arg(&self.machine_st.heap, term.focus, 1) - .and_then(|h| term_nth_arg(&self.machine_st.heap, h, 1)), - Some(_) => term_nth_arg(&self.machine_st.heap, term.focus, 1), + let term = loader.read_term_from_heap(temp_v!(2)); + + let indexing_arg = match term.name() { + Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg), + Some(_) => term.first_arg(), None => None, }; - let key_opt = indexing_arg_opt.and_then(|indexing_term_loc| { - term_predicate_key(&self.machine_st.heap, indexing_term_loc) - }); - - let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); - - if let Some((name, arity)) = key_opt { - loader - .wam_prelude - .indices - .goal_expansion_indices - .insert((name, arity)); + if let Some(indexing_term) = indexing_arg { + if let Some(indexing_name) = indexing_term.name() { + loader + .wam_prelude + .indices + .goal_expansion_indices + .insert((indexing_name, indexing_term.arity())); + } } loader.incremental_compile_clause( @@ -1964,21 +1965,29 @@ impl Machine { }; let stub_gen = || functor_stub(key.0, key.1); - let assert_clause = self.machine_st.registers[2]; - let key_opt = clause_predicate_key_from_heap(&self.machine_st.heap, assert_clause); + let head = self.deref_register(2); - let mut compile_assert = |assert_clause, key_opt| { + 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 loader: Loader<'_, LiveLoadAndMachineState<'_>> = Loader::new(self, LiveTermStream::new(ListingSource::User)); loader.payload.compilation_target = compilation_target; - let (name, arity) = if let Some(key) = key_opt { - key + let head = + LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head); + + let name = if let Some(name) = head.name() { + name } else { return Err(SessionError::from(CompilationError::InvalidRuleHead)); }; + let arity = head.arity(); let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity)); let is_dynamic_predicate = loader @@ -2010,39 +2019,39 @@ impl Machine { return LiveLoadAndMachineState::evacuate(loader); } + 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 machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload); - // let asserted_clause = loader.copy_term_from_heap(assert_clause); - - let term = TermWriteResult::from(&mut machine_st.heap, assert_clause) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - loader.incremental_compile_clause( (name, arity), - term, + asserted_clause, compilation_target, false, append_or_prepend, )?; - let clause_clause_term = loader.clause_clause(assert_clause)?; - // the global clock is incremented after each assertion. LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; loader.compile_clause_clauses( (name, arity), compilation_target, - vec![clause_clause_term], + std::iter::once((head, body)), append_or_prepend, )?; LiveLoadAndMachineState::evacuate(loader) }; - match compile_assert(assert_clause, key_opt) { + match compile_assert() { Ok(_) => Ok(()), Err(SessionError::CompilationError( CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact, @@ -2244,23 +2253,11 @@ impl Machine { }; let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); - let predicate_focus_opt = loader - .payload - .predicates - .first() - .map(|term_write_result| term_write_result.focus); - - let is_consistent = if let Some(predicate_focus) = predicate_focus_opt { - let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload); - clause_predicate_key(&machine_st.heap, predicate_focus) == Some(key) - } else { - true - }; LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = (!loader.payload.predicates.is_empty() && loader.payload.predicates.compilation_target != compilation_target) - || !is_consistent; + || !key.is_consistent(&loader.payload.predicates); let result = LiveLoadAndMachineState::evacuate(loader); self.restore_load_state_payload(result) @@ -2467,17 +2464,11 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> { self.payload.predicates.compilation_target = compilation_target; } - let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); - let value = machine_st.store(MachineState::deref(machine_st, machine_st[term_reg])); - - self.add_clause_clause_if_dynamic(value)?; - - let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); - - let term = TermWriteResult::from(&mut machine_st.heap, value) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + let term = self.read_term_from_heap(term_reg); + self.add_clause_clause_if_dynamic(&term)?; self.payload.term_stream.term_queue.push_back(term); + self.load() } } diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 1a4e8487..4551991e 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -19,7 +19,7 @@ pub type MachineStubGen = Box MachineStub>; #[derive(Debug)] pub(crate) struct MachineError { stub: MachineStub, - location: Option, + location: Option<(usize, usize)>, // line_num, col_num } // from 7.12.2 b) of 13211-1:1995 @@ -301,7 +301,7 @@ impl MachineState { } } - pub(super) fn resource_error(&mut self, err: ResourceError) -> MachineError { + pub(super) fn resource_error(err: ResourceError) -> MachineError { let stub = match err { ResourceError::FiniteMemory(size_requested) => { functor!( @@ -466,10 +466,10 @@ impl MachineState { fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError { match err { ArithmeticError::NonEvaluableFunctor(cell, arity) => { - let culprit = functor!(atom!("/"), [cell(cell), fixnum(arity)]); - + let culprit = functor!(atom!("/"), [literal(cell), fixnum(arity)]); self.type_error(ValidType::Evaluable, culprit) } + ArithmeticError::UninstantiatedVar => self.instantiation_error(), } } @@ -609,7 +609,7 @@ impl MachineState { } pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub { - if let Some(ParserErrorSrc { line_num, .. }) = err.location { + if let Some((line_num, _col_num)) = err.location { functor!( atom!("error"), [ @@ -665,16 +665,17 @@ pub enum CompilationError { InvalidRuleHead, InvalidUseModuleDecl, InvalidModuleResolution(Atom), + FiniteMemoryInHeap(usize), } #[derive(Debug)] pub enum DirectiveError { - ExpectedDirective(HeapCellValue), + ExpectedDirective(Term), InvalidDirective(Atom, usize /* arity */), - InvalidOpDeclNameType(HeapCellValue), - InvalidOpDeclSpecDomain(HeapCellValue), + InvalidOpDeclNameType(Term), + InvalidOpDeclSpecDomain(Term), InvalidOpDeclSpecValue(Atom), - InvalidOpDeclPrecType(HeapCellValue), + InvalidOpDeclPrecType(Term), InvalidOpDeclPrecDomain(Fixnum), ShallNotCreate(Atom), ShallNotModify(Atom), @@ -695,9 +696,9 @@ impl From for CompilationError { } impl CompilationError { - pub(crate) fn line_and_col_num(&self) -> Option { + pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> { match self { - CompilationError::ParserError(err) => Some(err.err_src()), + CompilationError::ParserError(err) => err.line_and_col_num(), _ => None, } } @@ -740,6 +741,9 @@ impl CompilationError { CompilationError::ParserError(ref err) => { functor!(err.as_atom()) } + CompilationError::FiniteMemoryInHeap(h) => { + vec![FunctorElement::AbsoluteCell(str_loc_as_cell!(*h))] + } } } } @@ -1015,6 +1019,13 @@ pub enum SessionError { PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey), } +impl From 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 e0142b77..d4a10a8c 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -21,8 +21,6 @@ use std::collections::BTreeSet; use std::ops::{Deref, DerefMut}; use crate::types::*; -// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -// pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity); // 7.2 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -223,6 +221,30 @@ impl CodeIndex { */ } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum VarKey { + AnonVar(usize), + VarPtr(VarPtr), +} + +impl VarKey { + #[allow(clippy::inherent_to_string)] + #[inline] + pub(crate) fn to_string(&self) -> String { + match self { + VarKey::AnonVar(h) => format!("_{}", h), + VarKey::VarPtr(var) => var.borrow().to_string(), + } + } + + #[inline(always)] + pub(crate) fn is_anon(&self) -> bool { + matches!(self, VarKey::AnonVar(_)) + } +} + +pub(crate) type HeapVarDict = IndexMap; + pub(crate) type GlobalVarDir = IndexMap), FxBuildHasher>; pub(crate) type StreamAliasDir = IndexMap; @@ -279,9 +301,11 @@ impl IndexStore { _ => self .get_meta_predicate_spec(key.0, key.1, &compilation_target) .map(|meta_specs| { - meta_specs.iter().find(|meta_spec| match meta_spec { - MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) => true, - _ => false, + meta_specs.iter().find(|meta_spec| { + matches!( + meta_spec, + MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) + ) }) }) .map(|meta_spec_opt| meta_spec_opt.is_some()) diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 8c50c128..049f131c 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -13,6 +13,7 @@ use crate::machine::stack::*; use crate::machine::streams::*; use crate::machine::Machine; use crate::parser::ast::*; +use crate::read::TermWriteResult; use crate::types::*; use crate::parser::dashu::Integer; @@ -22,7 +23,6 @@ use indexmap::IndexMap; use std::convert::TryFrom; use std::fmt; use std::ops::{Index, IndexMut, Range}; -use std::rc::Rc; use std::sync::Arc; pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1]; @@ -72,7 +72,7 @@ pub struct MachineState { pub(super) e: usize, pub(super) num_of_args: usize, pub(super) cp: usize, - pub(crate) attr_var_init: AttrVarInitializer, + pub(super) attr_var_init: AttrVarInitializer, pub(super) fail: bool, pub heap: Heap, pub(super) mode: MachineMode, @@ -203,52 +203,56 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn } */ -fn push_var_eq_functors( +// size may be an upper bound. +// true_size is calculated to compute the exact offset. + +fn push_var_eq_functors<'a>( heap: &mut Heap, size: usize, - iter: impl Iterator, + iter: impl Iterator, atom_tbl: &AtomTable, ) -> Result { let src_h = heap.cell_len(); - if size > 0 { - let mut writer = heap.reserve(1 + 5 * size)?; + let true_size = if size > 0 { + let mut writer = heap.reserve(2 + 5 * size)?; - writer.write_with(|section| { - for (var_loc, var) in iter { - // (var, binding) in iter { - let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); - let binding = heap_loc_as_cell!(var_loc); + writer + .write_with(|section| { + let mut size = 0; - section.push_cell(atom_as_cell!(atom!("="), 2)); - section.push_cell(atom_as_cell!(var_atom)); - section.push_cell(binding); - } + for (var, binding) in iter { + let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); - for idx in 0..size { - section.push_cell(list_loc_as_cell!(section.cell_len() + 1)); - section.push_cell(str_loc_as_cell!(src_h + 3 * idx)); - } + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(var_atom)); + section.push_cell(*binding); - section.push_cell(empty_list_as_cell!()); - }); + size += 1; + } - Ok(heap_loc_as_cell!(src_h + 3 * size)) + for idx in 0..size { + section.push_cell(list_loc_as_cell!(section.cell_len() + 1)); + section.push_cell(str_loc_as_cell!(src_h + 3 * idx)); + } + + if size > 0 { + section.push_cell(empty_list_as_cell!()); + } + + size + }) + .result } else { - Ok(empty_list_as_cell!()) - } -} + size + }; -/* -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) + Ok(if true_size > 0 { + heap_loc_as_cell!(src_h + 3 * true_size) + } else { + empty_list_as_cell!() + }) } -*/ #[derive(Debug)] pub struct Ball { @@ -377,7 +381,7 @@ impl<'a> CopierTarget for CopyTerm<'a> { } #[derive(Debug)] -pub(crate) struct CopyBallTerm<'a> { +pub(super) struct CopyBallTerm<'a> { attr_var_queue: &'a mut Vec, stack: &'a mut Stack, heap: &'a mut Heap, @@ -385,7 +389,7 @@ pub(crate) struct CopyBallTerm<'a> { } impl<'a> CopyBallTerm<'a> { - pub(crate) fn new( + pub(super) fn new( attr_var_queue: &'a mut Vec, stack: &'a mut Stack, heap: &'a mut Heap, @@ -629,24 +633,13 @@ impl MachineState { pub fn write_read_term_options( &mut self, - mut var_list: Vec<(Var, HeapCellValue, usize)>, - singletons_heap_list: HeapCellValue, + mut var_list: Vec<(VarKey, HeapCellValue, usize)>, + singleton_heap_list: HeapCellValue, ) -> CallResult { var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2)); - /* - let list_of_var_eqs = push_var_eq_functors( - &mut self.heap, - var_list.iter().map(|(var_name, var, _)| { - (var.get_value() as usize, var_name.clone()) - }), - num_vars, - &self.atom_tbl, - ); - */ - let singleton_addr = self.registers[3]; - unify_fn!(*self, singletons_heap_list, singleton_addr); + unify_fn!(*self, singleton_heap_list, singleton_addr); if self.fail { return Ok(()); @@ -669,21 +662,18 @@ impl MachineState { } let var_names_addr = self.registers[5]; - /* - let var_names_offset = heap_loc_as_cell!(iter_to_heap_list( - &mut self.heap, - list_of_var_eqs.into_iter() - )); - */ - let var_names_offset = resource_error_call_result!( self, push_var_eq_functors( &mut self.heap, var_list.len(), - var_list - .iter() - .map(|(var_name, var, _)| { (var.get_value() as usize, var_name.clone()) }), + var_list.iter().filter_map(|(var_name, var, _)| { + if var_name.is_anon() { + None + } else { + Some((var_name, var)) + } + }), &self.atom_tbl, ) ); @@ -691,37 +681,22 @@ impl MachineState { Ok(unify_fn!(*self, var_names_offset, var_names_addr)) } - pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult { - let heap_loc = self.heap[term.focus]; - - /* - read_heap_cell!(self.heap[term.heap_loc], - (HeapCellValueTag::PStr) => { // | HeapCellValueTag::PStrOffset) => { - pstr_loc_as_cell!(term.heap_loc) - } - _ => { - heap_loc_as_cell!(term.heap_loc) - } - ); - */ - + pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult { + let heap_loc = heap_loc_as_cell!(term_write_result.heap_loc); unify_fn!(*self, heap_loc, self.registers[2]); if self.fail { return Ok(()); } - /* for var in term_write_result.var_dict.values_mut() { *var = heap_bound_deref(&self.heap, *var); } - */ let mut singleton_var_set: IndexMap = IndexMap::new(); + self.heap[0] = heap_loc; - for cell in - stackful_preorder_iter::(&mut self.heap, &mut self.stack, term.focus) - { + for cell in stackful_preorder_iter::(&mut self.heap, &mut self.stack, 0) { let cell = unmark_cell_bits!(cell); if let Some(var) = cell.as_var() { @@ -737,38 +712,36 @@ impl MachineState { self, push_var_eq_functors( &mut self.heap, - singleton_var_set + term_write_result.var_dict.len(), + term_write_result + .var_dict .iter() - .filter(|(var, is_singleton)| { - **is_singleton - && term - .inverse_var_locs - .contains_key(&(var.get_value() as usize)) - }) - .count(), - term.inverse_var_locs - .iter() - .filter_map(|(var_loc, var_name)| { - let r = Ref::heap_cell(*var_loc); + .filter(|(var_name, binding)| { + if var_name.is_anon() { + return false; + } - if singleton_var_set.get(&r).cloned().unwrap_or(false) { - Some((*var_loc, var_name.clone())) + if let Some(r) = binding.as_var() { + *singleton_var_set.get(&r).unwrap_or(&false) } else { - None + false } }), &self.atom_tbl, ) ); + for var in term_write_result.var_dict.values_mut() { + *var = heap_bound_deref(&self.heap, *var); + } + let mut var_list = Vec::with_capacity(singleton_var_set.len()); - for (var_loc, var_name) in term.inverse_var_locs { - 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_name, cell, idx)); + for (var_name, addr) in term_write_result.var_dict { + if let Some(var) = addr.as_var() { + if let Some(idx) = singleton_var_set.get_index_of(&var) { + var_list.push((var_name, addr, idx)); + } } } @@ -851,8 +824,8 @@ impl MachineState { } loop { - match self.read_to_heap(stream, &indices.op_dir) { - Ok(term) => return self.read_term_body(term), + match self.read(stream, &indices.op_dir) { + Ok(term_write_result) => return self.read_term_body(term_write_result), Err(err) => { match &err { CompilationError::ParserError(e) if e.is_unexpected_eof() => { @@ -891,7 +864,7 @@ impl MachineState { let printer = match self.try_from_list(self.registers[6], stub_gen) { Ok(addrs) => { - let mut var_names: IndexMap = IndexMap::new(); + let mut var_names: IndexMap = IndexMap::new(); for addr in addrs { read_heap_cell!(addr, @@ -910,14 +883,14 @@ impl MachineState { read_heap_cell!(atom, (HeapCellValueTag::Atom, (name, _arity)) => { debug_assert_eq!(_arity, 0); - var_names.insert(var, Rc::new(name.as_str().to_owned())); + var_names.insert(var, VarPtr::from(name.as_str().to_owned())); } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.heap[s]) .get_name_and_arity(); debug_assert_eq!(arity, 0); - var_names.insert(var, Rc::new(name.as_str().to_owned())); + var_names.insert(var, VarPtr::from(name.as_str().to_owned())); } _ => { unreachable!(); @@ -996,18 +969,14 @@ impl MachineState { } ); - let term_loc = self.heap.cell_len(); - - step_or_resource_error!(self, self.heap.push_cell(term_to_be_printed), { - return Ok(None); - }); + self.heap[0] = term_to_be_printed; let mut printer = HCPrinter::new( &mut self.heap, &mut self.stack, op_dir, PrinterOutputter::new(), - term_loc, + 0, ); printer.ignore_ops = ignore_ops; @@ -1040,7 +1009,6 @@ impl MachineState { } printer.var_names = var_names; - printer } Err(err) => { diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index ef1d32dc..bd041f36 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -621,10 +621,17 @@ impl MachineState { (HeapCellValueTag::PStrLoc, l1) => { read_heap_cell!(v2, (HeapCellValueTag::PStrLoc, l2) => { - let cmp_result = self.heap.compare_pstr_segments(l1, l2); - - if let Some(ordering) = cmp_result.continue_pstr_compare(&mut self.pdl) { - return Some(ordering); + match self.heap.compare_pstr_segments(l1, l2) { + PStrSegmentCmpResult::Continue(v1, v2) => { + self.pdl.push(v1); + self.pdl.push(v2); + } + PStrSegmentCmpResult::Less => { + return Some(Ordering::Less); + } + PStrSegmentCmpResult::Greater => { + return Some(Ordering::Greater); + } } } (HeapCellValueTag::Lis, l2) => { @@ -747,38 +754,6 @@ impl MachineState { Some(Ordering::Equal) } - /* TODO: new, inlined match_partial_string. now inlined into GetPartialString, - * the only place it is called from. Therefore, it has been inlined. - - pub fn match_partial_string( - &mut self, - value: HeapCellValue, - string: &str, - ) -> Result<(), usize> { - debug_assert!(value.is_ref()); - - self.heap[0] = value; - let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, 0); - - match heap_pstr_iter.compare_pstr_to_string(string) { - Some(PStrCmpResult::CompleteMatch { bytes_matched, pstr_loc }) => { - self.s_offset = bytes_matched; - self.s = HeapPtr::PStr(pstr_loc); - self.mode = MachineMode::Read; - } - Some(PStrCmpResult::PartialMatch { string, var_loc }) => { - let cell = self.heap.allocate_pstr(string)?; - unify!(self, cell, heap_loc_as_loc!(var_loc)); - } - None => { - self.fail = true; - } - } - - Ok(()) - } - */ - pub(crate) fn setup_call_n_init_goal_info( &mut self, goal: HeapCellValue, diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 32c4cf59..a372e0af 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -7,6 +7,7 @@ pub use crate::parser::ast::*; #[cfg(test)] use crate::machine::copier::CopierTarget; +use crate::read::TermWriteResult; #[cfg(test)] use std::ops::{Deref, DerefMut, Index, IndexMut, Range}; @@ -34,7 +35,7 @@ impl MockWAM { &mut self, input_stream: Stream, ) -> Result { - self.machine_st.read_to_heap(input_stream, &self.op_dir) + self.machine_st.read(input_stream, &self.op_dir) } pub fn parse_and_write_parsed_term_to_heap( @@ -50,24 +51,24 @@ impl MockWAM { term_string: &'static str, ) -> Result { let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?; - - print_heap_terms(&self.machine_st.heap, term_write_result.focus); - - let var_names = term_write_result - .inverse_var_locs - .iter() - .map(|(var_loc, var_name)| (self.machine_st.heap[*var_loc], var_name.clone())) - .collect(); + print_heap_terms(&self.machine_st.heap, term_write_result.heap_loc); let mut printer = HCPrinter::new( &mut self.machine_st.heap, &mut self.machine_st.stack, &self.op_dir, PrinterOutputter::new(), - term_write_result.focus, + term_write_result.heap_loc, ); - printer.var_names = var_names; + printer.var_names = term_write_result + .var_dict + .into_iter() + .map(|(var, cell)| match var { + VarKey::VarPtr(var) => (cell, var.clone()), + VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string())), + }) + .collect(); Ok(printer.print().result()) } @@ -238,7 +239,7 @@ pub(crate) fn write_parsed_term_to_heap( input_stream: Stream, op_dir: &OpDir, ) -> Result { - machine_st.read_to_heap(input_stream, op_dir) + machine_st.read(input_stream, op_dir) } #[cfg(test)] @@ -298,7 +299,7 @@ mod tests { unify!( wam, str_loc_as_cell!(0), - str_loc_as_cell!(term_write_result_2.focus) + str_loc_as_cell!(term_write_result_2.heap_loc) ); assert!(wam.fail); @@ -310,16 +311,15 @@ mod tests { wam.heap.clear(); { - let term_write_result_1 = - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap(); unify!( wam, - heap_loc_as_cell!(term_write_result_1.focus), - heap_loc_as_cell!(term_write_result_2.focus) + str_loc_as_cell!(1), + heap_loc_as_cell!(term_write_result_2.heap_loc) ); assert!(!wam.fail); @@ -331,16 +331,15 @@ mod tests { wam.heap.clear(); { - let term_write_result_1 = - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap(); unify!( wam, - heap_loc_as_cell!(term_write_result_1.focus), - heap_loc_as_cell!(term_write_result_2.focus) + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) ); assert!(!wam.fail); @@ -352,16 +351,15 @@ mod tests { wam.heap.clear(); { - let term_write_result_1 = - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap(); unify!( wam, - heap_loc_as_cell!(term_write_result_1.focus), - heap_loc_as_cell!(term_write_result_2.focus) + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) ); assert!(!wam.fail); @@ -373,16 +371,15 @@ mod tests { wam.heap.clear(); { - let term_write_result_1 = - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap(); unify!( wam, - heap_loc_as_cell!(term_write_result_1.focus), - heap_loc_as_cell!(term_write_result_2.focus) + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) ); assert!(!wam.fail); @@ -394,8 +391,7 @@ mod tests { wam.heap.clear(); { - let term_write_result_1 = - parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); @@ -404,8 +400,8 @@ mod tests { unify!( wam, - heap_loc_as_cell!(term_write_result_1.focus), - heap_loc_as_cell!(term_write_result_2.focus) + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) ); assert!(!wam.fail); @@ -526,8 +522,21 @@ mod tests { }); unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); + assert!(!wam.fail); all_cells_unmarked(&wam.heap); + wam.heap.clear(); + + { + let term_write_result_1 = + parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap(); + + print_heap_terms(&wam.heap, term_write_result_1.heap_loc); + + unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4)); + + assert_eq!(wam.heap[2], str_loc_as_cell!(4)); + } } #[test] @@ -550,8 +559,8 @@ mod tests { unify_with_occurs_check!( wam, - heap_loc_as_cell!(0), - heap_loc_as_cell!(term_write_result_2.focus) + str_loc_as_cell!(0), + str_loc_as_cell!(term_write_result_2.heap_loc) ); assert!(wam.fail); @@ -594,7 +603,7 @@ mod tests { Some(Ordering::Equal) ); - let cstr_cell = wam.allocate_cstr("string").unwrap(); + let cstr_cell = wam.heap.allocate_cstr("string").unwrap(); assert_eq!( compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell), @@ -693,7 +702,7 @@ mod tests { Some(Ordering::Greater) ); - let cstr_cell = wam.allocate_cstr("string").unwrap(); + let cstr_cell = wam.heap.allocate_cstr("string").unwrap(); assert_eq!( compare_term_test!(wam, empty_list_as_cell!(), cstr_cell), @@ -782,7 +791,7 @@ mod tests { wam.heap.clear(); let h = wam.heap.cell_len(); - wam.allocate_cstr("a string").unwrap(); + wam.heap.allocate_cstr("a string").unwrap(); assert!(!wam.is_cyclic_term(h)); } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 02471f25..98b70ca6 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1114,7 +1114,6 @@ impl Machine { if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { self.try_execute(name, arity, idx.get()) } else { - println!("aaand undefined!"); self.undefined_procedure(name, arity) } } else if let Some(module) = self.indices.modules.get(&module_name) { diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 9484bf40..43163ce2 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -363,7 +363,7 @@ mod test { fn pstr_iter_tests() { let mut wam = MockWAM::new(); - let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap(); + let pstr_cell = wam.machine_st.heap.allocate_pstr("abc ").unwrap(); wam.machine_st .heap .push_cell(empty_list_as_cell!()) @@ -391,7 +391,7 @@ mod test { wam.machine_st.heap[2] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.allocate_pstr("def").unwrap(); + wam.machine_st.heap.allocate_pstr("def").unwrap(); let h = wam.machine_st.heap.cell_len(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(h)).unwrap(); @@ -456,7 +456,7 @@ mod test { wam.machine_st.heap.clear(); - let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap(); + let pstr_cell = wam.machine_st.heap.allocate_cstr("abc").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -484,7 +484,7 @@ mod test { wam.machine_st.heap.clear(); - let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap(); + let pstr_cell = wam.machine_st.heap.allocate_cstr("abc").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -515,7 +515,7 @@ mod test { wam.machine_st.heap.clear(); - let pstr_cell = wam.machine_st.allocate_cstr("d").unwrap(); + let pstr_cell = wam.machine_st.heap.allocate_cstr("d").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -534,7 +534,7 @@ mod test { wam.machine_st.heap.clear(); - let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap(); + let pstr_cell = wam.machine_st.heap.allocate_cstr("abc").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -564,7 +564,7 @@ mod test { wam.machine_st.heap.clear(); - let pstr_cell = wam.machine_st.allocate_cstr("abcdef").unwrap(); + let pstr_cell = wam.machine_st.heap.allocate_cstr("abcdef").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -602,7 +602,7 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.allocate_cstr("abc").unwrap(); + wam.machine_st.heap.allocate_cstr("abc").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -629,7 +629,7 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.allocate_cstr("a ").unwrap(); + wam.machine_st.heap.allocate_cstr("a ").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -653,7 +653,7 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.allocate_cstr(" a").unwrap(); + wam.machine_st.heap.allocate_cstr(" a").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -678,7 +678,7 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.allocate_cstr("a b").unwrap(); + wam.machine_st.heap.allocate_cstr("a b").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -706,7 +706,7 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.allocate_cstr(" a ").unwrap(); + wam.machine_st.heap.allocate_cstr(" a ").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -733,7 +733,7 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.allocate_cstr(" a bc").unwrap(); + wam.machine_st.heap.allocate_cstr(" a bc").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -764,7 +764,7 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.allocate_cstr("abc").unwrap(); + wam.machine_st.heap.allocate_cstr("abc").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); @@ -791,7 +791,7 @@ mod test { // #2293, test7. wam.machine_st.heap.clear(); - wam.machine_st.allocate_cstr("abcde").unwrap(); + wam.machine_st.heap.allocate_cstr("abcde").unwrap(); let start = wam.machine_st.heap.cell_len(); let mut writer = wam.machine_st.heap.reserve(16).unwrap(); diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index ff64494a..9ee332ed 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -3,17 +3,13 @@ use crate::codegen::CodeGenSettings; use crate::forms::*; use crate::instructions::*; use crate::machine::disjuncts::*; -use crate::machine::heap::*; use crate::machine::loader::*; use crate::machine::machine_errors::*; -use crate::machine::CodeIndex; use crate::parser::ast::*; -use crate::types::*; -use fxhash::FxBuildHasher; -use indexmap::IndexMap; use indexmap::IndexSet; +use std::cell::Cell; use std::convert::TryFrom; pub(crate) fn to_op_decl(prec: u16, spec: OpDeclSpec, name: Atom) -> OpDecl { OpDecl::new(OpDesc::build_with(prec, spec), name) @@ -25,47 +21,43 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result Result { - let (focus, _cell) = subterm_index(term.heap, term.focus); - - let name = match term_predicate_key(term.heap, focus + 3) { - Some((name, 0)) => name, - _ => { +fn setup_op_decl(mut terms: Vec) -> Result { + // should allow non-partial lists? + let name = match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => name, + other => { return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclNameType(term.heap[focus + 3]), + DirectiveError::InvalidOpDeclNameType(other), )); } }; - let spec = match term_predicate_key(term.heap, focus + 2) { - Some((name, _)) => name, - None => { + let spec = match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => name, + other => { return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus + 2]), - )); + DirectiveError::InvalidOpDeclSpecDomain(other), + )) } }; let spec = to_op_decl_spec(spec)?; - let prec = term.deref_loc(focus + 1); - let prec = read_heap_cell!(prec, - (HeapCellValueTag::Fixnum, n) => { - match u16::try_from(n.get_num()) { - Ok(n) if n <= 1200 => n, - _ => { - return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclPrecDomain(n), - )); - } + let prec = match terms.pop().unwrap() { + Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) { + Ok(n) if n <= 1200 => n, + _ => { + return Err(CompilationError::InvalidDirective( + DirectiveError::InvalidOpDeclPrecDomain(bi), + )); } - } - _ => { + }, + other => { return Err(CompilationError::InvalidDirective( - DirectiveError::InvalidOpDeclPrecType(prec), + DirectiveError::InvalidOpDeclPrecType(other), )); } - ); + }; if name == "[]" || name == "{}" { return Err(CompilationError::InvalidDirective( @@ -88,162 +80,129 @@ fn setup_op_decl(term: &FocusedHeapRefMut) -> Result { Ok(to_op_decl(prec, spec, name)) } -fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result { - let key_opt = term_predicate_key(term.heap, term.focus); +fn setup_predicate_indicator(term: &mut Term) -> 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(); - if let Some((atom!("/") | atom!("//"), 2)) = key_opt { - let arity_loc = term.nth_arg(term.focus, 2).unwrap(); - - let arity = match Number::try_from(term.deref_loc(arity_loc)) { - Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), - Ok(Number::Integer(n)) => (&*n).try_into().ok(), - _ => None, - } - .ok_or(CompilationError::InvalidModuleExport)?; - - let name_loc = term.nth_arg(term.focus, 1).unwrap(); - let name = term_predicate_key(term.heap, name_loc) - .map(|(name, _)| name) + 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)?; - if matches!(key_opt, Some((atom!("/"), _))) { - Ok((name, arity)) - } else { - Ok((name, arity + 2)) + let name = match name { + Term::Literal(_, Literal::Atom(name)) => Some(name), + _ => None, + } + .ok_or(CompilationError::InvalidModuleExport)?; + + if *slash == atom!("/") { + Ok((name, arity)) + } else { + Ok((name, arity + 2)) + } } - } else { - Err(CompilationError::InvalidModuleExport) + _ => Err(CompilationError::InvalidModuleExport), } } -fn setup_module_export(term: &FocusedHeapRefMut) -> Result { - setup_predicate_indicator(term) +fn setup_module_export(mut term: Term) -> Result { + setup_predicate_indicator(&mut term) .map(ModuleExport::PredicateKey) .or_else(|_| { - let key_opt = term_predicate_key(term.heap, term.focus); - - if let Some((atom!("op"), 3)) = key_opt { - Ok(ModuleExport::OpDecl(setup_op_decl(term)?)) + if let Term::Clause(_, name, terms) = term { + if terms.len() == 3 && name == atom!("op") { + Ok(ModuleExport::OpDecl(setup_op_decl(terms)?)) + } else { + Err(CompilationError::InvalidModuleDecl) + } } else { Err(CompilationError::InvalidModuleDecl) } }) } -/* TODO: should be unnecessary now. - pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term { let head_term = Term::Clause(Cell::default(), atom!(""), vars.to_vec()); let rule = vec![head_term, body_term]; Term::Clause(Cell::default(), atom!(":-"), rule) } -*/ pub(super) fn setup_module_export_list( - term: FocusedHeapRefMut, + mut export_list: Term, ) -> Result, CompilationError> { let mut exports = vec![]; - let mut focus = term.focus; - loop { - read_heap_cell!(term.heap[focus], - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h == focus { - break; - } else { - focus = h; - } - } - (HeapCellValueTag::Lis, l) => { - let term = FocusedHeapRefMut { - heap: term.heap, - focus: l, - }; + while let Term::Cons(_, t1, t2) = export_list { + let module_export = setup_module_export(*t1)?; - exports.push(setup_module_export(&term)?); - focus = l + 1; - } - (HeapCellValueTag::Atom, (name, _arity)) => { - if name == atom!("[]") { - return Ok(exports); - } else { - break; - } - } - _ => { - break; - } - ); + exports.push(module_export); + export_list = *t2; } - Err(CompilationError::InvalidModuleDecl) + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { + Ok(exports) + } else { + Err(CompilationError::InvalidModuleDecl) + } } -fn setup_module_decl(mut term: FocusedHeapRefMut) -> Result { - let name = term_predicate_key(term.heap, term.focus + 1) - .map(|(name, _)| name) - .ok_or(CompilationError::InvalidModuleDecl)?; +fn setup_module_decl(mut terms: Vec) -> Result { + let export_list = terms.pop().unwrap(); + let name = terms.pop().unwrap(); - term.focus = term.focus + 2; - let exports = setup_module_export_list(term)?; + let name = match name { + Term::Literal(_, Literal::Atom(name)) => Some(name), + _ => None, + } + .ok_or(CompilationError::InvalidModuleDecl)?; + let exports = setup_module_export_list(export_list)?; Ok(ModuleDecl { name, exports }) } -fn setup_use_module_decl(term: &FocusedHeapRefMut) -> Result { - read_heap_cell!(term.deref_loc(term.focus+1), - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity(); - - if (name, arity) == (atom!("library"), 1) { - read_heap_cell!(term.deref_loc(s+1), - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - return Ok(ModuleSource::Library(name)); - } - } - _ => { - } - ) - } - - return Err(CompilationError::InvalidModuleDecl); - } - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - Ok(ModuleSource::File(name)) - } else { - Err(CompilationError::InvalidUseModuleDecl) +fn setup_use_module_decl(mut terms: Vec) -> 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), } } - _ => { - Err(CompilationError::InvalidUseModuleDecl) - } - ) + Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)), + _ => Err(CompilationError::InvalidUseModuleDecl), + } } type UseModuleExport = (ModuleSource, IndexSet); -fn setup_qualified_import(term: FocusedHeapRefMut) -> Result { - let module_src = setup_use_module_decl(&term)?; +fn setup_qualified_import(mut terms: Vec) -> 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), + }?; + let mut exports = IndexSet::new(); - let mut focus = term.focus + 2; - - while let HeapCellValueTag::Lis = term.heap[focus].get_tag() { - focus = term.heap[focus].get_value() as usize; - - let term = FocusedHeapRefMut { - heap: term.heap, - focus, - }; - - exports.insert(setup_module_export(&term)?); - focus = focus + 1; + while let Term::Cons(_, t1, t2) = export_list { + exports.insert(setup_module_export(*t1)?); + export_list = *t2; } - if term.heap[focus] == empty_list_as_cell!() { + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { Ok((module_src, exports)) } else { Err(CompilationError::InvalidModuleDecl) @@ -290,20 +249,18 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result>( - term: TermWriteResult, + mut terms: Vec, loader: &mut Loader<'a, LS>, ) -> Result<(Atom, Atom, Vec), CompilationError> { - fn get_meta_specs( - term: FocusedHeapRefMut, - arity: usize, - ) -> Result, CompilationError> { + fn get_name_and_meta_specs( + name: Atom, + terms: &mut [Term], + ) -> Result<(Atom, Vec), CompilationError> { let mut meta_specs = vec![]; - for meta_spec_loc in term.focus + 1..term.focus + arity + 1 { - read_heap_cell!(term.deref_loc(meta_spec_loc), - (HeapCellValueTag::Atom, (meta_spec, arity)) => { - debug_assert_eq!(arity, 0); - + for meta_spec in terms.iter_mut() { + match meta_spec { + Term::Literal(_, Literal::Atom(meta_spec)) => { let meta_spec = match meta_spec { atom!("+") => MetaSpec::Plus, atom!("-") => MetaSpec::Minus, @@ -314,322 +271,263 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>( meta_specs.push(meta_spec); } - (HeapCellValueTag::Fixnum, n) => { - match usize::try_from(n.get_num()) { - Ok(n) if n <= MAX_ARITY => { - meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n)); - } - _ => { - return Err(CompilationError::InvalidMetaPredicateDecl); - } + Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) { + Ok(n) if n <= MAX_ARITY => { + meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n)); } - } + _ => { + return Err(CompilationError::InvalidMetaPredicateDecl); + } + }, _ => { return Err(CompilationError::InvalidMetaPredicateDecl); } - ); + } } - Ok(meta_specs) + Ok((name, meta_specs)) } - let heap = loader.machine_heap(); - let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[term.focus + 1])); + 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(); - read_heap_cell!(cell, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); - - match (name, arity) { - (atom!(":"), 2) => { - let module_name = heap[s+1]; - let spec = heap[s+2]; - - read_heap_cell!(module_name, - (HeapCellValueTag::Atom, (module_name, arity)) => { - if arity == 0 { - read_heap_cell!(spec, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(heap[s]) - .get_name_and_arity(); - - let term = FocusedHeapRefMut { heap, focus: s }; - return Ok((module_name, name, get_meta_specs(term, arity)?)); - } - _ => { - } - ); - } else { - return Err(CompilationError::InvalidMetaPredicateDecl); - } - } - _ => { - } - ); - } - _ => { - let term = FocusedHeapRefMut { heap, focus: s }; - let specs = get_meta_specs(term, arity)?; - let module_name = loader.payload.compilation_target.module_name(); - - return Ok((module_name, name, specs)); - } + match module_name { + Term::Literal(_, Literal::Atom(module_name)) => match spec { + Term::Clause(_, name, mut terms) => { + let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; + Ok((module_name, name, meta_specs)) + } + _ => Err(CompilationError::InvalidMetaPredicateDecl), + }, + _ => Err(CompilationError::InvalidMetaPredicateDecl), } - - Err(CompilationError::InvalidMetaPredicateDecl) } - _ => { - Err(CompilationError::InvalidMetaPredicateDecl) + Term::Clause(_, name, mut terms) => { + let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; + Ok(( + loader.payload.compilation_target.module_name(), + name, + meta_specs, + )) } - ) + _ => Err(CompilationError::InvalidMetaPredicateDecl), + } } pub(super) fn setup_declaration<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, - mut term: TermWriteResult, + mut terms: Vec, ) -> Result { - let mut focus = term.focus; - let machine_st = LS::machine_st(&mut loader.payload); + let term = terms.pop().unwrap(); - loop { - let decl = machine_st.heap[focus]; - - read_heap_cell!(decl, - (HeapCellValueTag::Atom, (name, arity)) => { - let mut focused = FocusedHeapRefMut::from(&mut machine_st.heap, focus); - - return match (name, arity) { - (atom!("dynamic"), 1) => { - let (name, arity) = setup_predicate_indicator(&focused)?; - Ok(Declaration::Dynamic(name, arity)) - } - (atom!("module"), 2) => { - Ok(Declaration::Module(setup_module_decl(focused)?)) - } - (atom!("op"), 3) => { - Ok(Declaration::Op(setup_op_decl(&focused)?)) - } - (atom!("non_counted_backtracking"), 1) => { - focused.focus = focused.nth_arg(focused.focus, 1).unwrap(); - let (name, arity) = setup_predicate_indicator(&focused)?; - Ok(Declaration::NonCountedBacktracking(name, arity)) - } - (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&focused)?)), - (atom!("use_module"), 2) => { - let (name, exports) = setup_qualified_import(focused)?; - Ok(Declaration::UseQualifiedModule(name, exports)) - } - (atom!("meta_predicate"), 1) => { - term.focus = focus; - let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?; - Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) - } - _ => Err(CompilationError::InvalidDirective( - DirectiveError::InvalidDirective(name, arity) - )) - }; + match term { + Term::Clause(_, name, mut terms) => match (name, terms.len()) { + (atom!("dynamic"), 1) => { + let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; + Ok(Declaration::Dynamic(name, arity)) } - (HeapCellValueTag::Str, s) => { - focus = s; + (atom!("module"), 2) => Ok(Declaration::Module(setup_module_decl(terms)?)), + (atom!("op"), 3) => Ok(Declaration::Op(setup_op_decl(terms)?)), + (atom!("non_counted_backtracking"), 1) => { + let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; + Ok(Declaration::NonCountedBacktracking(name, arity)) } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if focus != h { - focus = h; - } else { - return Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(decl), - )); - } + (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)), + (atom!("use_module"), 2) => { + let (name, exports) = setup_qualified_import(terms)?; + Ok(Declaration::UseQualifiedModule(name, exports)) } - _ => { - return Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(decl), - )); + (atom!("meta_predicate"), 1) => { + let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?; + Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) } - ); + _ => Err(CompilationError::InvalidDirective( + DirectiveError::InvalidDirective(name, terms.len()), + )), + }, + other => Err(CompilationError::InvalidDirective( + DirectiveError::ExpectedDirective(other), + )), } } fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, module_name: Atom, - arity: usize, - term: &TermWriteResult, + terms: Vec, meta_specs: Vec, -) -> IndexMap { - use crate::machine::heap::Heap; - let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default()); +) -> Vec { + let mut arg_terms = Vec::with_capacity(terms.len()); - let focus = { - let heap = loader.machine_heap(); - let focus_cell = - heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(term.focus))); - - if focus_cell.get_tag() == HeapCellValueTag::Str { - focus_cell.get_value() as usize - } else { - return index_ptrs; - } - }; - - for (subterm_loc, meta_spec) in (focus + 1..focus + arity + 1).zip(meta_specs) { + for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) { if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec { - let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); - - if let Some((name, arity)) = predicate_key_opt { + if let Some(name) = term.name() { if name == atom!("$call") { + arg_terms.push(term); continue; } - struct QualifiedNameInfo { - module_name: Atom, - name: Atom, - arity: usize, - qualified_term_loc: usize, - } + let arity = term.arity(); fn get_qualified_name( - heap: &Heap, - module_term_loc: usize, - qualified_term_loc: usize, - ) -> Option { - let (module_term_loc, _) = subterm_index(heap, module_term_loc); - let (qualified_term_loc, _) = subterm_index(heap, qualified_term_loc); - - read_heap_cell!(heap[module_term_loc], - (HeapCellValueTag::Atom, (module_name, arity)) => { - if arity == 0 { - if let Some((name, arity)) = term_predicate_key(heap, qualified_term_loc) { - return Some(QualifiedNameInfo { - module_name, - name, - arity, - qualified_term_loc, - }); - } - } + module_term: &Term, + qualified_term: &Term, + ) -> Option<(Atom, Atom)> { + if let Term::Literal(_, Literal::Atom(module_name)) = module_term { + if let Some(name) = qualified_term.name() { + return Some((*module_name, name)); } - _ => {} - ); + } None } - let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc); - let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); + fn identity_fn(_module_name: Atom, term: Term) -> Term { + term + } - let (module_name, key, term_loc) = if subterm_key_opt == Some((atom!(":"), 2)) { - match get_qualified_name( - loader.machine_heap(), - subterm_loc + 1, - subterm_loc + 2, - ) { - Some(QualifiedNameInfo { - module_name, - name, - arity, - qualified_term_loc, - }) => (module_name, (name, arity + supp_args), qualified_term_loc), - None => { + fn tag_with_module_name(module_name: Atom, term: Term) -> Term { + Term::Clause( + Cell::default(), + atom!(":"), + vec![ + Term::Literal(Cell::default(), Literal::Atom(module_name)), + term, + ], + ) + } + + let process_term: fn(Atom, Term) -> Term; + + let (module_name, key, term) = match term { + Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => { + if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1]) + { + process_term = tag_with_module_name; + ( + module_name, + (name, terms[1].arity() + supp_args), + terms.pop().unwrap(), + ) + } else { + arg_terms.push(Term::Clause(cell, atom!(":"), terms)); continue; } } - } else { - (module_name, (name, arity + supp_args), subterm_loc) + term => { + process_term = identity_fn; + (module_name, (name, arity + supp_args), term) + } }; - if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), term_loc) { - index_ptrs.insert(term_loc, index_ptr); - continue; - } + let term = match term { + Term::Clause(cell, name, mut terms) => { + if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { + arg_terms + .push(process_term(module_name, Term::Clause(cell, name, terms))); - index_ptrs.insert( - term_loc, - loader.get_or_insert_qualified_code_index(module_name, key), - ); + 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))], + ), + ) + } + term => term, + }; + + arg_terms.push(term); + continue; } } + + arg_terms.push(term); } - index_ptrs + arg_terms } #[inline] pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, - key: PredicateKey, - terms: &TermWriteResult, - term: HeapCellValue, + name: Atom, + mut terms: Vec, call_policy: CallPolicy, -) -> QueryClause { - // supplementary code vector indices are unnecessary for - // root-level clauses. - blunt_index_ptr(loader.machine_heap(), key, terms.focus); +) -> QueryTerm { + if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { + // supplementary code vector indices are unnecessary for + // root-level clauses. + terms.pop(); + } - let mut ct = loader.get_clause_type(key.0, key.1); + let mut ct = loader.get_clause_type(name, terms.len()); if let ClauseType::Named(arity, name, idx) = ct { if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { let module_name = loader.payload.compilation_target.module_name(); - let code_indices = - build_meta_predicate_clause(loader, module_name, arity, terms, meta_specs); + let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs); - return QueryClause { - ct: ClauseType::Named(key.1, key.0, idx), - term, - code_indices, + return QueryTerm::Clause( + Cell::default(), + ClauseType::Named(arity, name, idx), + terms, call_policy, - }; + ); } - ct = ClauseType::Named(key.1, key.0, idx); + ct = ClauseType::Named(arity, name, idx); } - QueryClause { - ct, - term, - code_indices: IndexMap::with_hasher(FxBuildHasher::default()), - call_policy, - } + QueryTerm::Clause(Cell::default(), ct, terms, call_policy) } #[inline] pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, - key: PredicateKey, module_name: Atom, - terms: &TermWriteResult, - term: HeapCellValue, + name: Atom, + mut terms: Vec, call_policy: CallPolicy, -) -> QueryClause { - // supplementary code vector indices are unnecessary for - // root-level clauses. - blunt_index_ptr(loader.machine_heap(), key, terms.focus); +) -> QueryTerm { + if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { + // supplementary code vector indices are unnecessary for + // root-level clauses. + terms.pop(); + } - let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1); + let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len()); if let ClauseType::Named(arity, name, idx) = ct { if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { - let code_indices = - build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs); + let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs); - return QueryClause { - ct: ClauseType::Named(key.1, key.0, idx), - term, - code_indices, + return QueryTerm::Clause( + Cell::default(), + ClauseType::Named(arity, name, idx), + terms, call_policy, - }; + ); } - ct = ClauseType::Named(key.1, key.0, idx); + ct = ClauseType::Named(arity, name, idx); } - QueryClause { - ct, - term, - code_indices: IndexMap::with_hasher(FxBuildHasher::default()), - call_policy, - } + QueryTerm::Clause(Cell::default(), ct, terms, call_policy) } #[derive(Debug)] @@ -642,66 +540,70 @@ impl Preprocessor { Preprocessor { settings } } - pub fn setup_fact<'a, LS: LoadState<'a>>( - &mut self, - loader: &mut Loader<'a, LS>, - term: TermWriteResult, - ) -> Result<(Fact, VarData), CompilationError> { - let heap = loader.machine_heap(); + fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> { + match term { + Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => { + let classifier = VariableClassifier::new(self.settings.default_call_policy()); - if term_predicate_key(heap, term.focus).is_some() { - let classifier = VariableClassifier::new(self.settings.default_call_policy()); - let var_data = classifier.classify_fact(loader, &term)?; - - Ok(( - Fact { - term_loc: term.focus, - }, - var_data, - )) - } else { - Err(CompilationError::InadmissibleFact) + let (head, var_data) = classifier.classify_fact(term)?; + Ok((Fact { head }, var_data)) + } + _ => Err(CompilationError::InadmissibleFact), } } fn setup_rule<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - term: TermWriteResult, + head: Term, + body: Term, ) -> Result<(Rule, VarData), CompilationError> { let classifier = VariableClassifier::new(self.settings.default_call_policy()); - let (clauses, var_data) = classifier.classify_rule(loader, &term)?; - let heap = loader.machine_heap(); - let head_loc = term_nth_arg(heap, term.focus, 1).unwrap(); + let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?; - if term_predicate_key(heap, head_loc).is_some() { - Ok(( + match head { + Term::Clause(_, name, terms) => Ok(( Rule { - term_loc: term.focus, + head: (name, terms), clauses, }, var_data, - )) - } else { - Err(CompilationError::InvalidRuleHead) + )), + Term::Literal(_, Literal::Atom(name)) => Ok(( + Rule { + head: (name, vec![]), + clauses, + }, + var_data, + )), + _ => Err(CompilationError::InvalidRuleHead), } } pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - term: TermWriteResult, + term: Term, ) -> Result { - let heap = &LS::machine_st(&mut loader.payload).heap; + match term { + Term::Clause(r, name, mut terms) => { + let is_rule = name == atom!(":-") && terms.len() == 2; - match term_predicate_key(heap, term.focus) { - Some((atom!(":-"), 2)) => { - let (rule, var_data) = self.setup_rule(loader, term)?; - Ok(PredicateClause::Rule(rule, var_data)) + if is_rule { + let tail = terms.pop().unwrap(); + let head = terms.pop().unwrap(); + + let (rule, var_data) = self.setup_rule(loader, head, tail)?; + Ok(PredicateClause::Rule(rule, var_data)) + } else { + let term = Term::Clause(r, name, terms); + let (fact, var_data) = self.setup_fact(term)?; + Ok(PredicateClause::Fact(fact, var_data)) + } } - _ => { - let (fact, var_data) = self.setup_fact(loader, term)?; + term => { + let (fact, var_data) = self.setup_fact(term)?; Ok(PredicateClause::Fact(fact, var_data)) } } diff --git a/src/machine/raw_block.rs b/src/machine/raw_block.rs index 7e85eff4..1b5d79fb 100644 --- a/src/machine/raw_block.rs +++ b/src/machine/raw_block.rs @@ -24,7 +24,12 @@ pub(crate) struct RawBlock { impl RawBlock { pub(crate) fn new() -> Self { - let mut block = Self::uninitialized(); + let mut block = RawBlock { + size: 0, + base: ptr::null(), + top: ptr::null(), + _marker: PhantomData, + }; unsafe { block.grow(); @@ -33,15 +38,6 @@ impl 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 4d8b970a..f0b136fa 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -168,13 +168,6 @@ impl Stack { } } - pub(crate) fn uninitialized() -> Self { - Stack { - buf: RawBlock::empty_block(), - _marker: PhantomData, - } - } - #[inline(always)] unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 { loop { diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 356072bc..1f9fae09 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1808,59 +1808,60 @@ impl MachineState { let addr = self.store(MachineState::deref(self, addr)); read_heap_cell!(addr, - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); - return match indices.get_stream(name) { - Some(stream) => Ok(stream), - _ => { - let stub = functor_stub(caller, arity); - let addr = atom_as_cell!(name); + return match indices.get_stream(name) { + Some(stream) => Ok(stream), + _ => { + let stub = functor_stub(caller, arity); + let addr = atom_as_cell!(name); - let existence_error = self.existence_error(ExistenceError::Stream(addr)); + let existence_error = self.existence_error(ExistenceError::Stream(addr)); - Err(self.error_form(existence_error, stub)) - } - }; - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.heap[s]) - .get_name_and_arity(); + Err(self.error_form(existence_error, stub)) + } + }; + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); - debug_assert_eq!(arity, 0); + debug_assert_eq!(arity, 0); - return match indices.get_stream(name) { - Some(stream) => Ok(stream), - _ => { - let stub = functor_stub(caller, arity); - let addr = atom_as_cell!(name); + return match indices.get_stream(name) { + Some(stream) => Ok(stream), + _ => { + let stub = functor_stub(caller, arity); + let addr = atom_as_cell!(name); - let existence_error = self.existence_error(ExistenceError::Stream(addr)); + let existence_error = self.existence_error(ExistenceError::Stream(addr)); - Err(self.error_form(existence_error, stub)) - } - }; - } - (HeapCellValueTag::Cons, ptr) => { - match_untyped_arena_ptr!(ptr, - (ArenaHeaderTag::Stream, stream) => { - if stream.is_null_stream() { - unreachable!("Null streams have no Cons representation"); - } - return Ok(stream); - } - (ArenaHeaderTag::Dropped, _value) => { - let stub = functor_stub(caller, arity); - let err = self.existence_error(ExistenceError::Stream(addr)); + Err(self.error_form(existence_error, stub)) + } + }; + } + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Stream, stream) => { + return if stream.is_null_stream() { + Err(self.open_permission_error(stream_as_cell!(stream), caller, arity)) + } else { + Ok(stream) + }; + } + (ArenaHeaderTag::Dropped, _value) => { + let stub = functor_stub(caller, arity); + let err = self.existence_error(ExistenceError::Stream(addr)); - return Err(self.error_form(err, stub)); - } - _ => { - } - ); - } - _ => { - } + return Err(self.error_form(err, stub)); + } + _ => { + } + ); + } + _ => { + } ); let stub = functor_stub(caller, arity); @@ -1880,7 +1881,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, ParserErrorSrc::default())), + Some(Err(e)) => Err(ParserError::IO(e)), Some(Ok(c)) => { if c == '\u{feff}' { // skip UTF-8 BOM @@ -2086,7 +2087,7 @@ impl MachineState { _ => { // assume the OS is out of file descriptors. let stub = functor_stub(atom!("open"), 4); - let err = self.resource_error(ResourceError::OutOfFiles); + let err = Self::resource_error(ResourceError::OutOfFiles); return Err(self.error_form(err, stub)); } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index ff2a73e4..c85bc7b6 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1,7 +1,3 @@ -use crate::parser::ast::*; -use crate::parser::lexer::LexerParser; -use crate::parser::parser::*; - use base64::Engine; use dashu::integer::{Sign, UBig}; use lazy_static::lazy_static; @@ -29,8 +25,10 @@ use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::streams::*; use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC}; +use crate::parser::ast::*; use crate::parser::char_reader::*; -use crate::parser::dashu::{Integer, Rational}; +use crate::parser::dashu::Integer; +use crate::parser::parser::*; use crate::read::*; use crate::types::*; use rand::rngs::StdRng; @@ -41,6 +39,7 @@ use ordered_float::OrderedFloat; use fxhash::{FxBuildHasher, FxHasher}; use indexmap::IndexSet; +use std::cell::Cell; use std::cmp::Ordering; use std::convert::TryFrom; use std::env; @@ -851,12 +850,10 @@ impl MachineState { ) { let mut seen_set = IndexSet::new(); - if term.is_ref() { - let mut iter = stackful_post_order_iter::( - &mut self.heap, - &mut self.stack, - term.get_value() as usize, - ); + { + self.heap[0] = term; + let mut iter = + stackful_post_order_iter::(&mut self.heap, &mut self.stack, 0); while let Some(value) = iter.next() { if iter.parent_stack_len() >= max_depth { @@ -874,9 +871,8 @@ impl MachineState { let outcome = step_or_resource_error!( self, - sized_iter_to_heap_list(&mut self.heap, seen_set.len(), seen_set.into_iter(),) + sized_iter_to_heap_list(&mut self.heap, seen_set.len(), seen_set.into_iter()) ); - unify_fn!(*self, list_of_vars, outcome); } @@ -959,7 +955,7 @@ impl MachineState { let nx = self.store(self.deref(self.registers[2])); let iter = std::io::Cursor::new(string); - let mut lexer_parser = LexerParser::new(CharReader::new(iter), self); + let mut lexer = Lexer::new(CharReader::new(iter), self); let mut tokens = vec![]; match lexer.next_number_token() { @@ -980,58 +976,35 @@ impl MachineState { } loop { - match lexer_parser.lookahead_char() { + match lexer.lookahead_char() { Err(e) if e.is_unexpected_eof() => { + let mut parser = Parser::from_lexer(lexer); let op_dir = CompositeOpDir::new(&indices.op_dir, None); tokens.reverse(); - let byte_size = heap_index!(tokens.len()); - match lexer_parser.read_term(&op_dir, Tokens::Provided(tokens, byte_size)) { - Ok(term) => { - read_heap_cell!(lexer_parser.machine_st.heap[term.focus], - (HeapCellValueTag::Cons, c) => { - match_untyped_arena_ptr!(c, - (ArenaHeaderTag::Rational, n) => { - self.unify_rational(n, nx); - } - (ArenaHeaderTag::Integer, n) => { - self.unify_big_int(n, nx); - } - _ => { - let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src()); - let e = self.syntax_error(e); - - return Err(self.error_form(e, stub_gen())); - } - ) - } - (HeapCellValueTag::F64, n) => { - self.unify_f64(n, nx); - } - (HeapCellValueTag::Fixnum, n) => { - self.unify_fixnum(n, nx); - } - _ => { - let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src()); - let e = self.syntax_error(e); - - return Err(self.error_form(e, stub_gen())); - } - ); - - return Ok(()); + match parser.read_term(&op_dir, Tokens::Provided(tokens)) { + Err(err) => { + let err = self.syntax_error(err); + return Err(self.error_form(err, stub_gen())); } - Err(e) => { - let e = self.syntax_error(e); - return Err(self.error_form(e, stub_gen())); + Ok(Term::Literal(_, cell)) => { + unify!(self, nx, HeapCellValue::from(cell)); + } + _ => { + let err = ParserError::ParseBigInt(0, 0); + let err = self.syntax_error(err); + + return Err(self.error_form(err, stub_gen())); } } + + return Ok(()); } Ok(c) => { - let err_src = lexer_parser.loc_to_err_src(); + let (line_num, col_num) = (lexer.line_num, lexer.col_num); - let err = ParserError::UnexpectedChar(c, err_src); + let err = ParserError::UnexpectedChar(c, line_num, col_num); let err = self.syntax_error(err); return Err(self.error_form(err, stub_gen())); @@ -1645,12 +1618,12 @@ impl Machine { let vars: Vec<_> = vars .union(&result.supp_vars) // difference + union does not cancel. - .cloned() + .map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value())))) .collect(); let helper_clause_loc = self.code.len(); - match self.compile_standalone_clause(temp_v!(1), vars) { + match self.compile_standalone_clause(temp_v!(1), &vars) { Err(e) => { let err = self.machine_st.session_error(e); let stub = functor_stub(atom!("call"), result.key.1); @@ -1996,7 +1969,7 @@ impl Machine { if let Some(name) = entry.file_name().to_str() { let file_string_cell = resource_error_call_result!( self.machine_st, - self.machine_st.allocate_cstr(name) + self.machine_st.heap.allocate_cstr(name) ); files.push(file_string_cell); @@ -2115,7 +2088,7 @@ impl Machine { let cstr_cell = step_or_resource_error!( self.machine_st, - self.machine_st.allocate_cstr(&chars_string) + self.machine_st.heap.allocate_cstr(&chars_string) ); unify!(self.machine_st, cstr_cell, self.machine_st.registers[3]); @@ -2251,7 +2224,7 @@ impl Machine { let current_string = resource_error_call_result!( self.machine_st, - self.machine_st.allocate_cstr(current) + self.machine_st.heap.allocate_cstr(current) ); unify!( @@ -2295,8 +2268,10 @@ impl Machine { } }; - let canonical_string = - resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(cs)); + let canonical_string = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.allocate_cstr(cs) + ); unify!( self.machine_st, @@ -2321,7 +2296,7 @@ impl Machine { let cell = step_or_resource_error!( self.machine_st, - self.machine_st.allocate_cstr(&*name.as_str()) + self.machine_st.heap.allocate_cstr(&*name.as_str()) ); unify!(self.machine_st, self.machine_st.registers[2], cell); @@ -2522,7 +2497,7 @@ impl Machine { let pstr_loc_cell = step_or_resource_error!( self.machine_st, - self.machine_st.allocate_pstr(&*atom.as_str()) + self.machine_st.heap.allocate_pstr(&*atom.as_str()) ); let tail_loc = Heap::pstr_tail_idx(atom.as_str().len() + heap_index!(pstr_h)); @@ -2897,7 +2872,7 @@ impl Machine { let cstr_cell = step_or_resource_error!( self.machine_st, - self.machine_st.allocate_cstr(string.trim()) + self.machine_st.heap.allocate_cstr(string.trim()) ); unify!(self.machine_st, cstr_cell, chs); @@ -3137,7 +3112,7 @@ impl Machine { let reg = self.machine_st.deref(self.machine_st.heap[s+1]); let upper_str = step_or_resource_error!( self.machine_st, - self.machine_st.allocate_cstr(&c.to_uppercase().to_string()) + self.machine_st.heap.allocate_cstr(&c.to_uppercase().to_string()) ); unify!(self.machine_st, reg, upper_str); } @@ -3145,7 +3120,7 @@ impl Machine { let reg = self.machine_st.deref(self.machine_st.heap[s+1]); let lower_str = step_or_resource_error!( self.machine_st, - self.machine_st.allocate_cstr(&c.to_uppercase().to_string()) + self.machine_st.heap.allocate_cstr(&c.to_uppercase().to_string()) ); unify!(self.machine_st, reg, lower_str); @@ -3660,12 +3635,7 @@ impl Machine { } Some(Err(e)) => { let stub = functor_stub(atom!("$get_n_chars"), 3); - let err = - self.machine_st - .session_error(SessionError::from(ParserError::IO( - e, - ParserErrorSrc::default(), - ))); + let err = self.machine_st.session_error(SessionError::from(e)); return Err(self.machine_st.error_form(err, stub)); } @@ -3677,8 +3647,10 @@ impl Machine { }; let output = self.deref_register(3); - let cstr_cell = - resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&string)); + let cstr_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.allocate_cstr(&string) + ); unify!(self.machine_st, cstr_cell, output); Ok(()) @@ -4403,9 +4375,7 @@ impl Machine { Ok(Number::Integer(n)) => match (&*n).try_into() as Result { Ok(n) => n, Err(_) => { - let err = self - .machine_st - .resource_error(ResourceError::FiniteMemory(len)); + let err = MachineState::resource_error(ResourceError::FiniteMemory(len)); return Err(self.machine_st.error_form(err, stub_gen())); } }, @@ -4508,6 +4478,7 @@ impl Machine { let string_cell = resource_error_call_result!( self.machine_st, self.machine_st + .heap .allocate_cstr(header_value.to_str().unwrap()) ); @@ -4568,7 +4539,7 @@ impl Machine { } } - Ok(()) + Ok::<(), _>(()) })?; } else { let err = self @@ -4758,7 +4729,7 @@ impl Machine { let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path); let path_cell = resource_error_call_result!( self.machine_st, - self.machine_st.allocate_cstr(&request.request_data.path) + self.machine_st.heap.allocate_cstr(&request.request_data.path) ); let mut headers = vec![]; @@ -4766,7 +4737,7 @@ impl Machine { for (header_name, header_value) in request.request_data.headers { let header_value = resource_error_call_result!( self.machine_st, - self.machine_st.allocate_cstr(header_value.to_str().unwrap()) + self.machine_st.heap.allocate_cstr(header_value.to_str().unwrap()) ); let header_term = functor!( @@ -4796,7 +4767,7 @@ impl Machine { let query_str = request.request_data.query; let query_cell = resource_error_call_result!( self.machine_st, - self.machine_st.allocate_cstr(&query_str) + self.machine_st.heap.allocate_cstr(&query_str) ); let mut stream = Stream::from_http_stream( @@ -5064,7 +5035,7 @@ impl Machine { Value::CString(cstr) => { let str_cell = resource_error_call_result!( self.machine_st, - self.machine_st.allocate_cstr(cstr.to_str().unwrap()) + self.machine_st.heap.allocate_cstr(cstr.to_str().unwrap()) ); unify!(self.machine_st, str_cell, return_value); @@ -5208,8 +5179,10 @@ impl Machine { let mut args_pstrs = vec![]; for arg in env::args() { - let pstr_cell = - resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&arg)); + let pstr_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.allocate_cstr(&arg) + ); args_pstrs.push(pstr_cell); } @@ -5230,8 +5203,10 @@ impl Machine { #[inline(always)] pub(crate) fn current_time(&mut self) { let timestamp = self.systemtime_to_timestamp(SystemTime::now()); - let cstr_cell = - step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(×tamp)); + let cstr_cell = step_or_resource_error!( + self.machine_st, + self.machine_st.heap.allocate_cstr(×tamp) + ); unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]); } @@ -6494,7 +6469,7 @@ impl Machine { } #[inline(always)] - fn read_term_from_atom( + fn read_term_and_write_to_heap( &mut self, atom_or_string: AtomOrString, ) -> Result, MachineStub> { @@ -6504,15 +6479,16 @@ impl Machine { }; let chars = CharReader::new(ByteStream::from_string(string)); - let mut parser = LexerParser::new(chars, &mut self.machine_st); + let mut parser = Parser::new(chars, &mut self.machine_st); let op_dir = CompositeOpDir::new(&self.indices.op_dir, None); - let term = parser + let term_write_result = parser .read_term(&op_dir, Tokens::Default) - .map_err(|e| error_after_read_term(e, 0)); + .map_err(|err| error_after_read_term(err, 0, &parser)) + .and_then(|term| write_term_to_heap(&term, &mut self.machine_st.heap)); - match term { - Ok(term) => Ok(Some(term)), + match term_write_result { + Ok(term_write_result) => Ok(Some(term_write_result)), Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => { let value = self.machine_st.registers[2]; self.machine_st.unify_atom(atom!("end_of_file"), value); @@ -6530,46 +6506,43 @@ impl Machine { #[inline(always)] pub(crate) fn read_from_chars(&mut self) -> CallResult { - let atom_or_string = self + if let Some(atom_or_string) = self .machine_st .value_to_str_like(self.machine_st.registers[1]) - .unwrap(); + { + if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? { + let result = heap_loc_as_cell!(term_write_result.heap_loc); + let var = self.deref_register(2).as_var().unwrap(); - if let Some(term) = self.read_term_from_atom(atom_or_string)? { - let result = self.machine_st.heap[term.focus]; - let var = self.deref_register(2).as_var().unwrap(); + self.machine_st.bind(var, result); + } - self.machine_st.bind(var, result); + Ok(()) + } else { + unreachable!() } - - Ok(()) } #[inline(always)] pub(crate) fn read_term_from_chars(&mut self) -> CallResult { - let atom_or_string = self + if let Some(atom_or_string) = self .machine_st .value_to_str_like(self.machine_st.registers[1]) - .unwrap(); + { + if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? { + self.machine_st.read_term_body(term_write_result) + } else { + if !self.machine_st.fail { + // wrote end_of_file term in this case. + self.machine_st + .write_read_term_options(vec![], empty_list_as_cell!())?; + } - let string = match atom_or_string { - AtomOrString::Atom(atom!("[]")) => "".to_owned(), - _ => atom_or_string.into(), - }; - - let chars = CharReader::new(ByteStream::from_string(string)); - let term = self - .machine_st - .read(chars, &self.indices.op_dir) - .map(|(term, _)| term) - .map_err(|e| { - let e = self.machine_st.session_error(SessionError::from(e)); - let stub = functor_stub(atom!("read_term_from_chars"), 3); - - self.machine_st.error_form(e, stub) - })?; - - self.machine_st.read_term_body(term) + Ok(()) + } + } else { + unreachable!() + } } #[inline(always)] @@ -7542,8 +7515,10 @@ impl Machine { }; let result = printer.print().result(); - let chars = - resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&result)); + let chars = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.allocate_cstr(&result) + ); let result_addr = self.deref_register(1); let var = result_addr.as_var().unwrap(); @@ -7559,7 +7534,7 @@ impl Machine { let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); let cstr_cell = - step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer)); + step_or_resource_error!(self.machine_st, self.machine_st.heap.allocate_cstr(&buffer)); unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]); } @@ -8010,7 +7985,10 @@ impl Machine { if buffer.is_empty() { empty_list_as_cell!() } else { - step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer)) + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.allocate_cstr(&buffer) + ) } }; @@ -8197,7 +8175,7 @@ impl Machine { Ok(value) => { let cstr = step_or_resource_error!( self.machine_st, - self.machine_st.allocate_cstr(&value) + self.machine_st.heap.allocate_cstr(&value) ); unify!(self.machine_st, self.machine_st.registers[2], cstr); @@ -8410,20 +8388,15 @@ impl Machine { 1, )?; - let mut lexer_parser = LexerParser::new(stream, &mut self.machine_st); + let mut parser = Parser::new(stream, &mut self.machine_st); - match devour_whitespace(&mut lexer_parser) { + match devour_whitespace(&mut parser.lexer) { Ok(false) => { - // not at EOF ... - stream.add_lines_read(lexer_parser.line_num()); - - // ... unless we are. - if stream.at_end_of_stream() { - self.machine_st.fail = true; - } + // not at EOF. + stream.add_lines_read(parser.lines_read()); } Ok(true) => { - stream.add_lines_read(lexer_parser.line_num()); + stream.add_lines_read(parser.lexer.line_num); self.machine_st.fail = true; } Err(err) => { @@ -8483,8 +8456,10 @@ impl Machine { if path.is_dir() { if let Some(path) = path.to_str() { - let path_string = - step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(path)); + let path_string = step_or_resource_error!( + self.machine_st, + self.machine_st.heap.allocate_cstr(path) + ); unify!(self.machine_st, self.machine_st.registers[1], path_string); return; @@ -8557,13 +8532,13 @@ impl Machine { node: roxmltree::Node, ) -> Result { if node.is_text() { - self.machine_st.allocate_cstr(node.text().unwrap()) + self.machine_st.heap.allocate_cstr(node.text().unwrap()) } else { let mut avec = Vec::new(); for attr in node.attributes() { let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.name()); - let value = self.machine_st.allocate_cstr(attr.value())?; + let value = self.machine_st.heap.allocate_cstr(attr.value())?; avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len())); @@ -8610,13 +8585,14 @@ impl Machine { match node.value().as_element() { None => self .machine_st + .heap .allocate_cstr(&node.value().as_text().unwrap().text), Some(element) => { let mut avec = Vec::new(); for attr in element.attrs() { let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.0); - let value = self.machine_st.allocate_cstr(attr.1)?; + let value = self.machine_st.heap.allocate_cstr(attr.1)?; avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len())); @@ -8669,7 +8645,7 @@ impl Machine { if buffer.is_empty() { Ok(empty_list_as_cell!()) } else { - self.machine_st.allocate_cstr(&buffer) + self.machine_st.heap.allocate_cstr(&buffer) } } } diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs index f8488af7..a0f5ae22 100644 --- a/src/machine/term_stream.rs +++ b/src/machine/term_stream.rs @@ -21,11 +21,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, + pub(super) clause_clauses: Vec<(Term, Term)>, } 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; } @@ -33,7 +33,7 @@ pub trait TermStream: Sized { #[derive(Debug)] pub struct BootstrappingTermStream<'a> { listing_src: ListingSource, - pub(super) lexer_parser: LexerParser<'a, Stream>, + pub(super) parser: Parser<'a, Stream>, } impl<'a> BootstrappingTermStream<'a> { @@ -43,9 +43,9 @@ impl<'a> BootstrappingTermStream<'a> { machine_st: &'a mut MachineState, listing_src: ListingSource, ) -> Self { - let lexer_parser = LexerParser::new(stream, machine_st); + let parser = Parser::new(stream, machine_st); Self { - lexer_parser, + parser, listing_src, } } @@ -53,18 +53,16 @@ impl<'a> BootstrappingTermStream<'a> { impl<'a> TermStream for BootstrappingTermStream<'a> { #[inline] - fn next(&mut self, op_dir: &CompositeOpDir) -> Result { - let result = self - .lexer_parser + fn next(&mut self, op_dir: &CompositeOpDir) -> Result { + self.parser.reset(); + self.parser .read_term(op_dir, Tokens::Default) - .map_err(CompilationError::from); - - result + .map_err(CompilationError::from) } #[inline] fn eof(&mut self) -> Result { - devour_whitespace(&mut self.lexer_parser) // eliminate dangling comments before checking for EOF. + devour_whitespace(&mut self.parser.lexer) // eliminate dangling comments before checking for EOF. .map_err(CompilationError::from) } @@ -75,7 +73,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> { } pub struct LiveTermStream { - pub(super) term_queue: VecDeque, + pub(super) term_queue: VecDeque, pub(super) listing_src: ListingSource, } @@ -111,7 +109,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()) } @@ -129,10 +127,8 @@ impl TermStream for LiveTermStream { pub struct InlineTermStream {} impl TermStream for InlineTermStream { - fn next(&mut self, _: &CompositeOpDir) -> Result { - Err(CompilationError::from(ParserError::unexpected_eof( - ParserErrorSrc::default(), - ))) + fn next(&mut self, _: &CompositeOpDir) -> Result { + Err(CompilationError::from(ParserError::unexpected_eof())) } fn eof(&mut self) -> Result { diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 899fc3ac..b9aae0e6 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -133,11 +133,14 @@ pub(crate) trait Unifier: DerefMut { machine_st.partial_string_to_pdl(pstr_loc, l); } (HeapCellValueTag::PStrLoc, other_pstr_loc) => { - let cmp_result = machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc); - - if cmp_result.continue_pstr_compare(&mut machine_st.pdl).is_some() { - debug_assert!(matches!(cmp_result, PStrSegmentCmpResult::Mismatch { .. })); - machine_st.fail = true; + match machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc) { + PStrSegmentCmpResult::Continue(v1, v2) => { + machine_st.pdl.push(v1); + machine_st.pdl.push(v2); + } + _ => { + machine_st.fail = true; + } } } _ => { @@ -501,10 +504,8 @@ fn bind_with_occurs_check(unifier: &mut U, r: Ref, value: HeapCellVa let mut occurs_triggered = false; - let machine_st: &mut MachineState = unifier.deref_mut(); - let value = machine_st.store(MachineState::deref(machine_st, value)); - - if value.is_ref() && !value.is_stack_var() { + if !value.is_constant() { + let machine_st: &mut MachineState = unifier.deref_mut(); machine_st.heap[0] = value; for cell in diff --git a/src/macros.rs b/src/macros.rs index 4869e402..6d6a71b8 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -287,12 +287,6 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; - ($cell:ident, Atom, (_, $arity:ident), $code:expr) => {{ - let $arity = cell_as_atom_cell!($cell).get_arity(); - #[allow(unused_braces)] - $code - }}; - /* ($cell:ident, PStr, $atom:ident, $code:expr) => {{ let $atom = cell_as_atom!($cell); #[allow(unused_braces)] @@ -313,7 +307,6 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; - */ ($cell:ident, Fixnum, $value:ident, $code:expr) => {{ let $value = Fixnum::from_bytes($cell.into_bytes()); #[allow(unused_braces)] @@ -489,7 +482,7 @@ macro_rules! step_or_resource_error { macro_rules! resource_error_call_result { ($machine_st:expr, $val:expr) => { step_or_resource_error!($machine_st, $val, { - return Err(vec![]); // TODO: return Ok(()); + return Err(vec![]); }) }; } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 2785b0bf..96a0df1f 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -2,18 +2,22 @@ use crate::arena::*; use crate::atom_table::*; -use crate::forms::PredicateKey; -use crate::machine::heap::*; -use crate::machine::machine_indices::*; -use crate::types::*; +use crate::machine::machine_indices::CodeIndex; +use crate::parser::char_reader::*; +use crate::types::HeapCellValueTag; +use std::cell::{Cell, Ref, RefCell, RefMut}; use std::fmt; use std::hash::Hash; +use std::hash::Hasher; use std::io::{Error as IOError, ErrorKind}; -use std::ops::Neg; +use std::ops::{Deref, Neg}; use std::rc::Rc; +use std::sync::Arc; use std::vec::Vec; +use dashu::Integer; +use dashu::Rational; use fxhash::FxBuildHasher; use indexmap::IndexMap; use scryer_modular_bitfield::error::OutOfBounds; @@ -138,16 +142,7 @@ pub const BTERM: u32 = 0x11000; pub const NEGATIVE_SIGN: u32 = 0x0200; macro_rules! fixnum { - ($n:expr, $arena:expr) => { - Fixnum::build_with_checked($n) - .map(|n| fixnum_as_cell!(n)) - .unwrap_or_else(|_| { - typed_arena_ptr_as_cell!( - arena_alloc!(Integer::from($n), $arena) as TypedArenaPtr - ) - }) - }; - ($wrapper:ty, $n:expr, $arena:expr) => { + ($wrapper:tt, $n:expr, $arena:expr) => { Fixnum::build_with_checked($n) .map(<$wrapper>::Fixnum) .unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena))) @@ -276,6 +271,37 @@ impl fmt::Display for RegType { } } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum VarReg { + ArgAndNorm(RegType, usize), + Norm(RegType), +} + +impl VarReg { + pub fn norm(self) -> RegType { + match self { + VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg, + } + } +} + +impl fmt::Display for VarReg { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), + VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), + VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg), + VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg), + } + } +} + +impl Default for VarReg { + fn default() -> Self { + VarReg::Norm(RegType::default()) + } +} + macro_rules! temp_v { ($x:expr) => { $crate::parser::ast::RegType::Temp($x) @@ -373,49 +399,41 @@ pub fn default_op_dir() -> OpDir { op_dir } -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] pub enum ArithmeticError { - NonEvaluableFunctor(HeapCellValue, usize), -} - -#[derive(Debug, Copy, Clone, Default)] -pub struct ParserErrorSrc { - pub col_num: usize, - pub line_num: usize, + NonEvaluableFunctor(Literal, usize), + UninstantiatedVar, } +#[allow(dead_code)] #[derive(Debug)] pub enum ParserError { - BackQuotedString(ParserErrorSrc), - IO(IOError, ParserErrorSrc), - IncompleteReduction(ParserErrorSrc), - InfiniteFloat(ParserErrorSrc), - InvalidSingleQuotedCharacter(char, ParserErrorSrc), - LexicalError(lexical::Error, ParserErrorSrc), - MissingQuote(ParserErrorSrc), - NonPrologChar(ParserErrorSrc), - ParseBigInt(ParserErrorSrc), - ResourceError(ParserErrorSrc), - UnexpectedChar(char, ParserErrorSrc), + BackQuotedString(usize, usize), + IO(IOError), + IncompleteReduction(usize, usize), + InfiniteFloat(usize, usize), + InvalidSingleQuotedCharacter(char), + LexicalError(lexical::Error), + MissingQuote(usize, usize), + NonPrologChar(usize, usize), + ParseBigInt(usize, usize), + UnexpectedChar(char, usize, usize), // UnexpectedEOF, - Utf8Error(ParserErrorSrc), + Utf8Error(usize, usize), } impl ParserError { - pub fn err_src(&self) -> ParserErrorSrc { + pub fn line_and_col_num(&self) -> Option<(usize, usize)> { match self { - &ParserError::BackQuotedString(err_src) - | &ParserError::IO(_, err_src) - | &ParserError::IncompleteReduction(err_src) - | &ParserError::InfiniteFloat(err_src) - | &ParserError::InvalidSingleQuotedCharacter(_, err_src) - | &ParserError::LexicalError(_, err_src) - | &ParserError::MissingQuote(err_src) - | &ParserError::NonPrologChar(err_src) - | &ParserError::ParseBigInt(err_src) - | &ParserError::ResourceError(err_src) - | &ParserError::UnexpectedChar(_, err_src) - | &ParserError::Utf8Error(err_src) => err_src, + &ParserError::BackQuotedString(line_num, col_num) + | &ParserError::IncompleteReduction(line_num, col_num) + | &ParserError::InfiniteFloat(line_num, col_num) + | &ParserError::MissingQuote(line_num, col_num) + | &ParserError::NonPrologChar(line_num, col_num) + | &ParserError::ParseBigInt(line_num, col_num) + | &ParserError::UnexpectedChar(_, line_num, col_num) + | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)), + _ => None, } } @@ -429,31 +447,30 @@ impl ParserError { ParserError::InfiniteFloat(..) => { atom!("infinite_float") } - ParserError::IO(e, _) if e.kind() == ErrorKind::UnexpectedEof => { + ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => { atom!("unexpected_end_of_file") } - ParserError::IO(e, _) if e.kind() == ErrorKind::InvalidData => { + ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => { atom!("invalid_data") } - ParserError::IO(..) => atom!("input_output_error"), - ParserError::LexicalError(..) => atom!("lexical_error"), + ParserError::IO(_) => atom!("input_output_error"), + ParserError::LexicalError(_) => atom!("lexical_error"), ParserError::MissingQuote(..) => atom!("missing_quote"), ParserError::NonPrologChar(..) => atom!("non_prolog_character"), ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"), ParserError::UnexpectedChar(..) => atom!("unexpected_char"), ParserError::Utf8Error(..) => atom!("utf8_conversion_error"), - ParserError::ResourceError(..) => atom!("resource_error"), } } #[inline] - pub fn unexpected_eof(err_src: ParserErrorSrc) -> Self { - ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof), err_src) + pub fn unexpected_eof() -> Self { + ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof)) } #[inline] pub fn is_unexpected_eof(&self) -> bool { - if let ParserError::IO(e, _) = self { + if let ParserError::IO(e) = self { e.kind() == ErrorKind::UnexpectedEof } else { false @@ -461,9 +478,25 @@ impl ParserError { } } -impl From for ParserError { - fn from(err_src: ParserErrorSrc) -> ParserError { - ParserError::LexicalError(err_src) +impl From for ParserError { + fn from(e: lexical::Error) -> ParserError { + ParserError::LexicalError(e) + } +} + +impl From for ParserError { + fn from(e: IOError) -> ParserError { + ParserError::IO(e) + } +} + +impl From<&IOError> for ParserError { + fn from(error: &IOError) -> ParserError { + if error.get_ref().filter(|e| e.is::()).is_some() { + ParserError::Utf8Error(0, 0) + } else { + ParserError::IO(error.kind().into()) + } } } @@ -575,8 +608,7 @@ impl Neg for Fixnum { } } -/* -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Literal { Atom(Atom), CodeIndex(CodeIndex), @@ -584,7 +616,6 @@ pub enum Literal { Integer(TypedArenaPtr), Rational(TypedArenaPtr), Float(F64Offset), - String(Rc), } impl From for Literal { @@ -606,7 +637,6 @@ impl fmt::Display for Literal { Literal::Integer(ref n) => write!(f, "{}", n), Literal::Rational(ref n) => write!(f, "{}", n), Literal::Float(ref n) => write!(f, "{}", *n), - Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()), } } } @@ -619,38 +649,109 @@ impl Literal { } } } -*/ -pub type Var = Rc; +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct VarPtr(Rc>); -pub(crate) fn subterm_index(heap: &impl SizedHeap, 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 Hash for VarPtr { + #[inline(always)] + fn hash(&self, hasher: &mut H) { + self.borrow().hash(hasher) + } +} + +impl Deref for VarPtr { + type Target = RefCell; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} + +impl VarPtr { + #[inline(always)] + pub(crate) fn borrow(&self) -> Ref<'_, Var> { + self.0.borrow() + } + + #[inline(always)] + pub(crate) fn borrow_mut(&self) -> RefMut<'_, Var> { + self.0.borrow_mut() + } + + pub(crate) fn to_var_num(&self) -> Option { + match *self.borrow() { + Var::Generated(var_num) => Some(var_num), + _ => None, + } + } + + pub(crate) fn set(&self, var: Var) { + let mut var_ref = self.borrow_mut(); + *var_ref = var; + } +} + +impl From for VarPtr { + #[inline(always)] + fn from(value: Var) -> VarPtr { + VarPtr(Rc::new(RefCell::new(value))) + } +} + +impl From for VarPtr { + #[inline(always)] + fn from(value: String) -> VarPtr { + VarPtr::from(Var::from(value)) + } +} + +impl From<&str> for VarPtr { + #[inline(always)] + fn from(value: &str) -> VarPtr { + VarPtr::from(value.to_owned()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum Var { + Generated(usize), + InSitu(usize), + Named(Rc), +} + +impl From for Var { + #[inline(always)] + fn from(value: String) -> Var { + Var::Named(Rc::new(value)) + } +} + +impl From<&str> for Var { + #[inline(always)] + fn from(value: &str) -> Var { + Var::Named(Rc::new(value.to_owned())) + } +} + +impl Var { + #[allow(clippy::inherent_to_string)] + #[inline(always)] + pub fn to_string(&self) -> String { + match self { + Var::InSitu(n) | Var::Generated(n) => format!("_{}", n), + Var::Named(value) => value.as_ref().clone(), + } } } -/* #[derive(Debug, Clone)] pub enum Term { AnonVar, Clause(Cell, Atom, Vec), Cons(Cell, Box, Box), - Literal(Cell, HeapCellValue), - // Literal(Cell, Literal), + Literal(Cell, Literal), // PartialString wraps a String in anticipation of it absorbing // other PartialString variants in as_partial_string. PartialString(Cell, Rc, Box), @@ -668,12 +769,8 @@ impl Term { pub fn name(&self) -> Option { match self { - Term::Literal(_, cell) => { - cell.to_atom() - } - &Term::Clause(_, atom, ..) => { - Some(atom) - } + &Term::Literal(_, Literal::Atom(atom)) => Some(atom), + &Term::Clause(_, atom, ..) => Some(atom), _ => None, } } @@ -714,281 +811,3 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec { terms.push(term); terms } - */ - -pub(crate) fn fetch_index_ptr(heap: &impl SizedHeap, term_loc: usize) -> Option { - let index_cell_loc = term_loc.saturating_sub(1); - - read_heap_cell!(heap[index_cell_loc], - (HeapCellValueTag::Cons, c) => { - match_untyped_arena_ptr!(c, - (ArenaHeaderTag::IndexPtr, ptr) => { - return Some(CodeIndex::from(ptr)); - } - _ => {} - ); - } - _ => {} - ); - - None -} - -pub(crate) fn blunt_index_ptr( - heap: &mut impl SizedHeapMut, - key: PredicateKey, - term_loc: usize, -) -> bool { - if fetch_index_ptr(heap, term_loc).is_some() { - heap[term_loc] = atom_as_cell!(key.0, key.1); - true - } else { - false - } -} - -pub(crate) fn unfold_by_str_once( - heap: &mut impl SizedHeapMut, - start_term: HeapCellValue, - atom: Atom, -) -> Option { - let start_term = heap_bound_store(heap, heap_bound_deref(heap, start_term)); - - if let HeapCellValueTag::Str = start_term.get_tag() { - let s = start_term.get_value() as usize; - - let (s_atom, s_arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); - blunt_index_ptr(heap, (s_atom, s_arity), s); - - if (s_atom, s_arity) == (atom, 2) { - return Some(s + 1); - } - } - - None -} - -pub fn unfold_by_str( - heap: &mut impl SizedHeapMut, - mut start_term: HeapCellValue, - atom: Atom, -) -> Vec { - let mut terms = vec![]; - start_term = heap_bound_store(heap, heap_bound_deref(heap, start_term)); - - while let Some(fst_loc) = unfold_by_str_once(heap, start_term, atom) { - let (_, snd) = subterm_index(heap, fst_loc + 1); - let (_, fst) = subterm_index(heap, fst_loc); - terms.push(fst); - start_term = snd; - } - - terms -} - -/* -pub fn unfold_by_str_locs( - heap: &mut [HeapCellValue], - mut term_loc: usize, - atom: Atom, -) -> Vec<(HeapCellValue, usize)> { - let mut terms = vec![]; - let mut current_term = heap_bound_store( - heap, - heap_bound_deref(heap, heap[term_loc]), - ); - - while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) { - (term_loc, current_term) = subterm_index(heap, fst_loc + 1); - let (fst_loc, fst) = subterm_index(heap, fst_loc); - terms.push((fst, fst_loc)); - } - - terms.push((current_term, term_loc)); - terms -} -*/ - -pub fn unfold_by_str_locs( - heap: &mut impl SizedHeapMut, - mut term_loc: usize, - atom: Atom, -) -> Vec<(HeapCellValue, usize)> { - let mut terms = vec![]; - let mut current_term = heap[term_loc]; - - while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) { - term_loc = fst_loc + 1; - current_term = heap[term_loc]; - let fst = heap[fst_loc]; - terms.push((fst, fst_loc)); - } - - terms.push((current_term, term_loc)); - terms -} - -pub fn term_predicate_key(heap: &impl SizedHeap, mut term_loc: usize) -> Option { - loop { - read_heap_cell!(heap[term_loc], - (HeapCellValueTag::Atom, (name, arity)) => { - return Some((name, arity)); - } - (HeapCellValueTag::Str, s) => { - term_loc = s; - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h != term_loc { - term_loc = h; - } else { - return None; - } - } - _ => { - return None; - } - ); - } -} - -pub fn inverse_var_locs_from_iter>(iter: I) -> InverseVarLocs { - 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; - } - } - - let mut inverse_var_locs = InverseVarLocs::default(); - - for (var, count) in occurrence_set { - let var_loc = var.get_value() as usize; - - if count > 1 { - inverse_var_locs.insert(var_loc, Rc::new(format!("_{}", var_loc))); - } - } - - inverse_var_locs -} - -/* -pub fn term_deref(heap: &[HeapCellValue], mut term_loc: usize) -> HeapCellValue { - loop { - read_heap_cell!(heap[term_loc], - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h != term_loc { - term_loc = h; - } else { - return heap[h]; - } - } - _ => { - return heap[term_loc]; - } - ) - } -} -*/ - -pub fn term_nth_arg(heap: &impl SizedHeap, mut term_loc: usize, n: usize) -> Option { - loop { - read_heap_cell!(heap[term_loc], - (HeapCellValueTag::Str, s) => { - return if cell_as_atom_cell!(heap[s]).get_arity() >= n { - Some(s+n) - } else { - None - }; - } - (HeapCellValueTag::Atom, (_name, arity)) => { - return if arity >= n { - Some(term_loc + n) - } else { - None - }; - } - (HeapCellValueTag::Lis, l) => { - return if 1 <= n && n <= 2 { - Some(l+n-1) - } else if n == 0 { - Some(term_loc) - } else { - None - }; - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h != term_loc { - term_loc = h; - } else { - return None; - } - } - _ => { - return None; - } - ); - } -} - -#[derive(Debug)] -pub struct TermWriteResult { - pub focus: usize, - pub inverse_var_locs: InverseVarLocs, -} - -pub type VarLocs = IndexMap; -pub type InverseVarLocs = IndexMap; - -#[derive(Debug)] -pub struct FocusedHeapRefMut<'a> { - pub heap: &'a mut Heap, - pub focus: usize, -} - -impl<'a> FocusedHeapRefMut<'a> { - #[inline] - pub fn from(heap: &'a mut Heap, focus: usize) -> Self { - Self { heap, focus } - } - - pub fn predicate_key(&self, term_loc: usize) -> Option { - term_predicate_key(self.heap, term_loc) - } - - pub fn arity(&self, term_loc: usize) -> usize { - self.predicate_key(term_loc) - .map(|(_, arity)| arity) - .unwrap_or(0) - } - - pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue { - let cell = self.heap[term_loc]; - heap_bound_store(self.heap, heap_bound_deref(self.heap, cell)) - } - - pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option { - term_nth_arg(self.heap, term_loc, n) - } - - /* - pub fn from_cell(heap: &'a mut Heap, cell: HeapCellValue) -> Self { - let focus = read_heap_cell!(cell, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - h - } - _ => { - let h = heap.len(); - heap.push_cell(cell).unwrap(); - - h - } - ); - - Self { heap, focus } - } - */ -} diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index e1be5c46..01a122a5 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -1,15 +1,12 @@ use crate::arena::F64Ptr; use crate::arena::TypedArenaPtr; -use lexical::{FromLexical, parse}; use crate::arena::*; use crate::atom_table::*; -use crate::machine::heap::*; pub use crate::machine::machine_state::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::dashu::Integer; -use crate::types::*; use std::convert::TryFrom; use std::fmt; @@ -35,7 +32,7 @@ struct LayoutInfo { #[derive(Debug, PartialEq)] pub enum Token { - Literal(HeapCellValue), + Literal(Literal), Var(String), String(String), Open, // '(' @@ -51,26 +48,6 @@ pub enum Token { } impl Token { - pub(super) fn byte_size(&self, flags: MachineFlags) -> usize { - match self { - Token::String(string) if flags.double_quotes.is_codes() => { - 2 * string.chars().count() + 1 - } - Token::String(string) => Heap::compute_pstr_size(&string), - Token::Literal(_) - | Token::Comma - | Token::HeadTailSeparator - | Token::Open - | Token::OpenCT - | Token::OpenCurly - | Token::OpenList - | Token::Var(_) => { - heap_index!(1) - } - _ => 0, - } - } - #[inline] pub(super) fn is_end(&self) -> bool { matches!(self, Token::End) @@ -126,14 +103,14 @@ macro_rules! try_nt { }}; } -pub(crate) struct LexerParser<'a, R> { +pub(crate) struct Lexer<'a, R> { pub(crate) reader: R, pub(crate) machine_st: &'a mut MachineState, pub(crate) line_num: usize, pub(crate) col_num: usize, } -impl<'a, R: fmt::Debug> fmt::Debug for LexerParser<'a, R> { +impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("LexerParser") .field("reader", &"&'a mut R") // Hacky solution. @@ -143,9 +120,9 @@ impl<'a, R: fmt::Debug> fmt::Debug for LexerParser<'a, R> { } } -impl<'a, R: CharRead> LexerParser<'a, R> { +impl<'a, R: CharRead> Lexer<'a, R> { pub fn new(src: R, machine_st: &'a mut MachineState) -> Self { - LexerParser { + Self { reader: src, machine_st, line_num: 0, @@ -156,14 +133,14 @@ impl<'a, R: CharRead> LexerParser<'a, R> { pub fn lookahead_char(&mut self) -> Result { match self.reader.peek_char() { Some(Ok(c)) => Ok(c), - _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())), + _ => Err(ParserError::unexpected_eof()), } } pub fn read_char(&mut self) -> Result { match self.reader.read_char() { Some(Ok(c)) => Ok(c), - _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())), + _ => Err(ParserError::unexpected_eof()), } } @@ -238,7 +215,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> { match comment_loop() { Err(e) if e.is_unexpected_eof() => { - return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); + return Err(ParserError::IncompleteReduction( + self.line_num, + self.col_num, + )); } Err(e) => { return Err(e); @@ -250,7 +230,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { self.skip_char(c); Ok(true) } else { - Err(ParserError::NonPrologChar(self.loc_to_err_src())) + Err(ParserError::NonPrologChar(self.line_num, self.col_num)) } } else { self.return_char('/'); @@ -267,7 +247,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { if !back_quote_char!(c2) { self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) } else { self.skip_char(c2); Ok(c2) @@ -292,7 +272,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { Ok(None) } else { self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) } } else { self.get_back_quoted_char().map(Some) @@ -314,10 +294,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> { self.skip_char(c); Ok(token) } else { - Err(ParserError::MissingQuote(self.loc_to_err_src())) + Err(ParserError::MissingQuote(self.line_num, self.col_num)) } } else { - Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) } } @@ -348,7 +328,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { if !single_quote_char!(c2) { self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) } else { self.skip_char(c2); Ok(c2) @@ -389,7 +369,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { if !double_quote_char!(c2) { self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) } else { self.skip_char(c2); Ok(c2) @@ -413,7 +393,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { 't' => '\t', 'n' => '\n', 'r' => '\r', - c => return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())), + c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)), }; self.skip_char(c); @@ -431,7 +411,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> { if hexadecimal_digit_char!(c) { self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16) } else { - Err(ParserError::IncompleteReduction(self.loc_to_err_src())) + Err(ParserError::IncompleteReduction( + self.line_num, + self.col_num, + )) } } @@ -457,11 +440,17 @@ impl<'a, R: CharRead> LexerParser<'a, R> { if backslash_char!(c) { self.skip_char(c); u32::from_str_radix(&token, radix).map_or_else( - |_| Err(ParserError::ParseBigInt(self.loc_to_err_src())), - |n| char::try_from(n).map_err(|_| ParserError::Utf8Error(self.loc_to_err_src())), + |_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)), + |n| { + char::try_from(n) + .map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num)) + }, ) } else { - Err(ParserError::IncompleteReduction(self.loc_to_err_src())) + Err(ParserError::IncompleteReduction( + self.line_num, + self.col_num, + )) } } @@ -473,7 +462,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { Ok(c) } else { if !backslash_char!(c) { - return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())); + return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)); } self.skip_char(c); @@ -504,7 +493,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { self.skip_char(c); Ok(token) } else { - Err(ParserError::MissingQuote(self.loc_to_err_src())) + Err(ParserError::MissingQuote(self.line_num, self.col_num)) } } @@ -529,7 +518,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { .map(NumberToken::Number) } else { self.return_char(start); - Err(ParserError::ParseBigInt(self.loc_to_err_src())) + Err(ParserError::ParseBigInt(self.line_num, self.col_num)) } } @@ -554,7 +543,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { .map(NumberToken::Number) } else { self.return_char(start); - Err(ParserError::ParseBigInt(self.loc_to_err_src())) + Err(ParserError::ParseBigInt(self.line_num, self.col_num)) } } @@ -579,7 +568,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { .map(NumberToken::Number) } else { self.return_char(start); - Err(ParserError::ParseBigInt(self.loc_to_err_src())) + Err(ParserError::ParseBigInt(self.line_num, self.col_num)) } } @@ -646,42 +635,37 @@ impl<'a, R: CharRead> LexerParser<'a, R> { if !token.is_empty() && token.chars().nth(1).is_none() { if let Some(c) = token.chars().next() { - return Ok(Token::Literal(char_as_cell!(c))); + return Ok(Token::Literal(Literal::Atom( + AtomCell::new_char_inlined(c).get_name(), + ))); } } } else { - return Err(ParserError::InvalidSingleQuotedCharacter( - self.loc_to_err_src(), - )); + return Err(ParserError::InvalidSingleQuotedCharacter(c)); } } else { match self.get_back_quoted_string() { - Ok(_) => return Err(ParserError::BackQuotedString(self.loc_to_err_src())), + Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)), Err(e) => return Err(e), } } if token.as_str() == "[]" { - Ok(Token::Literal(empty_list_as_cell!())) + Ok(Token::Literal(Literal::Atom(atom!("[]")))) } else { - Ok(Token::Literal(atom_as_cell!(AtomTable::build_with( + Ok(Token::Literal(Literal::Atom(AtomTable::build_with( &self.machine_st.atom_tbl, &token, )))) } } - fn parse_lossy_wrapper(&self, token: &str) -> Result { - match parse::(token.as_bytes()) { - Ok(n) => Ok(n), - Err(_) => return Err(ParserError::LexicalError(self.loc_to_err_src())), - } - } - fn vacate_with_float(&mut self, mut token: String) -> Result { self.return_char(token.pop().unwrap()); - let n = self.parse_lossy_wrapper::(&token)?; - Ok(Token::Literal(HeapCellValue::from(float_alloc!( + + let n = parse_float_lossy(&token)?; + + Ok(Token::Literal(Literal::from(float_alloc!( n, self.machine_st.arena )))) @@ -698,7 +682,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> { if decimal_digit_char!(c) { Ok(c) } else { - Err(ParserError::ParseBigInt(self.loc_to_err_src())) + Err(ParserError::ParseBigInt(self.line_num, self.col_num)) } } else { Ok(c) @@ -810,8 +794,8 @@ impl<'a, R: CharRead> LexerParser<'a, R> { } } - let n = self.parse_lossy_wrapper::(&token)?; - Ok(Token::Literal(HeapCellValue::from(float_alloc!( + let n = parse_float_lossy(&token)?; + Ok(Token::Literal(Literal::from(float_alloc!( n, self.machine_st.arena )))) @@ -819,8 +803,8 @@ impl<'a, R: CharRead> LexerParser<'a, R> { return self.vacate_with_float(token).map(NumberToken::Number); } } else { - let n = self.parse_lossy_wrapper::(&token)?; - Ok(Token::Literal(HeapCellValue::from(float_alloc!( + let n = parse_float_lossy(&token)?; + Ok(Token::Literal(Literal::from(float_alloc!( n, self.machine_st.arena )))) @@ -1057,14 +1041,14 @@ impl<'a, R: CharRead> LexerParser<'a, R> { return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes { let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s); - Ok(Token::Literal(atom_as_cell!(atom))) + Ok(Token::Literal(Literal::Atom(atom))) } else { Ok(Token::String(s)) }; } if c == '\u{0}' { - return Err(ParserError::unexpected_eof(self.loc_to_err_src())); + return Err(ParserError::unexpected_eof()); } self.name_token(c) @@ -1073,3 +1057,13 @@ impl<'a, R: CharRead> LexerParser<'a, R> { } } } + +fn parse_float_lossy(token: &str) -> Result { + const FORMAT: u128 = lexical::format::STANDARD; + let options = lexical::ParseFloatOptions::builder() + .lossy(true) + .build() + .unwrap(); + let n = lexical::parse_with_options::(token.as_bytes(), &options)?; + Ok(n) +} diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 0dcff8a7..a6ec7007 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -3,19 +3,18 @@ use dashu::Rational; use crate::arena::*; use crate::atom_table::*; -use crate::forms::Number; -use crate::machine::heap::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::lexer::*; -use crate::types::*; +use std::cell::Cell; +use std::mem; use std::ops::Neg; use std::rc::Rc; #[derive(Debug, Clone, Copy, PartialEq)] enum TokenType { - Term { heap_loc: HeapCellValue }, + Term, Open, OpenCT, OpenList, // '[' @@ -28,23 +27,6 @@ enum TokenType { End, } -impl TokenType { - fn sep_to_atom(self) -> Option { - match self { - TokenType::Open | TokenType::OpenCT => Some(atom!("(")), - TokenType::Close => Some(atom!(")")), - TokenType::OpenList => Some(atom!("[")), - TokenType::CloseList => Some(atom!("]")), - TokenType::OpenCurly => Some(atom!("{")), - TokenType::CloseCurly => Some(atom!("}")), - TokenType::HeadTailSeparator => Some(atom!("|")), - TokenType::Comma => Some(atom!(",")), - TokenType::End => Some(atom!(".")), - _ => None, - } - } -} - /* Specifies whether the token sequence should be read from the lexer or provided via the Provided variant. @@ -52,7 +34,7 @@ provided via the Provided variant. #[derive(Debug)] pub enum Tokens { Default, - Provided(Vec, usize), + Provided(Vec), } impl TokenType { @@ -80,6 +62,80 @@ struct TokenDesc { unfold_bounds: usize, } +pub(crate) fn as_partial_string( + head: Term, + mut tail: Term, +) -> Result<(String, Option>), Term> { + let mut string = match &head { + Term::Literal(_, Literal::Atom(atom)) => { + if let Some(c) = atom.as_char() { + c.to_string() + } else { + return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); + } + } + _ => { + return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); + } + }; + + let mut orig_tail = Box::new(tail); + let mut tail_ref = &mut orig_tail; + + loop { + match &mut **tail_ref { + Term::Cons(_, prev, succ) => { + match prev.as_ref() { + Term::Literal(_, Literal::Atom(atom)) => { + if let Some(c) = atom.as_char() { + string.push(c); + } else { + return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail)); + } + } + _ => { + tail = Term::Cons( + Cell::default(), + Box::new((**prev).clone()), + Box::new((**succ).clone()), + ); + break; + } + } + + tail_ref = succ; + } + Term::PartialString(_, pstr, tail) => { + string += pstr; + tail_ref = tail; + } + Term::CompleteString(_, cstr) => { + string += &*cstr.as_str(); + tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); + break; + } + tail_ref => { + tail = mem::replace(tail_ref, Term::AnonVar); + break; + } + } + } + + match tail { + Term::AnonVar | Term::Var(..) => Ok((string, Some(Box::new(tail)))), + Term::Literal(_, Literal::Atom(atom!("[]"))) => Ok((string, None)), + Term::CompleteString(_, tail) => { + string += &tail; + Ok((string, None)) + } + Term::PartialString(_, tail_string, tail) => { + string += &tail_string; + Ok((string, Some(tail))) + } + _ => Ok((string, Some(Box::new(tail)))), + } +} + pub fn get_op_desc(name: Atom, op_dir: &CompositeOpDir) -> Option { let mut op_desc = CompositeOpDesc { pre: 0, @@ -175,29 +231,20 @@ pub struct CompositeOpDesc { } #[derive(Debug)] -struct Parser<'a> { +pub struct Parser<'a, R> { + pub lexer: Lexer<'a, R>, tokens: Vec, stack: Vec, - terms: HeapWriter<'a>, - arena: &'a mut Arena, - flags: MachineFlags, - line_num: &'a mut usize, - col_num: &'a mut usize, - var_locs: VarLocs, - inverse_var_locs: InverseVarLocs, + terms: Vec, } -pub fn read_tokens( - lexer: &mut LexerParser, -) -> Result<(Vec, usize), ParserError> { +pub fn read_tokens(lexer: &mut Lexer<'_, R>) -> Result, ParserError> { let mut tokens = vec![]; - let mut term_size = 0; loop { match lexer.next_token() { Ok(token) => { let at_end = token.is_end(); - term_size += token.byte_size(lexer.machine_st.flags); tokens.push(token); if at_end { @@ -205,7 +252,10 @@ pub fn read_tokens( } } Err(e) if e.is_unexpected_eof() && !tokens.is_empty() => { - return Err(ParserError::IncompleteReduction(lexer.loc_to_err_src())); + return Err(ParserError::IncompleteReduction( + lexer.line_num, + lexer.col_num, + )); } Err(e) => { return Err(e); @@ -214,142 +264,78 @@ pub fn read_tokens( } tokens.reverse(); - - Ok((tokens, term_size)) + Ok(tokens) } -pub(crate) fn as_partial_string( - heap: &impl SizedHeap, - 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)); +fn atomize_term(term: &Term) -> Option { + match term { + &Term::Literal(_, Literal::Atom(c)) => Some(c), + _ => None, + } +} - let mut string = read_heap_cell!(head, - (HeapCellValueTag::Atom, (atom, arity)) => { - if arity == 0 { - if let Some(c) = atom.as_char() { - c.to_string() - } else { - return None; - } - } else { - return None; - } - } - _ => { - return None; - } - ); +impl TokenType { + fn sep_to_atom(&mut self) -> Option { + match self { + TokenType::Open | TokenType::OpenCT => Some(atom!("(")), + TokenType::Close => Some(atom!(")")), + TokenType::OpenList => Some(atom!("[")), + TokenType::CloseList => Some(atom!("]")), + TokenType::OpenCurly => Some(atom!("{")), + TokenType::CloseCurly => Some(atom!("}")), + TokenType::HeadTailSeparator => Some(atom!("|")), + TokenType::Comma => Some(atom!(",")), + TokenType::End => Some(atom!(".")), + _ => None, + } + } +} - loop { - read_heap_cell!(tail, - (HeapCellValueTag::Lis, l) => { - read_heap_cell!(heap[l], - (HeapCellValueTag::Atom, (atom, arity)) => { - if arity == 0 { - if let Some(c) = atom.as_char() { - string.push(c); - } else { - return None; - } - } else { - break; - } - } - _ => { - return None; - } - ); - - tail = heap[l+1]; - } - (HeapCellValueTag::PStrLoc, l) => { - let HeapStringScan { string: pstr, tail_idx } = heap.scan_slice_to_str(l); - string += pstr; - tail = heap[tail_idx]; - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if heap[h] != tail { - tail = heap[h]; - } else { - break; - } - } - _ => { - // Anon - break; - } - ); +impl<'a, R: CharRead> Parser<'a, R> { + pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self { + Parser { + lexer: Lexer::new(stream, machine_st), + tokens: vec![], + stack: vec![], + terms: vec![], + } } - read_heap_cell!(tail, - (HeapCellValueTag::Var) => { - Some((string, Some(tail))) - } - (HeapCellValueTag::Atom, (atom, arity)) => { - if atom == atom!("[]") && arity == 0 { - Some((string, None)) - } else { - Some((string, Some(tail))) - } - } - _ => { - Some((string, Some(tail))) - } - ) -} + pub fn from_lexer(lexer: Lexer<'a, R>) -> Self { + Parser { + lexer, + tokens: vec![], + stack: vec![], + terms: vec![], + } + } -impl<'a> Parser<'a> { - fn get_term_name(&self, td: TokenDesc) -> Option { + fn get_term_name(&mut self, td: TokenDesc) -> Option { match td.tt { TokenType::HeadTailSeparator => Some(atom!("|")), TokenType::Comma => Some(atom!(",")), - TokenType::Term { heap_loc } => { - if heap_loc.is_ref() { - term_predicate_key(&self.terms, heap_loc.get_value() as usize).map(|key| key.0) - } else { + TokenType::Term => match self.terms.pop() { + Some(Term::Literal(_, Literal::Atom(atom))) => Some(atom), + Some(term) => { + self.terms.push(term); None } - } + _ => None, + }, _ => None, } } - fn push_binary_op( - &mut self, - op: TokenDesc, - operand_1: TokenDesc, - operand_2: TokenDesc, - spec: Specifier, - ) { - if let TokenDesc { - tt: TokenType::Term { heap_loc: arg2 }, - .. - } = operand_2 - { - if let TokenDesc { - tt: TokenType::Term { heap_loc: arg1 }, - .. - } = operand_1 - { - if let Some(name) = self.get_term_name(op) { - let str_loc = self.terms.cell_len(); - - self.terms.write_with(|section| { - section.push_cell(atom_as_cell!(name, 2)); - section.push_cell(arg1); - section.push_cell(arg2); - - section.push_cell(str_loc_as_cell!(str_loc)); - }); + fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) { + if let Some(arg2) = self.terms.pop() { + if let Some(name) = self.get_term_name(td) { + if let Some(arg1) = self.terms.pop() { + let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]); + self.terms.push(term); self.stack.push(TokenDesc { - tt: TokenType::Term { - heap_loc: heap_loc_as_cell!(str_loc + 3), - }, - priority: op.priority, + tt: TokenType::Term, + priority: td.priority, spec, unfold_bounds: 0, }); @@ -358,31 +344,20 @@ impl<'a> Parser<'a> { } } - fn push_unary_op(&mut self, op: TokenDesc, operand: TokenDesc, spec: Specifier) { - if let TokenDesc { - tt: TokenType::Term { heap_loc: arg1 }, - .. - } = operand - { - if let TokenDesc { - tt: TokenType::Term { .. }, - .. - } = op - { - if let Some(name) = self.get_term_name(op) { - let str_loc = self.terms.cell_len(); + fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: OpDeclSpec) { + if let Some(mut arg1) = self.terms.pop() { + if let Some(mut name) = self.terms.pop() { + if assoc.is_postfix() { + mem::swap(&mut arg1, &mut name); + } - self.terms.write_with(|section| { - section.push_cell(atom_as_cell!(name, 1)); - section.push_cell(arg1); - section.push_cell(str_loc_as_cell!(str_loc)); - }); + if let Term::Literal(_, Literal::Atom(name)) = name { + let term = Term::Clause(Cell::default(), name, vec![arg1]); + self.terms.push(term); self.stack.push(TokenDesc { - tt: TokenType::Term { - heap_loc: heap_loc_as_cell!(str_loc + 2), - }, - priority: op.priority, + tt: TokenType::Term, + priority: td.priority, spec, unfold_bounds: 0, }); @@ -392,13 +367,10 @@ impl<'a> Parser<'a> { } fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) { - let h = self.terms.cell_len(); self.terms - .write_with(|section| section.push_cell(atom_as_cell!(atom))); + .push(Term::Literal(Cell::default(), Literal::Atom(atom))); self.stack.push(TokenDesc { - tt: TokenType::Term { - heap_loc: heap_loc_as_cell!(h), - }, + tt: TokenType::Term, priority, spec: assoc, unfold_bounds: 0, @@ -406,90 +378,42 @@ impl<'a> Parser<'a> { } fn shift(&mut self, token: Token, priority: usize, spec: Specifier) { - let heap_loc = heap_loc_as_cell!(self.terms.cell_len()); - let tt = match token { - Token::String(s) if self.flags.double_quotes.is_codes() => { - let mut list = empty_list_as_cell!(); + Token::String(s) if self.lexer.machine_st.flags.double_quotes.is_codes() => { + let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); - self.terms.write_with(|section| { - for c in s.as_str().chars().rev() { - let h = section.cell_len(); + 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), + ); + } - section.push_cell(fixnum_as_cell!(Fixnum::build_with(c as i64))); - section.push_cell(list); - - list = list_loc_as_cell!(h); - } - - section.push_cell(list); - }); - - TokenType::Term { heap_loc: list } + self.terms.push(list); + TokenType::Term } Token::String(s) => { - debug_assert!(self.flags.double_quotes.is_chars()); - let mut pstr_cell = heap_loc; - - if s == "\u{0}" { - let h = self.terms.cell_len(); - - self.terms.write_with(|section| { - section.push_cell(char_as_cell!('\u{0}')); - section.push_cell(empty_list_as_cell!()); - section.push_cell(list_loc_as_cell!(h)); - }); - - TokenType::Term { - heap_loc: heap_loc_as_cell!(h + 2), - } - } else { - self.terms - .write_with(|section| match section.push_pstr(&s) { - Some(pstr_loc_cell) => { - section.push_cell(empty_list_as_cell!()); - let h = section.cell_len(); - section.push_cell(pstr_loc_cell); - pstr_cell = heap_loc_as_cell!(h); - } - None => { - section.push_cell(empty_list_as_cell!()); - } - }); - - TokenType::Term { - heap_loc: pstr_cell, - } - } + debug_assert!(self.lexer.machine_st.flags.double_quotes.is_chars()); + self.terms + .push(Term::CompleteString(Cell::default(), Rc::new(s))); + TokenType::Term } Token::Literal(c) => { - self.terms.write_with(|section| section.push_cell(c)); - TokenType::Term { heap_loc } + self.terms.push(Term::Literal(Cell::default(), c)); + TokenType::Term } - Token::Var(var_string) => { - let var = Rc::new(var_string); - - match self.var_locs.get(&var).cloned() { - Some(heap_loc) => { - self.terms.write_with(|section| section.push_cell(heap_loc)); - TokenType::Term { heap_loc } - } - None => { - self.terms.write_with(|section| section.push_cell(heap_loc)); - - // if var_string == "_", it not being present - // as a key of self.var_locs means it is - // anonymous. - - if var.trim() != "_" { - self.var_locs.insert(var.clone(), heap_loc); - self.inverse_var_locs - .insert(heap_loc.get_value() as usize, var); - } - - TokenType::Term { heap_loc } - } + Token::Var(v) => { + if v.trim() == "_" { + self.terms.push(Term::AnonVar); + } else { + self.terms.push(Term::Var(Cell::default(), VarPtr::from(v))); } + + TokenType::Term } Token::Comma => TokenType::Comma, Token::Open => TokenType::Open, @@ -519,10 +443,10 @@ impl<'a> Parser<'a> { if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1) || is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1) { - self.push_binary_op(desc2, desc3, desc1, LTERM); + self.push_binary_op(desc2, LTERM); continue; } else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) { - self.push_binary_op(desc2, desc3, desc1, TERM); + self.push_binary_op(desc2, TERM); continue; } else { self.stack.push(desc3); @@ -530,16 +454,16 @@ impl<'a> Parser<'a> { } if is_yf!(desc1.spec) && affirm_yf(desc1, desc2) { - self.push_unary_op(desc1, desc2, LTERM); + self.push_unary_op(desc1, LTERM, YF); continue; } else if is_xf!(desc1.spec) && affirm_xf(desc1, desc2) { - self.push_unary_op(desc1, desc2, LTERM); + self.push_unary_op(desc1, LTERM, XF); continue; } else if is_fy!(desc2.spec) && affirm_fy(priority, desc1, desc2) { - self.push_unary_op(desc2, desc1, TERM); + self.push_unary_op(desc2, TERM, FY); continue; } else if is_fx!(desc2.spec) && affirm_fx(priority, desc1, desc2) { - self.push_unary_op(desc2, desc1, TERM); + self.push_unary_op(desc2, TERM, FX); continue; } else { self.stack.push(desc2); @@ -583,14 +507,6 @@ impl<'a> Parser<'a> { None } - fn term_from_stack(&self, idx: usize) -> Option { - if let TokenType::Term { heap_loc } = self.stack[idx].tt { - Some(heap_loc) - } else { - None - } - } - fn reduce_term(&mut self) -> bool { if self.stack.is_empty() { return false; @@ -617,94 +533,39 @@ impl<'a> Parser<'a> { return false; } - if self.terms.cell_len() < arity { + if self.terms.len() < 1 + arity { return false; } let stack_len = self.stack.len() - 2 * arity - 1; - let term_idx = self.terms.cell_len(); + let idx = self.terms.len() - arity; - let push_structure = |parser: &mut Self, name: Atom| -> TokenType { - parser - .terms - .write_with(|section| section.push_cell(atom_as_cell!(name, arity))); - - for idx in (stack_len + 2..parser.stack.len()).step_by(2) { - let subterm = parser.term_from_stack(idx).unwrap(); - parser - .terms - .write_with(|section| section.push_cell(subterm)); - } - - let str_loc_idx = parser.terms.cell_len(); - parser - .terms - .write_with(|section| section.push_cell(str_loc_as_cell!(term_idx))); - - TokenType::Term { - heap_loc: heap_loc_as_cell!(str_loc_idx), - } - }; - - if let TokenDesc { - tt: TokenType::Term { heap_loc }, - .. - } = self.stack[stack_len] + if TokenType::Term == self.stack[stack_len].tt + && atomize_term(&self.terms[idx - 1]).is_some() { - let idx = heap_loc.get_value() as usize; + self.stack.truncate(stack_len + 1); - if let Some((name, arity)) = term_predicate_key(&self.terms, idx) { + let mut subterms: Vec<_> = self.terms.drain(idx..).collect(); + + if let Some(name) = self.terms.pop().and_then(|t| atomize_term(&t)) { // reduce the '.' functor to a cons cell if it applies. - let new_tt = if name == atom!(".") && arity == 2 { - let head = self.term_from_stack(stack_len + 2).unwrap(); - let tail = self.term_from_stack(stack_len + 4).unwrap(); - let cell_len = self.terms.cell_len(); + if name == atom!(".") && subterms.len() == 2 { + let tail = subterms.pop().unwrap(); + let head = subterms.pop().unwrap(); - match as_partial_string(&self.terms, head, tail) { - Some((string_buf, tail_opt)) => { - let HeapSectionWriteResult { bytes_written, .. } = - self.terms.write_with(|section| { - if let Some(pstr_cell) = section.push_pstr(&string_buf) { - section - .push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); - section.push_cell(pstr_cell); - } else { - section.push_cell(empty_list_as_cell!()); - } - }); - - if cell_index!(bytes_written) > 1 { - TokenType::Term { - heap_loc: heap_loc_as_cell!( - cell_index!(bytes_written) - 1 + cell_len - ), - } - } else { - TokenType::Term { - heap_loc: heap_loc_as_cell!(cell_len), - } - } + self.terms.push(match as_partial_string(head, tail) { + Ok((string_buf, Some(tail))) => { + Term::PartialString(Cell::default(), Rc::new(string_buf), tail) } - None => { - let HeapSectionWriteResult { bytes_written, .. } = - self.terms.write_with(|section| { - section.push_cell(head); - section.push_cell(tail); - section.push_cell(list_loc_as_cell!(term_idx)); - }); - - TokenType::Term { - heap_loc: heap_loc_as_cell!( - cell_len + cell_index!(bytes_written) - 1 - ), - } + Ok((string_buf, None)) => { + Term::CompleteString(Cell::default(), Rc::new(string_buf)) } - } + Err(term) => term, + }); } else { - push_structure(self, name) - }; - - self.stack.truncate(stack_len + 1); + self.terms + .push(Term::Clause(Cell::default(), name, subterms)); + } if let Some(&mut TokenDesc { ref mut tt, @@ -717,56 +578,38 @@ impl<'a> Parser<'a> { return false; } - *tt = new_tt; + *tt = TokenType::Term; *priority = 0; *spec = TERM; *unfold_bounds = 0; } - } else { - return false; - }; - return true; + return true; + } } false } - fn loc_to_err_src(&self) -> ParserErrorSrc { - ParserErrorSrc { - line_num: *self.line_num, - col_num: *self.col_num, - } + pub fn reset(&mut self) { + self.stack.clear() } fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { - if let Some(term) = self.term_from_stack(index - 1) { + if let Some(mut term) = self.terms.pop() { let mut op_desc = self.stack[index - 1]; - let mut term = heap_bound_store(&self.terms, heap_bound_deref(&self.terms, term)); - if term.is_ref() - && 0 < op_desc.priority - && op_desc.priority < self.stack[index].priority - { + if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority { /* '|' is a head-tail separator here, not * an operator, so expand the * terms it compacted out again. */ - - let focus = term.get_value() as usize; - let key_opt = term_predicate_key(&self.terms, focus); - - if key_opt == Some((atom!(","), 2)) { + if let (Some(atom!(",")), 2) = (term.name(), term.arity()) { let terms = if op_desc.unfold_bounds == 0 { - unfold_by_str(&mut self.terms, term, atom!(",")) + unfold_by_str(term, atom!(",")) } else { let mut terms = vec![]; - while let Some(fst_loc) = - unfold_by_str_once(&mut self.terms, term, atom!(",")) - { - let (_, snd) = subterm_index(&self.terms, fst_loc + 1); - let (_, fst) = subterm_index(&self.terms, fst_loc); - + while let Some((fst, snd)) = unfold_by_str_once(&mut term, atom!(",")) { terms.push(fst); term = snd; @@ -782,16 +625,13 @@ impl<'a> Parser<'a> { }; let arity = terms.len() - 1; - self.stack - .extend(terms.into_iter().map(|heap_loc| TokenDesc { - tt: TokenType::Term { heap_loc }, - priority: 0, - spec: 0, - unfold_bounds: 0, - })); + + self.terms.extend(terms); return arity; } } + + self.terms.push(term); } 0 @@ -831,18 +671,13 @@ impl<'a> Parser<'a> { } if let Some(ref mut td) = self.stack.last_mut() { - // parsed an empty list token if td.tt == TokenType::OpenList { - let h = self.terms.cell_len(); - self.terms - .write_with(|section| section.push_cell(empty_list_as_cell!())); - td.spec = TERM; - td.tt = TokenType::Term { - heap_loc: heap_loc_as_cell!(h), - }; + td.tt = TokenType::Term; td.priority = 0; + self.terms + .push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))); return Ok(true); } } @@ -856,99 +691,65 @@ impl<'a> Parser<'a> { // we know that self.stack.len() >= 2 by this point. let idx = self.stack.len() - 2; - let list_start_idx = self.stack.len() - 2 * arity; + let list_len = self.stack.len() - 2 * arity; - let mut tail_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { - empty_list_as_cell!() + let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { + Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))) } else { - let tail_term = match self.term_from_stack(idx + 1) { + let term = match self.terms.pop() { Some(term) => term, - None => { - return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); + _ => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) } }; - self.stack.pop(); - if self.stack[idx].priority > 1000 { arity += self.expand_comma_compacted_terms(idx); } - // decrement for the removal of tail term. - arity -= 1; - tail_term - }; - - if arity > self.terms.cell_len() { - return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); - } - - let pre_terms_len = self.terms.cell_len(); - - while let Some(token_desc) = self.stack.pop() { - let subterm = match token_desc.tt { - TokenType::Term { heap_loc } => heap_loc, - _ => { - continue; - } - }; - arity -= 1; - let link_cell = list_loc_as_cell!(self.terms.cell_len() + 1); + term + }; - self.terms.write_with(|section| { - section.push_cell(link_cell); - section.push_cell(subterm); - section.push_cell(tail_term); - }); - - tail_term = link_cell; - - if arity == 0 { - break; - } + if arity > self.terms.len() { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); } - debug_assert_eq!(arity, 0); + let idx = self.terms.len() - arity; - self.stack.truncate(list_start_idx); + let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| { + Term::Cons(Cell::default(), Box::new(t), Box::new(acc)) + }); - let list_loc = self.terms.cell_len() - 3; - - let head_term = self.terms[list_loc + 1]; - let tail_term = self.terms[list_loc + 2]; - - let heap_loc = match as_partial_string(&self.terms, head_term, tail_term) { - Some((string_buf, tail_opt)) => { - self.terms.truncate(pre_terms_len); - - let HeapSectionWriteResult { bytes_written, .. } = - self.terms.write_with(|section| { - if let Some(pstr_cell) = section.push_pstr(&string_buf) { - section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); - section.push_cell(pstr_cell); - } - }); - - if bytes_written > 0 { - heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1) - } else { - empty_list_as_cell!() - } - } - None => { - heap_loc_as_cell!(list_loc) // head_term - } - }; + self.stack.truncate(list_len); self.stack.push(TokenDesc { - tt: TokenType::Term { heap_loc }, + tt: TokenType::Term, priority: 0, spec: TERM, unfold_bounds: 0, }); + self.terms.push(match list { + Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) { + Ok((string_buf, Some(tail))) => { + Term::PartialString(Cell::default(), Rc::new(string_buf), tail) + } + Ok((string_buf, None)) => { + Term::CompleteString(Cell::default(), Rc::new(string_buf)) + } + Err(term) => term, + }, + term => term, + }); + Ok(true) } @@ -959,17 +760,13 @@ impl<'a> Parser<'a> { if let Some(ref mut td) = self.stack.last_mut() { if td.tt == TokenType::OpenCurly { - let h = self.terms.cell_len(); - - self.terms - .write_with(|section| section.push_cell(atom_as_cell!(atom!("{}")))); - - td.tt = TokenType::Term { - heap_loc: heap_loc_as_cell!(h), - }; + td.tt = TokenType::Term; td.priority = 0; td.spec = TERM; + let term = Term::Literal(Cell::default(), Literal::Atom(atom!("{}"))); + + self.terms.push(term); return Ok(true); } } @@ -979,43 +776,29 @@ impl<'a> Parser<'a> { if self.stack.len() > 1 { if let Some(td) = self.stack.pop() { if let Some(ref mut oc) = self.stack.last_mut() { - if !matches!(td.tt, TokenType::Term { .. }) { + if td.tt != TokenType::Term { return Ok(false); } if oc.tt == TokenType::OpenCurly { - if let TokenType::Term { heap_loc } = td.tt { - let curly_idx = self.terms.cell_len(); + oc.tt = TokenType::Term; + oc.priority = 0; + oc.spec = TERM; - oc.tt = TokenType::Term { - heap_loc: heap_loc_as_cell!(curly_idx + 2), - }; - 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.write_with(|section| { - section.push_cell(atom_as_cell!(atom!("{}"), 1)); - section.push_cell(heap_loc); - section.push_cell(str_loc_as_cell!(curly_idx)); - }); + self.terms + .push(Term::Clause(Cell::default(), atom!("{}"), vec![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); - } + return Ok(true); } } } @@ -1035,9 +818,8 @@ impl<'a> Parser<'a> { return false; } - match self.stack.last().map(|token| token.tt) { - Some(TokenType::Open | TokenType::OpenCT) => return false, - _ => {} + if let Some(TokenType::Open | TokenType::OpenCT) = self.stack.last().map(|token| token.tt) { + return false; } let idx = self.stack.len() - 2; @@ -1049,14 +831,13 @@ impl<'a> Parser<'a> { return false; } - let term = if self.stack[idx].tt.sep_to_atom().is_some() { - atom_as_cell!(atom!("|")) - } else { - self.term_from_stack(idx).unwrap() - }; + if let Some(atom) = self.stack[idx].tt.sep_to_atom() { + self.terms + .push(Term::Literal(Cell::default(), Literal::Atom(atom))); + } self.stack[idx].spec = BTERM; - self.stack[idx].tt = TokenType::Term { heap_loc: term }; + self.stack[idx].tt = TokenType::Term; self.stack[idx].priority = 0; true @@ -1074,11 +855,7 @@ impl<'a> Parser<'a> { }) = get_op_desc(name, op_dir) { if (pre > 0 && inf + post > 0) || is_negate!(spec) { - match self - .tokens - .last() - .ok_or(ParserError::unexpected_eof(self.loc_to_err_src()))? - { + match self.tokens.last().ok_or(ParserError::unexpected_eof())? { // do this when layout hasn't been inserted, // ie. why we don't match on Token::Open. Token::OpenCT => { @@ -1133,33 +910,31 @@ impl<'a> Parser<'a> { fn negate_number(&mut self, n: N, negator: Negator, constr: ToLiteral) where Negator: Fn(N, &mut Arena) -> N, - ToLiteral: Fn(N, &mut Arena) -> HeapCellValue, + ToLiteral: Fn(N, &mut Arena) -> Literal, { - match self.stack.last().cloned() { - Some( - td @ TokenDesc { - tt: TokenType::Term { .. }, - spec, - .. - }, - ) => { - if let Some(name) = self.get_term_name(td) { - if name == atom!("-") && (is_prefix!(spec) || is_negate!(spec)) { + if let Some(desc) = self.stack.last().cloned() { + if let Some(term) = self.terms.last().cloned() { + match term { + Term::Literal(_, Literal::Atom(name)) + if name == atom!("-") + && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => + { self.stack.pop(); + self.terms.pop(); - let arena = &mut self.arena; + let arena = &mut self.lexer.machine_st.arena; let literal = constr(negator(n, arena), arena); self.shift(Token::Literal(literal), 0, TERM); return; } + _ => {} } } - _ => {} } - let literal = constr(n, &mut self.arena); + let literal = constr(n, &mut self.lexer.machine_st.arena); self.shift(Token::Literal(literal), 0, TERM); } @@ -1180,58 +955,62 @@ impl<'a> Parser<'a> { Token::String(string) => { self.shift(Token::String(string), 0, TERM); } - Token::Literal(c) => match Number::try_from(c) { - Ok(Number::Integer(n)) => { - self.negate_number(n, negate_int_rc, |n, _| typed_arena_ptr_as_cell!(n)) - } - Ok(Number::Rational(n)) => { - self.negate_number(n, negate_rat_rc, |r, _| typed_arena_ptr_as_cell!(r)) - } - Ok(Number::Float(n)) if n.is_infinite() => { - return Err(ParserError::InfiniteFloat( - self.loc_to_err_src(), - )); - } - Ok(Number::Float(n)) => { - use ordered_float::OrderedFloat; - - self.negate_number( - n, - |n, _| -n, - |OrderedFloat(n), arena| HeapCellValue::from(float_alloc!(n, arena)), - ) - } - Ok(Number::Fixnum(n)) => { - self.negate_number(n, |n, _| -n, |n, _| fixnum_as_cell!(n)) - } - Err(_) => { - if let Some(name) = c.to_atom() { - if !self.shift_op(name, op_dir)? { - self.shift(Token::Literal(c), 0, TERM); - } - } else { + Token::Literal(Literal::Integer(n)) => { + self.negate_number(n, negate_int_rc, |n, _| Literal::Integer(n)) + } + Token::Literal(Literal::Rational(n)) => { + self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r)) + } + Token::Literal(Literal::Float(n)) if n.as_ptr().is_infinite() => { + return Err(ParserError::InfiniteFloat( + self.lexer.line_num, + self.lexer.col_num, + )); + } + Token::Literal(Literal::Float(n)) => self.negate_number( + **n.as_ptr(), + |n, _| -n, + |n, arena| Literal::from(float_alloc!(n, arena)), + ), + Token::Literal(Literal::Fixnum(n)) => { + self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n)) + } + Token::Literal(c) => { + if let Literal::Atom(name) = c { + if !self.shift_op(name, op_dir)? { self.shift(Token::Literal(c), 0, TERM); } + } else { + self.shift(Token::Literal(c), 0, TERM); } - }, + } Token::Var(v) => self.shift(Token::Var(v), 0, TERM), Token::Open => self.shift(Token::Open, 1300, DELIMITER), Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER), Token::Close => { if !self.reduce_term() && !self.reduce_brackets() { - return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); } } Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER), Token::CloseList => { if !self.reduce_list()? { - return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); } } Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER), Token::CloseCurly => { if !self.reduce_curly()? { - return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); } } Token::HeadTailSeparator => { @@ -1265,7 +1044,10 @@ impl<'a> Parser<'a> { | Some(TokenType::OpenCurly) | Some(TokenType::HeadTailSeparator) | Some(TokenType::Comma) => { - return Err(ParserError::IncompleteReduction(self.loc_to_err_src())) + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) } _ => {} }, @@ -1273,19 +1055,15 @@ impl<'a> Parser<'a> { Ok(()) } -} -impl<'a, R: CharRead> LexerParser<'a, R> { #[inline] - pub fn line_num(&self) -> usize { - self.line_num + pub fn add_lines_read(&mut self, lines_read: usize) { + self.lexer.line_num += lines_read; } - pub fn loc_to_err_src(&self) -> ParserErrorSrc { - ParserErrorSrc { - line_num: self.line_num, - col_num: self.col_num, - } + #[inline] + pub fn lines_read(&self) -> usize { + self.lexer.line_num } // on success, returns the parsed term and the number of lines read. @@ -1293,66 +1071,39 @@ impl<'a, R: CharRead> LexerParser<'a, R> { &mut self, op_dir: &CompositeOpDir, tokens: Tokens, - ) -> Result { - let (tokens, term_byte_size) = match tokens { - Tokens::Default => read_tokens(self)?, - Tokens::Provided(tokens, size) => (tokens, size), + ) -> Result { + self.tokens = match tokens { + Tokens::Default => read_tokens(&mut self.lexer)?, + Tokens::Provided(tokens) => tokens, }; - // the parser uses conditional indirection in many places so - // the reserved size should be at least 4 * term_byte_size - // so all cells are accounted for. - let writer = match self - .machine_st - .heap - .reserve(cell_index!(4 * term_byte_size)) - { - Ok(term) => term, - Err(_err_loc) => { - return Err(ParserError::ResourceError(self.loc_to_err_src())); - } - }; - - let before_len = writer.cell_len(); - - let mut parser_impl = Parser { - tokens, - stack: vec![], - terms: writer, - arena: &mut self.machine_st.arena, - flags: self.machine_st.flags, - line_num: &mut self.line_num, - col_num: &mut self.col_num, - var_locs: VarLocs::default(), - inverse_var_locs: InverseVarLocs::default(), - }; - - while let Some(token) = parser_impl.tokens.pop() { - parser_impl.shift_token(token, op_dir)?; + while let Some(token) = self.tokens.pop() { + self.shift_token(token, op_dir)?; } - parser_impl.reduce_op(1400); + self.reduce_op(1400); - let after_len = parser_impl.terms.cell_len(); - - debug_assert!(after_len - before_len <= cell_index!(4 * term_byte_size)); - - if parser_impl.stack.len() > 1 || parser_impl.terms.is_empty() { + if self.terms.len() > 1 || self.stack.len() > 1 { return Err(ParserError::IncompleteReduction( - parser_impl.loc_to_err_src(), + self.lexer.line_num, + self.lexer.col_num, )); } - match parser_impl.stack.pop() { - Some(TokenDesc { - tt: TokenType::Term { heap_loc }, - .. - }) => Ok(TermWriteResult { - focus: heap_loc.get_value() as usize, - inverse_var_locs: parser_impl.inverse_var_locs, - }), + match self.terms.pop() { + Some(term) => { + if self.terms.is_empty() { + Ok(term) + } else { + Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } + } _ => Err(ParserError::IncompleteReduction( - parser_impl.loc_to_err_src(), + self.lexer.line_num, + self.lexer.col_num, )), } } diff --git a/src/raw_block.rs b/src/raw_block.rs index 9e3b4a7b..da757415 100644 --- a/src/raw_block.rs +++ b/src/raw_block.rs @@ -19,7 +19,7 @@ pub struct RawBlock { impl RawBlock { #[inline] - pub(crate) fn empty_block() -> Self { + fn empty_block() -> Self { RawBlock { base: ptr::null(), top: ptr::null(), diff --git a/src/read.rs b/src/read.rs index 549cdef0..7b476b3e 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,14 +1,21 @@ use crate::parser::ast::*; +use crate::parser::lexer::Lexer; use crate::parser::parser::*; use crate::atom_table::*; +use crate::forms::*; +use crate::iterators::*; +use crate::machine::heap::*; use crate::machine::machine_errors::*; +use crate::machine::machine_indices::*; use crate::machine::machine_state::MachineState; use crate::machine::streams::*; use crate::parser::char_reader::*; -use crate::parser::lexer::LexerParser; #[cfg(feature = "repl")] use crate::repl_helper::Helper; +use crate::types::*; + +use fxhash::FxBuildHasher; #[cfg(feature = "repl")] use rustyline::error::ReadlineError; @@ -17,13 +24,16 @@ use rustyline::history::DefaultHistory; #[cfg(feature = "repl")] use rustyline::{Config, Editor}; +use std::collections::VecDeque; use std::io::{Cursor, Read}; #[cfg(feature = "repl")] use std::io::{Error, ErrorKind}; use std::sync::Arc; +type SubtermDeque = VecDeque<(usize, usize)>; + pub(crate) fn devour_whitespace( - lexer: &mut LexerParser<'_, R>, + lexer: &mut Lexer<'_, R>, ) -> Result { match lexer.scan_for_layout() { Err(e) if e.is_unexpected_eof() => Ok(true), @@ -32,16 +42,18 @@ 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 ParserErrorSrc { line_num, col_num } = err.err_src(); + let line_num = parser.lexer.line_num; + let col_num = parser.lexer.col_num; // rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here if !(line_num == prior_num_lines_read && col_num == 0) { - return CompilationError::from(ParserError::IncompleteReduction(err.err_src())); + return CompilationError::from(ParserError::IncompleteReduction(line_num, col_num)); } } @@ -49,37 +61,27 @@ pub(crate) fn error_after_read_term( } impl MachineState { - pub(crate) fn read( - &mut self, - inner: R, - op_dir: &OpDir, - ) -> Result<(TermWriteResult, usize), ParserError> { - let mut lexer_parser = LexerParser::new(inner, self); - let op_dir = CompositeOpDir::new(op_dir, None); - - let term_result = lexer_parser.read_term(&op_dir, Tokens::Default); - let lines_read = lexer_parser.line_num(); - - term_result.map(|term| (term, lines_read)) - } - - pub(crate) fn read_to_heap( + pub(crate) fn read( &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)); - } + 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); + + parser.add_lines_read(prior_num_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, parser.lines_read() - prior_num_lines_read) }; - Ok(term) + inner.add_lines_read(num_lines_read); + write_term_to_heap(&term, &mut self.heap) } } @@ -278,6 +280,7 @@ impl CharRead for ReadlineStream { } } } + #[inline] fn consume(&mut self, nread: usize) { self.pending_input.consume(nread); @@ -288,3 +291,217 @@ impl CharRead for ReadlineStream { self.pending_input.put_back_char(c); } } + +#[inline] +pub(crate) fn write_term_to_heap( + term: &Term, + heap: &mut Heap, +) -> Result { + let term_writer = TermWriter::new(heap); + term_writer.write_term_to_heap(term) +} + +#[derive(Debug)] +struct TermWriter<'a> { + heap: &'a mut Heap, + queue: SubtermDeque, + var_dict: HeapVarDict, +} + +#[derive(Debug)] +pub struct TermWriteResult { + pub heap_loc: usize, + pub var_dict: HeapVarDict, +} + +impl<'a> TermWriter<'a> { + #[inline] + fn new(heap: &'a mut Heap) -> Self { + TermWriter { + heap, + queue: SubtermDeque::new(), + var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()), + } + } + + #[inline] + fn modify_head_of_queue(&mut self, term: &TermRef, h: usize) { + if let Some((arity, site_h)) = self.queue.pop_front() { + self.heap[site_h] = self.term_as_addr(term, h); + + if arity > 1 { + self.queue.push_front((arity - 1, site_h + 1)); + } + } + } + + #[inline] + fn push_stub_addr(&mut self) -> Result<(), CompilationError> { + let h = self.heap.cell_len(); + self.push_cell(heap_loc_as_cell!(h)) + } + + #[inline] + fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), CompilationError> { + self.heap + .push_cell(cell) + .map_err(|h| CompilationError::FiniteMemoryInHeap(h)) + } + + fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue { + match term { + &TermRef::Cons(..) => list_loc_as_cell!(h), + &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h), + TermRef::PartialString(..) | TermRef::CompleteString(..) => heap_loc_as_cell!(h), + &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal), + &TermRef::Clause(_, _, _, subterms) if subterms.is_empty() => heap_loc_as_cell!(h), + &TermRef::Clause(..) => str_loc_as_cell!(h), + } + } + + fn write_term_to_heap(mut self, term: &Term) -> Result { + let heap_loc = self.heap.cell_len(); + + for term in breadth_first_iter(term, RootIterationPolicy::Iterated) { + let h = self.heap.cell_len(); + + match &term { + &TermRef::Cons(Level::Root, ..) => { + self.queue.push_back((2, h + 1)); + self.push_cell(list_loc_as_cell!(h + 1))?; + + self.push_stub_addr()?; + self.push_stub_addr()?; + + continue; + } + &TermRef::Cons(..) => { + self.queue.push_back((2, h)); + + self.push_stub_addr()?; + self.push_stub_addr()?; + } + &TermRef::Clause(Level::Root, _, name, subterms) => { + if subterms.len() > MAX_ARITY { + return Err(CompilationError::ExceededMaxArity); + } + + self.push_cell(if subterms.is_empty() { + heap_loc_as_cell!(heap_loc + 1) + } else { + str_loc_as_cell!(heap_loc + 1) + })?; + + self.queue.push_back((subterms.len(), h + 2)); + let named = atom_as_cell!(name, subterms.len()); + + self.push_cell(named)?; + + for _ in 0..subterms.len() { + self.push_stub_addr()?; + } + + continue; + } + &TermRef::Clause(_, _, name, subterms) => { + self.queue.push_back((subterms.len(), h + 1)); + let named = atom_as_cell!(name, subterms.len()); + + self.push_cell(named)?; + + for _ in 0..subterms.len() { + self.push_stub_addr()?; + } + } + &TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => { + let addr = self.term_as_addr(&term, h); + self.push_cell(addr)?; + } + &TermRef::Var(Level::Root, _, ref var_ptr) => { + let addr = self.term_as_addr(&term, h); + self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr); + self.push_cell(addr)?; + } + &TermRef::AnonVar(_) => { + if let Some((arity, site_h)) = self.queue.pop_front() { + self.var_dict + .insert(VarKey::AnonVar(h), heap_loc_as_cell!(site_h)); + + if arity > 1 { + self.queue.push_front((arity - 1, site_h + 1)); + } + } + + continue; + } + TermRef::CompleteString(lvl, _, src) => { + let cell = self + .heap + .allocate_cstr(src) + .map_err(CompilationError::FiniteMemoryInHeap)?; + + let h = self.heap.cell_len(); + self.push_cell(cell)?; + + if !matches!(lvl, Level::Root) { + self.modify_head_of_queue(&term, h); + } + + continue; + } + TermRef::PartialString(lvl, _, src, _) => { + if let Level::Root = lvl { + self.push_stub_addr()?; + } + + let cell = self + .heap + .allocate_pstr(src) + .map_err(CompilationError::FiniteMemoryInHeap)?; + + let tail_h = self.heap.cell_len(); + self.push_stub_addr()?; + + if let Level::Root = lvl { + self.heap[h] = cell; + } else { + self.push_cell(cell)?; + }; + + self.queue.push_back((1, tail_h)); + + if !matches!(lvl, Level::Root) { + self.modify_head_of_queue(&term, tail_h + 1); + } + + continue; + } + TermRef::Var(.., var) => { + if let Some((arity, site_h)) = self.queue.pop_front() { + let var_key = VarKey::VarPtr(var.clone()); + + if let Some(addr) = self.var_dict.get(&var_key).cloned() { + self.heap[site_h] = addr; + } else { + self.var_dict.insert(var_key, heap_loc_as_cell!(site_h)); + } + + if arity > 1 { + self.queue.push_front((arity - 1, site_h + 1)); + } + } + + continue; + } + _ => {} + }; + + self.modify_head_of_queue(&term, h); + } + + Ok(TermWriteResult { + heap_loc, + var_dict: self.var_dict, + }) + } +} diff --git a/src/targets.rs b/src/targets.rs index bea12f5c..dbb036c2 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -3,6 +3,7 @@ use crate::parser::ast::*; use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; +use crate::iterators::*; use crate::types::*; use std::rc::Rc; @@ -11,7 +12,11 @@ pub(crate) struct FactInstruction; pub(crate) struct QueryInstruction; pub(crate) trait CompilationTarget<'a> { - fn to_constant(lvl: Level, cell: HeapCellValue, r: RegType) -> Instruction; + type Iterator: Iterator>; + + fn iter(term: &'a Term) -> Self::Iterator; + + fn to_constant(lvl: Level, constant: Literal, r: RegType) -> Instruction; fn to_list(lvl: Level, r: RegType) -> Instruction; fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction; @@ -22,7 +27,7 @@ pub(crate) trait CompilationTarget<'a> { fn incr_void_instr(instr: &mut Instruction); - fn constant_subterm(literal: HeapCellValue) -> Instruction; + fn constant_subterm(literal: Literal) -> Instruction; fn argument_to_variable(r: RegType, r: usize) -> Instruction; fn argument_to_value(r: RegType, val: usize) -> Instruction; @@ -38,8 +43,14 @@ pub(crate) trait CompilationTarget<'a> { } impl<'a> CompilationTarget<'a> for FactInstruction { - fn to_constant(lvl: Level, cell: HeapCellValue, reg: RegType) -> Instruction { - Instruction::GetConstant(lvl, cell, reg) + type Iterator = FactIterator<'a>; + + fn iter(term: &'a Term) -> Self::Iterator { + breadth_first_iter(term, RootIterationPolicy::NotIterated) + } + + fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { + Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg) } fn to_structure(lvl: Level, name: Atom, arity: usize, reg: RegType) -> Instruction { @@ -68,8 +79,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } } - fn constant_subterm(constant: HeapCellValue) -> Instruction { - Instruction::UnifyConstant(constant) + fn constant_subterm(constant: Literal) -> Instruction { + Instruction::UnifyConstant(HeapCellValue::from(constant)) } fn argument_to_variable(arg: RegType, val: usize) -> Instruction { @@ -106,8 +117,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } impl<'a> CompilationTarget<'a> for QueryInstruction { - fn to_constant(lvl: Level, constant: HeapCellValue, reg: RegType) -> Instruction { - Instruction::PutConstant(lvl, constant, reg) + type Iterator = QueryIterator<'a>; + + fn iter(term: &'a Term) -> Self::Iterator { + post_order_iter(term) } fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction { @@ -136,8 +149,12 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { } } - fn constant_subterm(constant: HeapCellValue) -> Instruction { - Instruction::SetConstant(constant) + fn constant_subterm(constant: Literal) -> Instruction { + Instruction::SetConstant(HeapCellValue::from(constant)) + } + + fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { + Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg) } fn argument_to_variable(arg: RegType, val: usize) -> Instruction { diff --git a/src/tests/builtins.pl b/src/tests/builtins.pl index 1a437413..a87fc22a 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/tests/call_with_inference_limit.pl b/src/tests/call_with_inference_limit.pl index 7a093019..18fda2dd 100644 --- a/src/tests/call_with_inference_limit.pl +++ b/src/tests/call_with_inference_limit.pl @@ -30,7 +30,7 @@ test_queries_on_call_with_inference_limit :- [true, 4], [!, 5]]), findall([R,X], - (call_with_inference_limit(g(X), 2, R), call(true)), + (call_with_inference_limit(g(X), 5, R), call(true)), [[true, 1], [true, 2], [inference_limit_exceeded, _]]), diff --git a/src/types.rs b/src/types.rs index 67e482cc..188f0974 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,6 +7,7 @@ use crate::machine::heap::*; use crate::machine::machine_indices::*; use crate::machine::streams::*; use crate::parser::ast::Fixnum; +use crate::parser::ast::Literal; use std::cmp::Ordering; use std::convert::TryFrom; @@ -14,6 +15,8 @@ use std::fmt; use std::mem; use std::ops::{Add, Sub, SubAssign}; +use dashu::{Integer, Rational}; + #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[repr(u8)] #[bits = 6] @@ -307,6 +310,67 @@ impl fmt::Debug for HeapCellValue { } } +impl From for HeapCellValue { + #[inline] + fn from(literal: Literal) -> Self { + match literal { + Literal::Atom(name) => atom_as_cell!(name), + Literal::CodeIndex(ptr) => { + untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr)) + } + Literal::Fixnum(n) => fixnum_as_cell!(n), + Literal::Integer(bigint_ptr) => { + typed_arena_ptr_as_cell!(bigint_ptr) + } + Literal::Rational(bigint_ptr) => { + typed_arena_ptr_as_cell!(bigint_ptr) + } + Literal::Float(f) => HeapCellValue::from(f.as_ptr()), + } + } +} + +impl TryFrom for Literal { + type Error = (); + + fn try_from(value: HeapCellValue) -> Result { + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + Ok(Literal::Atom(name)) + } else { + Err(()) + } + } + (HeapCellValueTag::Fixnum, n) => { + Ok(Literal::Fixnum(n)) + } + (HeapCellValueTag::F64, f) => { + Ok(Literal::Float(f.as_offset())) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Integer, n) => { + Ok(Literal::Integer(n)) + } + (ArenaHeaderTag::Rational, n) => { + Ok(Literal::Rational(n)) + } + (ArenaHeaderTag::IndexPtr, ip) => { + Ok(Literal::CodeIndex(CodeIndex::from(ip))) + } + _ => { + Err(()) + } + ) + } + _ => { + Err(()) + } + ) + } +} + impl From> for HeapCellValue where T::Payload: Sized, diff --git a/src/variable_records.rs b/src/variable_records.rs index a22e5be1..c918067e 100644 --- a/src/variable_records.rs +++ b/src/variable_records.rs @@ -88,10 +88,7 @@ pub enum VarAlloc { safety: VarSafetyStatus, to_perm_var_num: Option, }, - Perm { - reg: usize, - allocation: PermVarAllocation, - }, // stack offset, allocation info + Perm(usize, PermVarAllocation), // stack offset, allocation info } impl VarAlloc { @@ -99,14 +96,14 @@ impl VarAlloc { pub(crate) fn as_reg_type(&self) -> RegType { match *self { VarAlloc::Temp { temp_reg, .. } => RegType::Temp(temp_reg), - VarAlloc::Perm { reg, .. } => RegType::Perm(reg), + VarAlloc::Perm(r, _) => RegType::Perm(r), } } #[inline] pub(crate) fn set_register(&mut self, reg_num: usize) { match self { - VarAlloc::Perm { ref mut reg, .. } => *reg = reg_num, + VarAlloc::Perm(ref mut p, _) => *p = reg_num, VarAlloc::Temp { ref mut temp_reg, .. } => *temp_reg = reg_num, @@ -155,10 +152,7 @@ pub struct VariableRecord { impl Default for VariableRecord { fn default() -> Self { VariableRecord { - allocation: VarAlloc::Perm { - reg: 0, - allocation: PermVarAllocation::Pending, - }, + allocation: VarAlloc::Perm(0, PermVarAllocation::Pending), num_occurrences: 0, running_count: 0, } diff --git a/tests-pl/iso-conformity-tests.pl b/tests-pl/iso-conformity-tests.pl index 10b85c10..eea347cc 100644 --- a/tests-pl/iso-conformity-tests.pl +++ b/tests-pl/iso-conformity-tests.pl @@ -761,7 +761,8 @@ test_171 :- writeq_term_to_chars("a", C), test_229 :- test_syntax_error("\"\\z.\"", syntax_error(missing_quote)). -test_300 :- writeq_term_to_chars("\0\", C), +test_300 :- '$debug_hook', + writeq_term_to_chars("\0\", C), C == "['\\x0\\']". test_172 :- X is 10.0** -323, diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index a187f14d..f0edd5d8 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:3).\n", + " error(syntax_error(incomplete_reduction),read_term/3:6).\n", ); } From 22080f378702719ead725af83173ad960f0e76c6 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 6 Apr 2025 12:11:57 -0700 Subject: [PATCH 018/122] move CodeIndex to F64Table-like table --- Cargo.toml | 1 + src/arena.rs | 342 +----------------------- src/arithmetic.rs | 1 + src/heap_print.rs | 17 +- src/lib.rs | 1 + src/machine/arithmetic_ops.rs | 1 + src/machine/dispatch.rs | 4 +- src/machine/lib_machine/mod.rs | 4 +- src/machine/load_state.rs | 4 +- src/machine/loader.rs | 119 ++++----- src/machine/machine_indices.rs | 64 ++--- src/machine/machine_state_impl.rs | 1 + src/machine/mod.rs | 10 +- src/machine/system_calls.rs | 17 +- src/machine/unify.rs | 1 + src/macros.rs | 28 +- src/offset_table.rs | 428 ++++++++++++++++++++++++++++++ src/parser/ast.rs | 4 +- src/parser/lexer.rs | 2 + src/parser/parser.rs | 2 + src/types.rs | 34 ++- 21 files changed, 584 insertions(+), 501 deletions(-) create mode 100644 src/offset_table.rs diff --git a/Cargo.toml b/Cargo.toml index e7b7f930..22609228 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -136,6 +136,7 @@ opt-level = 3 [profile.release] lto = true opt-level = 3 +debug = 2 [profile.wasm-dev] inherits = "dev" diff --git a/src/arena.rs b/src/arena.rs index fbb9999f..47de6fa3 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -3,20 +3,14 @@ #[cfg(feature = "http")] use crate::http::{HttpListener, HttpResponse}; use crate::machine::loader::LiveLoadState; -use crate::machine::machine_indices::*; use crate::machine::streams::*; -use crate::raw_block::*; +use crate::offset_table::*; use crate::read::*; use crate::types::UntypedArenaPtr; use crate::parser::dashu::{Integer, Rational}; -use arcu::atomic::Arcu; -use arcu::epoch_counters::GlobalEpochCounterPool; -use arcu::rcu_ref::RcuRef; -use arcu::Rcu; use ordered_float::OrderedFloat; -use std::cell::UnsafeCell; use std::fmt; use std::fmt::Debug; use std::hash::{Hash, Hasher}; @@ -27,7 +21,7 @@ use std::ops::{Deref, DerefMut}; use std::ptr; use std::ptr::addr_of_mut; use std::ptr::NonNull; -use std::sync::RwLock; +use std::sync::Arc; macro_rules! arena_alloc { ($e:expr, $arena:expr) => {{ @@ -39,7 +33,7 @@ macro_rules! arena_alloc { macro_rules! float_alloc { ($e:expr, $arena:expr) => {{ let result = $e; - unsafe { $arena.f64_tbl.build_with(result).as_ptr() } + unsafe { $arena.f64_tbl.build_with(OrderedFloat(result)).as_ptr() } }}; } @@ -55,120 +49,6 @@ where payload_offset - header_offset } -use std::sync::Arc; -use std::sync::Mutex; -use std::sync::Weak; - -const F64_TABLE_INIT_SIZE: usize = 1 << 16; -const F64_TABLE_ALIGN: usize = 8; - -#[inline(always)] -fn global_f64table() -> &'static RwLock> { - static GLOBAL_ATOM_TABLE: RwLock> = RwLock::new(Weak::new()); - &GLOBAL_ATOM_TABLE -} - -impl RawBlockTraits for F64Table { - #[inline] - fn init_size() -> usize { - F64_TABLE_INIT_SIZE - } - - #[inline] - fn align() -> usize { - F64_TABLE_ALIGN - } -} - -#[derive(Debug)] -pub struct F64Table { - block: Arcu, GlobalEpochCounterPool>, - update: Mutex<()>, -} - -// TODO: Actually prove this, as it's probably unsound right now -unsafe impl Send for F64Table {} -unsafe impl Sync for F64Table {} - -#[inline(always)] -pub fn lookup_float( - offset: F64Offset, -) -> RcuRef, UnsafeCell>> { - let f64table = global_f64table() - .read() - .unwrap() - .upgrade() - .expect("We should only be looking up floats while there is a float table"); - - RcuRef::try_map(f64table.block.read(), |raw_block| unsafe { - raw_block - .base - .add(offset.0) - .cast_mut() - .cast::>>() - .as_ref() - }) - .expect("The offset should result in a non-null pointer") -} - -impl F64Table { - #[inline] - pub fn new() -> Arc { - let upgraded = global_f64table().read().unwrap().upgrade(); - // don't inline upgraded, otherwise temporary will be dropped too late in case of None - if let Some(atom_table) = upgraded { - atom_table - } else { - let mut guard = global_f64table().write().unwrap(); - // try to upgrade again in case we lost the race on the write lock - if let Some(atom_table) = guard.upgrade() { - atom_table - } else { - let atom_table = Arc::new(Self { - block: Arcu::new(RawBlock::new(), GlobalEpochCounterPool), - update: Mutex::new(()), - }); - *guard = Arc::downgrade(&atom_table); - atom_table - } - } - } - - #[allow(clippy::missing_safety_doc)] - pub unsafe fn build_with(&self, value: f64) -> F64Offset { - let update_guard = self.update.lock(); - - // we don't have an index table for lookups as AtomTable does so - // just get the epoch after we take the upgrade lock - let mut block_epoch = self.block.read(); - - let mut ptr; - - loop { - ptr = block_epoch.alloc(mem::size_of::()); - - if ptr.is_null() { - let new_block = block_epoch.grow_new().unwrap(); - self.block.replace(new_block); - block_epoch = self.block.read(); - } else { - break; - } - } - - ptr::write(ptr as *mut OrderedFloat, OrderedFloat(value)); - - let float = F64Offset(ptr as usize - block_epoch.base as usize); - - // atometable would have to update the index table at this point - - // expicit drop to ensure we don't accidentally drop it early - drop(update_guard); - - float - } -} - #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)] #[bits = 7] pub enum ArenaHeaderTag { @@ -194,10 +74,6 @@ pub enum ArenaHeaderTag { HttpListener = 0b1000001, HttpResponse = 0b1000010, Dropped = 0b1000100, - IndexPtrDynamicUndefined = 0b1000101, - IndexPtrDynamicIndex = 0b1000110, - IndexPtrIndex = 0b1000111, - IndexPtrUndefined = 0b1001000, } #[bitfield] @@ -436,137 +312,6 @@ pub trait ArenaAllocated { } } -#[derive(Debug)] -pub struct F64Ptr(RcuRef, UnsafeCell>>); - -impl Clone for F64Ptr { - fn clone(&self) -> Self { - Self(RcuRef::clone(&self.0)) - } -} - -impl PartialEq for F64Ptr { - fn eq(&self, other: &F64Ptr) -> bool { - RcuRef::ptr_eq(&self.0, &other.0) || self.deref() == other.deref() - } -} - -impl Eq for F64Ptr {} - -impl PartialOrd for F64Ptr { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for F64Ptr { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - (**self).cmp(&**other) - } -} - -impl Hash for F64Ptr { - #[inline(always)] - fn hash(&self, hasher: &mut H) { - (self as &OrderedFloat).hash(hasher) - } -} - -impl fmt::Display for F64Ptr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self as &OrderedFloat) - } -} - -impl Deref for F64Ptr { - type Target = OrderedFloat; - - #[inline] - fn deref(&self) -> &Self::Target { - unsafe { self.0.get().as_ref().unwrap() } - } -} - -impl DerefMut for F64Ptr { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.0.get().as_mut().unwrap() } - } -} - -impl F64Ptr { - #[inline(always)] - pub fn from_offset(offset: F64Offset) -> Self { - Self(lookup_float(offset)) - } - - #[inline(always)] - pub fn as_offset(&self) -> F64Offset { - F64Offset(self.0.get() as usize - RcuRef::get_root(&self.0).base as usize) - } -} - -#[derive(Clone, Copy, Debug)] -pub struct F64Offset(usize); - -impl F64Offset { - #[inline(always)] - pub fn new(offset: usize) -> Self { - Self(offset) - } - - #[inline(always)] - pub fn from_ptr(ptr: F64Ptr) -> Self { - ptr.as_offset() - } - - #[inline(always)] - pub fn as_ptr(self) -> F64Ptr { - F64Ptr::from_offset(self) - } - - #[inline(always)] - pub fn to_u64(self) -> u64 { - self.0 as u64 - } -} - -impl PartialEq for F64Offset { - #[inline(always)] - fn eq(&self, other: &F64Offset) -> bool { - self.as_ptr() == other.as_ptr() - } -} - -impl Eq for F64Offset {} - -impl PartialOrd for F64Offset { - #[inline(always)] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for F64Offset { - #[inline(always)] - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.as_ptr().cmp(&other.as_ptr()) - } -} - -impl Hash for F64Offset { - #[inline(always)] - fn hash(&self, hasher: &mut H) { - self.as_ptr().hash(hasher) - } -} - -impl fmt::Display for F64Offset { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "F64Offset({})", self.0) - } -} - impl ArenaAllocated for Integer { type Payload = Self; #[inline] @@ -644,46 +389,6 @@ impl ArenaAllocated for HttpResponse { } } -impl ArenaAllocated for IndexPtr { - type Payload = Self; - #[inline] - fn tag() -> ArenaHeaderTag { - ArenaHeaderTag::IndexPtrUndefined - } - - #[inline] - fn header_offset_from_payload() -> usize { - 0 - } - - /// # Safety - /// - the caller must guarantee that the pointee type of UntypedArenaPtr is T - /// - the pointer must be non-null - unsafe fn typed_ptr(ptr: UntypedArenaPtr) -> TypedArenaPtr { - TypedArenaPtr(NonNull::new_unchecked( - ptr.get_ptr().cast_mut().cast::(), - )) - } - - #[inline] - fn alloc(arena: &mut Arena, value: Self) -> TypedArenaPtr { - let slab = Box::new(IndexPtrSlab { - next: arena.base.take(), - index_ptr: value, - }); - - let (allocated_ptr, untyped_slab) = slab.to_untyped(); - arena.base = Some(untyped_slab); - allocated_ptr - } - - /// # Safety - /// - ptr points to an allocated slab of the correct kind - unsafe fn dealloc(ptr: NonNull>) { - drop(unsafe { Box::from_raw(ptr.as_ptr().cast::()) }); - } -} - #[repr(C)] #[derive(Debug)] pub struct AllocSlab { @@ -691,13 +396,6 @@ pub struct AllocSlab { header: ArenaHeader, } -#[repr(C)] -#[derive(Debug)] -pub struct IndexPtrSlab { - next: Option, - index_ptr: IndexPtr, -} - const _: () = { if std::mem::align_of::() < std::mem::align_of::<*const ()>() { panic!("alignment of AllocSlab is too low"); @@ -706,34 +404,8 @@ const _: () = { if std::mem::offset_of!(AllocSlab, header) % std::mem::align_of::<*const ()>() != 0 { panic!("alignment of header not a multiple of pointers alignment"); } - - if std::mem::offset_of!(AllocSlab, header) != std::mem::offset_of!(IndexPtrSlab, index_ptr) { - panic!("IndexPtrSlab.index_ptr and AllocSlab.header are at different offsets"); - } }; -impl IndexPtrSlab { - #[inline] - pub fn to_untyped(self: Box) -> (TypedArenaPtr, UntypedArenaSlab) { - let raw_box = Box::into_raw(self); - - // safety: the pointer from Box::into_raw fullfills addr_of_mut's saftey requirements - let index_ptr_ptr = unsafe { ptr::addr_of_mut!((*raw_box).index_ptr) }; - let allocated_ptr = TypedArenaPtr( - // safety: the pointer points into a valid allocation so it is non null - unsafe { NonNull::new_unchecked(index_ptr_ptr) }, - ); - - let untyped_arena = UntypedArenaSlab { - // safety: pointer from Box::into_raw is never null - slab: unsafe { NonNull::new_unchecked(raw_box.cast::()) }, - tag: ::tag(), - }; - - (allocated_ptr, untyped_arena) - } -} - #[repr(C)] #[derive(Debug)] pub struct TypedAllocSlab { @@ -787,6 +459,7 @@ impl Drop for UntypedArenaSlab { pub struct Arena { base: Option, pub f64_tbl: Arc, + pub code_index_tbl: Arc, } unsafe impl Send for Arena {} @@ -799,6 +472,7 @@ impl Arena { Arena { base: None, f64_tbl: F64Table::new(), + code_index_tbl: CodeIndexTable::new(), } } } @@ -874,12 +548,6 @@ unsafe fn drop_slab_in_place(value: NonNull, tag: ArenaHeaderTag) { ArenaHeaderTag::StandardErrorStream => { drop_typed_slab_in_place!(StandardErrorStream, value); } - ArenaHeaderTag::IndexPtrUndefined - | ArenaHeaderTag::IndexPtrDynamicUndefined - | ArenaHeaderTag::IndexPtrDynamicIndex - | ArenaHeaderTag::IndexPtrIndex => { - drop_typed_slab_in_place!(IndexPtr, value); - } ArenaHeaderTag::NullStream => { unreachable!("NullStream is never arena allocated!"); } diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 4863932a..2bdcc315 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -7,6 +7,7 @@ use crate::debray_allocator::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::*; +use crate::offset_table::*; use crate::targets::QueryInstruction; use crate::types::*; diff --git a/src/heap_print.rs b/src/heap_print.rs index 8c39b41e..f11fb4d5 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -12,6 +12,7 @@ use crate::machine::machine_indices::*; use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::streams::*; +use crate::offset_table::*; use crate::types::*; use dashu::base::Signed; @@ -1506,21 +1507,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - fn print_index_ptr(&mut self, index_ptr: IndexPtr, max_depth: usize) { + fn print_index_ptr(&mut self, idx: CodeIndex, max_depth: usize) { if self.format_struct(max_depth, 1, atom!("$index_ptr")) { let atom = self.state_stack.pop().unwrap(); self.state_stack.pop(); self.state_stack.pop(); - let offset = if index_ptr.is_undefined() || index_ptr.is_dynamic_undefined() { + let idx_ptr = idx.as_ptr(); + + let offset = if idx_ptr.is_undefined() || idx_ptr.is_dynamic_undefined() { TokenOrRedirect::Atom(atom!("undefined")) } else { - let idx = index_ptr.p() as i64; + let idx_ptr_p = idx_ptr.p() as i64; TokenOrRedirect::NumberFocus( max_depth, - NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx))), + NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx_ptr_p))), None, ) }; @@ -1707,6 +1710,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }); } } + (HeapCellValueTag::CodeIndex, idx) => { + self.print_index_ptr(idx, self.max_depth); + } (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => { self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op); } @@ -1750,9 +1756,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { (ArenaHeaderTag::Dropped, _value) => { self.print_impromptu_atom(atom!("$dropped_value")); } - (ArenaHeaderTag::IndexPtr, index_ptr) => { - self.print_index_ptr(*index_ptr, max_depth); - } _ => { } ); diff --git a/src/lib.rs b/src/lib.rs index 1926c7df..598110ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ pub(crate) mod macros; pub(crate) mod atom_table; #[macro_use] pub(crate) mod arena; +pub(crate) mod offset_table; #[macro_use] pub(crate) mod parser; #[macro_use] diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index f7bd69ef..43bb3723 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -11,6 +11,7 @@ use crate::forms::*; use crate::heap_iter::*; use crate::machine::machine_errors::*; use crate::machine::machine_state::*; +use crate::offset_table::*; use crate::parser::ast::*; use crate::parser::dashu::{Integer, Rational}; use crate::types::*; diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index f1519986..4c9db0e8 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -610,7 +610,7 @@ impl Machine { .indices .code_dir .get_index(predicate_idx) - .map(|x| x.1.p() as usize) + .map(|x| x.1.as_ptr().p() as usize) .unwrap(); debug_assert!(current_pred_start <= p); @@ -619,7 +619,7 @@ impl Machine { .indices .code_dir .get_index(predicate_idx + 1) - .map(|x| x.1.p() as usize) + .map(|x| x.1.as_ptr().p() as usize) .unwrap_or(self.code.len()); debug_assert!(current_pred_end >= p); diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index 66c1783a..d11419e0 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -7,9 +7,9 @@ use crate::heap_iter::{stackful_post_order_iter, NonListElider}; use crate::machine::machine_indices::VarKey; use crate::machine::mock_wam::CompositeOpDir; use crate::machine::{ - ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, - LIB_QUERY_SUCCESS, + ArenaHeaderTag, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS, }; +use crate::offset_table::*; use crate::parser::ast::{Var, VarPtr}; use crate::parser::parser::{Parser, Tokens}; use crate::read::{write_term_to_heap, TermWriteResult}; diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 64d0bb82..0a712c1a 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -147,7 +147,7 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>( src_code_index.get(), ); - if src_code_index.is_dynamic_undefined() { + if src_code_index.as_ptr().is_dynamic_undefined() { code_dir.insert(key, src_code_index); } } else { @@ -486,7 +486,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { continue; } - if !code_index.is_undefined() && !code_index.is_dynamic_undefined() { + if !code_index.as_ptr().is_undefined() && !code_index.as_ptr().is_dynamic_undefined() { let old_index_ptr = code_index.replace(IndexPtr::undefined()); self.payload.retraction_info.push_record( diff --git a/src/machine/loader.rs b/src/machine/loader.rs index c117887b..89b83ed3 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1219,7 +1219,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let code_index = self.get_or_insert_code_index(key, compilation_target); - if code_index.is_undefined() { + if code_index.as_ptr().is_undefined() { set_code_index( &mut self.payload.retraction_info, &compilation_target, @@ -1378,73 +1378,72 @@ impl MachineState { while let Some(addr) = iter.next() { let addr = unmark_cell_bits!(addr); - if let Ok(literal) = Literal::try_from(addr) { - term_stack.push(Term::Literal(Cell::default(), literal)); - } else { - read_heap_cell!(addr, - (HeapCellValueTag::Lis) => { - use crate::parser::parser::as_partial_string; + 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(); + let tail = term_stack.pop().unwrap(); + let head = term_stack.pop().unwrap(); - match as_partial_string(head, tail) { - Ok((string, Some(tail))) => { - term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail)); - } - Ok((string, None)) => { - term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string))); - } - Err(cons_term) => term_stack.push(cons_term), + match as_partial_string(head, tail) { + Ok((string, Some(tail))) => { + term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail)); } - } - (HeapCellValueTag::StackVar, h) => { - term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h)))); - } - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { - term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h)))); - } - (HeapCellValueTag::Atom, (name, arity)) => { - let h = iter.focus().value() as usize; - let mut arity = arity; - let value = iter.heap[h.saturating_sub(1)]; - - if let Some(idx) = get_structure_index(value) { - term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx))); - arity += 1; - } - - if arity == 0 { - term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); - } else { - let subterms = term_stack - .drain(term_stack.len() - arity ..) - .collect(); - - term_stack.push(Term::Clause(Cell::default(), name, subterms)); + Ok((string, None)) => { + term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string))); } + Err(cons_term) => term_stack.push(cons_term), } - (HeapCellValueTag::PStrLoc, h) => { - let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h); - let tail = term_stack.pop().unwrap(); + } + (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64) => { + term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap())); + } + (HeapCellValueTag::StackVar, h) => { + term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h)))); + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { + term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h)))); + } + (HeapCellValueTag::Atom, (name, arity)) => { + let h = iter.focus().value() as usize; + let mut arity = arity; + let value = iter.heap[h.saturating_sub(1)]; - term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) { - Term::CompleteString( - Cell::default(), - Rc::new(string.to_owned()), - ) - } else { - Term::PartialString( - Cell::default(), - Rc::new(string.to_owned()), - Box::new(tail), - ) - }); + if let Some(idx) = get_structure_index(value) { + term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx))); + arity += 1; } - _ => { + + if arity == 0 { + term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); + } else { + let subterms = term_stack + .drain(term_stack.len() - arity ..) + .collect(); + + term_stack.push(Term::Clause(Cell::default(), name, subterms)); } - ); - } + } + (HeapCellValueTag::PStrLoc, h) => { + let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h); + let tail = term_stack.pop().unwrap(); + + term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) { + Term::CompleteString( + Cell::default(), + Rc::new(string.to_owned()), + ) + } else { + Term::PartialString( + Cell::default(), + Rc::new(string.to_owned()), + Box::new(tail), + ) + }); + } + _ => { + } + ); } debug_assert!(term_stack.len() == 1); diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index d4a10a8c..8dc5291f 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -10,6 +10,7 @@ use crate::machine::machine_state::*; use crate::machine::streams::{Stream, StreamOptions}; use crate::machine::ClauseType; use crate::machine::MachineStubGen; +use crate::offset_table::*; use fxhash::FxBuildHasher; use indexmap::{IndexMap, IndexSet}; @@ -18,7 +19,7 @@ use scryer_modular_bitfield::{bitfield, BitfieldSpecifier}; use std::cmp::Ordering; use std::collections::BTreeSet; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use crate::types::*; @@ -129,7 +130,7 @@ impl IndexPtr { } #[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)] -pub struct CodeIndex(TypedArenaPtr); +pub struct CodeIndex(CodeIndexOffset); #[cfg(target_pointer_width = "32")] const_assert!(std::mem::align_of::() == 4); @@ -137,47 +138,24 @@ const_assert!(std::mem::align_of::() == 4); #[cfg(target_pointer_width = "64")] const_assert!(std::mem::align_of::() == 8); -impl Deref for CodeIndex { - type Target = TypedArenaPtr; - - #[inline(always)] - fn deref(&self) -> &TypedArenaPtr { - &self.0 - } -} - -impl DerefMut for CodeIndex { - #[inline(always)] - fn deref_mut(&mut self) -> &mut TypedArenaPtr { - &mut self.0 - } -} - -impl From for UntypedArenaPtr { - #[inline(always)] - fn from(ptr: CodeIndex) -> UntypedArenaPtr { - UntypedArenaPtr::build_with(ptr.0.as_ptr() as usize) - } -} - -impl From> for CodeIndex { - #[inline(always)] - fn from(ptr: TypedArenaPtr) -> CodeIndex { - CodeIndex(ptr) - } -} - impl From for HeapCellValue { #[inline(always)] fn from(idx: CodeIndex) -> HeapCellValue { - untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)) + HeapCellValue::from(idx.as_ptr()) + } +} + +impl From for CodeIndex { + #[inline(always)] + fn from(offset: CodeIndexOffset) -> CodeIndex { + CodeIndex(offset) } } impl CodeIndex { #[inline] pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self { - CodeIndex(arena_alloc!(ptr, arena)) + unsafe { CodeIndex(arena.code_index_tbl.build_with(ptr)) } } #[inline(always)] @@ -186,39 +164,37 @@ impl CodeIndex { } pub(crate) fn local(&self) -> Option { - match self.0.tag() { - IndexPtrTag::Index => Some(self.0.p() as usize), - IndexPtrTag::DynamicIndex => Some(self.0.p() as usize), + match self.0.as_ptr().tag() { + IndexPtrTag::Index => Some(self.get().p() as usize), + IndexPtrTag::DynamicIndex => Some(self.get().p() as usize), _ => None, } } #[inline(always)] pub(crate) fn get(&self) -> IndexPtr { - *self.0.deref() + *self.as_ptr().deref() } #[inline(always)] pub(crate) fn set(&mut self, value: IndexPtr) { - *self.0.deref_mut() = value; + self.as_ptr().set(value); } #[inline(always)] pub(crate) fn get_tag(self) -> IndexPtrTag { - self.0.tag() + self.get().tag() } #[inline(always)] pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr { - std::mem::replace(self.0.deref_mut(), value) + self.as_ptr().replace(value) } - /* #[inline(always)] - pub(crate) fn as_ptr(&self) -> *const IndexPtr { + pub(crate) fn as_ptr(&self) -> CodeIndexPtr { self.0.as_ptr() } - */ } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index bd041f36..66d3237b 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -11,6 +11,7 @@ use crate::machine::machine_state::*; use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::unify::*; +use crate::offset_table::*; use crate::parser::ast::*; use crate::parser::dashu::{Integer, Rational}; use crate::types::*; diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 98b70ca6..c0dcb6e4 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -45,6 +45,7 @@ use crate::machine::machine_indices::*; use crate::machine::machine_state::*; use crate::machine::stack::*; use crate::machine::streams::*; +use crate::offset_table::*; use crate::parser::ast::*; use crate::parser::dashu::{Integer, Rational}; use crate::types::*; @@ -207,13 +208,8 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) { #[inline] pub(crate) fn get_structure_index(value: HeapCellValue) -> Option { read_heap_cell!(value, - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::IndexPtr, ip) => { - return Some(CodeIndex::from(ip)); - } - _ => {} - ); + (HeapCellValueTag::CodeIndex, ip) => { + return Some(ip); } _ => { } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index c85bc7b6..554ffdb9 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1454,7 +1454,7 @@ impl Machine { }; if let Some(code_index) = index_cell { - if !code_index.is_undefined() { + if !code_index.as_ptr().is_undefined() { load_registers(&mut self.machine_st, goal, goal_arity); self.machine_st.neck_cut(); return call_at_index(self, name, arity, code_index.get()); @@ -1603,8 +1603,7 @@ impl Machine { let expanded_term = if result.is_simple_goal { let idx = self.get_or_insert_qualified_code_index(module_name, result.key); - self.machine_st.heap[result.index_ptr_loc] = - untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)); + self.machine_st.heap[result.index_ptr_loc] = HeapCellValue::from(idx); result.goal } else { let mut unexpanded_vars = IndexSet::with_hasher(FxBuildHasher::default()); @@ -1642,7 +1641,7 @@ impl Machine { ); writer.write_with(|section| { - section.push_cell(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))); + section.push_cell(HeapCellValue::from(idx)); section.push_cell(atom_as_cell!(atom!("$aux"), 0)); for value in unexpanded_vars.difference(&result.supp_vars).cloned() { @@ -1679,14 +1678,8 @@ impl Machine { let idx_cell = self.machine_st.heap[s.saturating_sub(1)]; - if HeapCellValueTag::Cons == idx_cell.get_tag() { - match_untyped_arena_ptr!(cell_as_untyped_arena_ptr!(idx_cell), - (ArenaHeaderTag::IndexPtr, _ip) => { - return true; - } - _ => { - } - ); + if HeapCellValueTag::CodeIndex == idx_cell.get_tag() { + return true; } } diff --git a/src/machine/unify.rs b/src/machine/unify.rs index b9aae0e6..7d451fc8 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -3,6 +3,7 @@ use crate::forms::*; use crate::heap_iter::{stackful_preorder_iter, NonListElider}; use crate::machine::machine_state::*; use crate::machine::*; +use crate::offset_table::*; use crate::types::*; use std::ops::{Deref, DerefMut}; diff --git a/src/macros.rs b/src/macros.rs index 6d6a71b8..7aeba996 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -62,7 +62,14 @@ macro_rules! cell_as_atom_cell { macro_rules! cell_as_f64_ptr { ($cell:expr) => {{ let offset = $cell.get_value() as usize; - F64Ptr::from_offset(F64Offset::new(offset)) + F64Ptr::from_offset(F64Offset::from(offset)) + }}; +} + +macro_rules! cell_as_code_index { + ($cell:expr) => {{ + let offset = $cell.get_value() as usize; + CodeIndex::from(CodeIndexOffset::from(offset)) }}; } @@ -140,7 +147,7 @@ macro_rules! raw_ptr_as_cell { ($ptr:expr) => {{ // Cell is 64-bit, but raw ptr is 32-bit in 32-bit systems // TODO use <*{const,mut} _>::addr instead of as when the strict_provenance feature is stable rust-lang/rust#95228 - // we might need <*{const,mut} _>::expose_provenance for strict provenance, dependening on how we recreate a pointer later + // we might need <*{const,mut} _>::expose_provenance for strict provenance, depending on how we recreate a pointer later let ptr : *const _ = $ptr; debug_assert!(!$ptr.is_null()); HeapCellValue::from_ptr_addr(ptr as usize) @@ -217,12 +224,6 @@ macro_rules! match_untyped_arena_ptr_pat_body { #[allow(unused_braces)] $code }}; - ($ptr:ident, IndexPtr, $ip:ident, $code:expr) => {{ - #[allow(unused_mut)] - let mut $ip = unsafe { $ptr.as_typed_ptr::() }; - #[allow(unused_braces)] - $code - }}; ($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{ let $s = Stream::from_tag($ptr.get_tag(), $ptr); #[allow(unused_braces)] @@ -246,12 +247,6 @@ macro_rules! match_untyped_arena_ptr_pat { | ArenaHeaderTag::StandardOutputStream | ArenaHeaderTag::StandardErrorStream }; - (IndexPtr) => { - ArenaHeaderTag::IndexPtrUndefined - | ArenaHeaderTag::IndexPtrDynamicUndefined - | ArenaHeaderTag::IndexPtrDynamicIndex - | ArenaHeaderTag::IndexPtrIndex - }; ($tag:ident) => { ArenaHeaderTag::$tag }; @@ -282,6 +277,11 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; + ($cell:ident, CodeIndex, $n:ident, $code:expr) => {{ + let $n = cell_as_code_index!($cell); + #[allow(unused_braces)] + $code + }}; ($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => {{ let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity(); #[allow(unused_braces)] diff --git a/src/offset_table.rs b/src/offset_table.rs new file mode 100644 index 00000000..5afcf89b --- /dev/null +++ b/src/offset_table.rs @@ -0,0 +1,428 @@ +use std::cell::UnsafeCell; +use std::hash::{Hash, Hasher}; +use std::ops::{Deref, DerefMut}; +use std::sync::RwLock; +use std::sync::Weak; +use std::sync::{Arc, Mutex}; +use std::{fmt, mem, ptr}; + +use arcu::atomic::Arcu; +use arcu::epoch_counters::GlobalEpochCounterPool; +use arcu::rcu_ref::RcuRef; +use arcu::Rcu; + +use crate::machine::machine_indices::IndexPtr; +use crate::raw_block::RawBlock; +use crate::raw_block::RawBlockTraits; + +use ordered_float::OrderedFloat; + +const F64_TABLE_INIT_SIZE: usize = 1 << 16; +const F64_TABLE_ALIGN: usize = 8; + +const CODE_INDEX_TABLE_INIT_SIZE: usize = 1 << 16; +const CODE_INDEX_TABLE_ALIGN: usize = 8; + +#[derive(Debug)] +pub struct OffsetTableImpl +where + OffsetTableImpl: RawBlockTraits, +{ + block: Arcu>, GlobalEpochCounterPool>, + update: Mutex<()>, +} + +pub type F64Table = OffsetTableImpl>; +pub type CodeIndexTable = OffsetTableImpl; + +impl RawBlockTraits for F64Table { + #[inline] + fn init_size() -> usize { + F64_TABLE_INIT_SIZE + } + + #[inline] + fn align() -> usize { + F64_TABLE_ALIGN + } +} + +impl RawBlockTraits for CodeIndexTable { + #[inline] + fn init_size() -> usize { + CODE_INDEX_TABLE_INIT_SIZE + } + + #[inline] + fn align() -> usize { + CODE_INDEX_TABLE_ALIGN + } +} + +pub trait OffsetTable: RawBlockTraits { + type Offset: Copy + From + Into; + type Stored; + + fn global_table() -> &'static RwLock>; +} + +impl OffsetTable for F64Table { + type Offset = F64Offset; + type Stored = OrderedFloat; + + #[inline(always)] + fn global_table() -> &'static RwLock> { + static GLOBAL_ATOM_TABLE: RwLock> = RwLock::new(Weak::new()); + &GLOBAL_ATOM_TABLE + } +} + +impl OffsetTable for CodeIndexTable { + type Offset = CodeIndexOffset; + type Stored = IndexPtr; + + #[inline(always)] + fn global_table() -> &'static RwLock> { + static GLOBAL_CODE_INDEX_TABLE: RwLock> = RwLock::new(Weak::new()); + &GLOBAL_CODE_INDEX_TABLE + } +} + +impl OffsetTableImpl +where + OffsetTableImpl: OffsetTable, +{ + #[inline] + pub fn new() -> Arc { + let upgraded = Self::global_table().read().unwrap().upgrade(); + // don't inline upgraded, otherwise temporary will be dropped too late in case of None + if let Some(atom_table) = upgraded { + atom_table + } else { + let mut guard = Self::global_table().write().unwrap(); + // try to upgrade again in case we lost the race on the write lock + if let Some(atom_table) = guard.upgrade() { + atom_table + } else { + let table = Arc::new(Self { + block: Arcu::new(RawBlock::new(), GlobalEpochCounterPool), + update: Mutex::new(()), + }); + *guard = Arc::downgrade(&table); + table + } + } + } + + #[allow(clippy::missing_safety_doc)] + pub unsafe fn build_with( + &self, + value: as OffsetTable>::Stored, + ) -> as OffsetTable>::Offset { + let update_guard = self.update.lock(); + + // we don't have an index table for lookups as AtomTable does so + // just get the epoch after we take the upgrade lock + let mut block_epoch = self.block.read(); + + let mut ptr; + + loop { + ptr = block_epoch.alloc(mem::size_of::()); + + if ptr.is_null() { + let new_block = block_epoch.grow_new().unwrap(); + self.block.replace(new_block); + block_epoch = self.block.read(); + } else { + break; + } + } + + ptr::write(ptr as *mut T, value); + + let value = as OffsetTable>::Offset::from( + ptr as usize - block_epoch.base as usize, + ); + + // AtomTable would have to update the index table at this point + // explicit drop to ensure we don't accidentally drop it early + drop(update_guard); + + value + } + + pub fn lookup(offset: ::Offset) -> RcuRef, UnsafeCell> { + let table = Self::global_table() + .read() + .unwrap() + .upgrade() + .expect("We should only be looking up entries when there is a table"); + + RcuRef::try_map(table.block.read(), |raw_block| unsafe { + raw_block + .base + .add(offset.into()) + .cast_mut() + .cast::>() + .as_ref() + }) + .expect("The offset should result in a non-null pointer") + } +} + +#[derive(Debug)] +pub struct TablePtr(RcuRef>, UnsafeCell>) +where + OffsetTableImpl: RawBlockTraits; + +pub type CodeIndexPtr = TablePtr; +pub type F64Ptr = TablePtr>; + +impl Clone for TablePtr +where + OffsetTableImpl: RawBlockTraits, +{ + fn clone(&self) -> Self { + Self(RcuRef::clone(&self.0)) + } +} + +impl PartialEq for TablePtr +where + OffsetTableImpl: RawBlockTraits, +{ + fn eq(&self, other: &TablePtr) -> bool { + RcuRef::ptr_eq(&self.0, &other.0) || self.deref() == other.deref() + } +} + +impl Eq for TablePtr where OffsetTableImpl: RawBlockTraits {} + +impl PartialOrd for TablePtr +where + OffsetTableImpl: RawBlockTraits, +{ + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for TablePtr +where + OffsetTableImpl: RawBlockTraits, +{ + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + (**self).cmp(&**other) + } +} + +impl Hash for TablePtr +where + OffsetTableImpl: RawBlockTraits, +{ + #[inline(always)] + fn hash(&self, hasher: &mut H) { + (self as &T).hash(hasher) + } +} + +impl fmt::Display for TablePtr +where + OffsetTableImpl: RawBlockTraits, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self as &T) + } +} + +impl Deref for TablePtr +where + OffsetTableImpl: RawBlockTraits, +{ + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { self.0.get().as_ref().unwrap() } + } +} + +impl DerefMut for TablePtr +where + OffsetTableImpl: RawBlockTraits, +{ + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.0.get().as_mut().unwrap() } + } +} + +impl TablePtr +where + OffsetTableImpl: OffsetTable, +{ + #[inline(always)] + pub fn from_offset(offset: as OffsetTable>::Offset) -> Self { + Self(OffsetTableImpl::::lookup(offset)) + } + + #[inline(always)] + pub fn as_offset(&self) -> as OffsetTable>::Offset { + as OffsetTable>::Offset::from( + self.0.get() as usize - RcuRef::get_root(&self.0).base as usize, + ) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct F64Offset(usize); + +impl From for F64Offset { + #[inline(always)] + fn from(offset: usize) -> Self { + Self(offset) + } +} + +impl Into for F64Offset { + #[inline(always)] + fn into(self: Self) -> usize { + self.0 + } +} + +#[derive(Debug, Clone, Copy)] +pub struct CodeIndexOffset(usize); + +impl From for CodeIndexOffset { + #[inline(always)] + fn from(offset: usize) -> Self { + Self(offset) + } +} + +impl Into for CodeIndexOffset { + #[inline(always)] + fn into(self: Self) -> usize { + self.0 + } +} + +impl CodeIndexOffset { + #[inline(always)] + pub fn from_ptr(ptr: CodeIndexPtr) -> Self { + ptr.as_offset() + } + + #[inline(always)] + pub fn as_ptr(self) -> CodeIndexPtr { + CodeIndexPtr::from_offset(self) + } + + #[inline(always)] + pub fn to_u64(self) -> u64 { + self.0 as u64 + } +} + +impl PartialEq for CodeIndexOffset { + #[inline(always)] + fn eq(&self, other: &CodeIndexOffset) -> bool { + self.as_ptr() == other.as_ptr() + } +} + +impl Eq for CodeIndexOffset {} + +impl PartialOrd for CodeIndexOffset { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for CodeIndexOffset { + #[inline(always)] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_ptr().cmp(&other.as_ptr()) + } +} + +impl Hash for CodeIndexOffset { + #[inline(always)] + fn hash(&self, hasher: &mut H) { + self.as_ptr().hash(hasher) + } +} + +impl fmt::Display for CodeIndexOffset { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CodeIndexOffset({})", self.0) + } +} + +impl CodeIndexPtr { + #[inline] + pub fn set(&self, val: IndexPtr) { + unsafe { *self.0.get() = val }; + } + + #[inline] + pub fn replace(&self, val: IndexPtr) -> IndexPtr { + unsafe { self.0.get().replace(val) } + } +} + +impl F64Offset { + #[inline(always)] + pub fn from_ptr(ptr: F64Ptr) -> Self { + ptr.as_offset() + } + + #[inline(always)] + pub fn as_ptr(self) -> F64Ptr { + F64Ptr::from_offset(self) + } + + #[inline(always)] + pub fn to_u64(self) -> u64 { + self.0 as u64 + } +} + +impl PartialEq for F64Offset { + #[inline(always)] + fn eq(&self, other: &F64Offset) -> bool { + self.as_ptr() == other.as_ptr() + } +} + +impl Eq for F64Offset {} + +impl PartialOrd for F64Offset { + #[inline(always)] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for F64Offset { + #[inline(always)] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_ptr().cmp(&other.as_ptr()) + } +} + +impl Hash for F64Offset { + #[inline(always)] + fn hash(&self, hasher: &mut H) { + self.as_ptr().hash(hasher) + } +} + +impl fmt::Display for F64Offset { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "F64Offset({})", self.0) + } +} diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 96a0df1f..9f1d7382 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -3,6 +3,7 @@ use crate::arena::*; use crate::atom_table::*; use crate::machine::machine_indices::CodeIndex; +use crate::offset_table::*; use crate::parser::char_reader::*; use crate::types::HeapCellValueTag; @@ -631,8 +632,7 @@ impl fmt::Display for Literal { Literal::Atom(ref atom) => { write!(f, "{}", atom.flat_index()) } - // Literal::Char(c) => write!(f, "'{}'", *c as u32), - Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64), + Literal::CodeIndex(i) => write!(f, "{:?}", *i.as_ptr()), Literal::Fixnum(n) => write!(f, "{}", n.get_num()), Literal::Integer(ref n) => write!(f, "{}", n), Literal::Rational(ref n) => write!(f, "{}", n), diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 01a122a5..95162196 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -8,6 +8,8 @@ use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::dashu::Integer; +use ordered_float::OrderedFloat; + use std::convert::TryFrom; use std::fmt; diff --git a/src/parser/parser.rs b/src/parser/parser.rs index a6ec7007..b39fc557 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -7,6 +7,8 @@ use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::lexer::*; +use ordered_float::OrderedFloat; + use std::cell::Cell; use std::mem; use std::ops::Neg; diff --git a/src/types.rs b/src/types.rs index 188f0974..e356016b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -6,6 +6,7 @@ use crate::forms::*; use crate::machine::heap::*; use crate::machine::machine_indices::*; use crate::machine::streams::*; +use crate::offset_table::*; use crate::parser::ast::Fixnum; use crate::parser::ast::Literal; @@ -31,7 +32,7 @@ pub enum HeapCellValueTag { Cons = 0b0, F64 = 0b010101, Fixnum = 0b011001, - // Char = 0b011011, + CodeIndex = 0b011011, Atom = 0b011111, CutPoint = 0b011101, // trail elements. @@ -58,7 +59,7 @@ pub enum HeapCellValueView { Cons = 0b0, F64 = 0b010101, Fixnum = 0b011001, - Char = 0b011011, + CodeIndex = 0b011011, Atom = 0b011111, CutPoint = 0b011101, // trail elements. @@ -315,9 +316,7 @@ impl From for HeapCellValue { fn from(literal: Literal) -> Self { match literal { Literal::Atom(name) => atom_as_cell!(name), - Literal::CodeIndex(ptr) => { - untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr)) - } + Literal::CodeIndex(idx) => HeapCellValue::from(idx), Literal::Fixnum(n) => fixnum_as_cell!(n), Literal::Integer(bigint_ptr) => { typed_arena_ptr_as_cell!(bigint_ptr) @@ -348,6 +347,9 @@ impl TryFrom for Literal { (HeapCellValueTag::F64, f) => { Ok(Literal::Float(f.as_offset())) } + (HeapCellValueTag::CodeIndex, idx) => { + Ok(Literal::CodeIndex(idx)) + } (HeapCellValueTag::Cons, cons_ptr) => { match_untyped_arena_ptr!(cons_ptr, (ArenaHeaderTag::Integer, n) => { @@ -356,9 +358,6 @@ impl TryFrom for Literal { (ArenaHeaderTag::Rational, n) => { Ok(Literal::Rational(n)) } - (ArenaHeaderTag::IndexPtr, ip) => { - Ok(Literal::CodeIndex(CodeIndex::from(ip))) - } _ => { Err(()) } @@ -388,6 +387,16 @@ impl From for HeapCellValue { } } +impl From for HeapCellValue { + #[inline] + fn from(code_index_ptr: CodeIndexPtr) -> HeapCellValue { + HeapCellValue::build_with( + HeapCellValueTag::CodeIndex, + code_index_ptr.as_offset().to_u64(), + ) + } +} + impl From for HeapCellValue { #[inline(always)] fn from(cons_ptr: ConsPtr) -> HeapCellValue { @@ -739,22 +748,23 @@ impl UntypedArenaPtr { } #[inline] - pub fn get_ptr(self) -> *const ArenaHeader { - unsafe { mem::transmute::<_, *const ArenaHeader>(self.ptr()) } + pub fn get_ptr(self) -> *const u8 { + let addr: u64 = self.ptr(); + addr as usize as *const u8 } #[inline] pub fn get_tag(self) -> ArenaHeaderTag { unsafe { debug_assert!(!self.get_ptr().is_null()); - let header = *self.get_ptr(); + let header = *(self.get_ptr() as *const ArenaHeader); header.get_tag() } } #[inline] pub fn payload_offset(self) -> *const u8 { - unsafe { self.get_ptr().byte_add(mem::size_of::()) as *const _ } + unsafe { self.get_ptr().add(mem::size_of::()) } } /// # Safety From 98dae9aecc8ad23a2652354ad6e3a7ec3ebb551e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 9 Apr 2025 23:03:28 -0700 Subject: [PATCH 019/122] do not allow strings containing null characters to be inlined (#2848) --- src/atom_table.rs | 2 +- src/loader.pl | 1 - src/types.rs | 3 ++- tests-pl/iso-conformity-tests.pl | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/atom_table.rs b/src/atom_table.rs index 09922b17..c9abafb7 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -467,7 +467,7 @@ impl AtomTable { } pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom { - if 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN { + if 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') { return Atom::new_inlined(string); } diff --git a/src/loader.pl b/src/loader.pl index 2a5e9fb8..f2d77009 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -177,7 +177,6 @@ print_comma_separated_list([VN=_, VNEq | VNEqs]) :- filter_anonymous_vars([], []). filter_anonymous_vars([VN=V | VNEqs0], VNEqs) :- - '$debug_hook', ( atom_concat('_', _, VN) -> filter_anonymous_vars(VNEqs0, VNEqs) ; VNEqs = [VN=V | VNEqs1], diff --git a/src/types.rs b/src/types.rs index e356016b..8c989d9b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -101,7 +101,8 @@ impl ConsPtr { #[inline(always)] pub fn as_ptr(self) -> *mut u8 { - unsafe { mem::transmute::<_, *mut u8>(self.ptr()) } + let addr: u64 = self.ptr(); + addr as usize as *mut _ } #[inline(always)] diff --git a/tests-pl/iso-conformity-tests.pl b/tests-pl/iso-conformity-tests.pl index eea347cc..10b85c10 100644 --- a/tests-pl/iso-conformity-tests.pl +++ b/tests-pl/iso-conformity-tests.pl @@ -761,8 +761,7 @@ test_171 :- writeq_term_to_chars("a", C), test_229 :- test_syntax_error("\"\\z.\"", syntax_error(missing_quote)). -test_300 :- '$debug_hook', - writeq_term_to_chars("\0\", C), +test_300 :- writeq_term_to_chars("\0\", C), C == "['\\x0\\']". test_172 :- X is 10.0** -323, From 8981ab72d1ffdacc461e57ad8fe8bd058ec503d6 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 10 Apr 2025 21:03:29 -0700 Subject: [PATCH 020/122] restore tabu_list insertions to PStr-Lis comparisons (#2636) --- src/machine/machine_state_impl.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 66d3237b..58535f03 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -564,6 +564,12 @@ impl MachineState { (HeapCellValueTag::Lis, l1) => { read_heap_cell!(v2, (HeapCellValueTag::PStrLoc, l2) => { + if tabu_list.contains(&(l1, l2)) { + continue; + } + + tabu_list.insert((l1, l2)); + // like the action of // partial_string_to_pdl here but // the ordering of PDL pushes is From 549a26dd0359256b44cb92c4ef4d9603ee6e8db7 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 10 Apr 2025 21:06:44 -0700 Subject: [PATCH 021/122] restore more tabu_list use to compare_term_tests (#2633) --- src/machine/machine_state_impl.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 58535f03..d2dfc18d 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -628,6 +628,12 @@ impl MachineState { (HeapCellValueTag::PStrLoc, l1) => { read_heap_cell!(v2, (HeapCellValueTag::PStrLoc, l2) => { + if tabu_list.contains(&(l1, l2)) { + continue; + } + + tabu_list.insert((l1, l2)); + match self.heap.compare_pstr_segments(l1, l2) { PStrSegmentCmpResult::Continue(v1, v2) => { self.pdl.push(v1); @@ -642,6 +648,12 @@ impl MachineState { } } (HeapCellValueTag::Lis, l2) => { + if tabu_list.contains(&(l1, l2)) { + continue; + } + + tabu_list.insert((l1, l2)); + let (c, succ_cell) = self.heap.last_str_char_and_tail(l1); self.pdl.push(succ_cell); @@ -651,10 +663,16 @@ impl MachineState { self.pdl.push(heap_loc_as_cell!(l2)); } (HeapCellValueTag::Str, s) => { + if tabu_list.contains(&(l1, s)) { + continue; + } + let (name, arity) = cell_as_atom_cell!(self.heap[s]) .get_name_and_arity(); if name == atom!(".") && arity == 2 { + tabu_list.insert((l1, s)); + let (c, succ_cell) = self.heap.last_str_char_and_tail(l1); self.pdl.push(heap_loc_as_cell!(s+2)); From e20363b4622b8849ff4027b025f524f681e30c0b Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 11 Apr 2025 23:59:53 -0700 Subject: [PATCH 022/122] correct create_partial_string (#2593) --- src/machine/heap.rs | 68 ++++++++++++++++++------------------- src/machine/system_calls.rs | 4 +-- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 0c754baf..af26e4af 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -131,11 +131,13 @@ impl ReservedHeapSection { pub(crate) fn push_cell(&mut self, cell: HeapCellValue) { unsafe { ptr::write( - self.heap_ptr.add(heap_index!(self.heap_cell_len)) as *mut _, + self.heap_ptr + .add(heap_index!(self.heap_cell_len)) + .cast::(), cell, ); } - // self.pstr_vec.push(false); + self.heap_cell_len += 1; } @@ -243,7 +245,7 @@ impl ReservedHeapSection { } } - self.push_pstr_segment(&src); + self.push_pstr_segment(src); return ret; } } @@ -316,7 +318,7 @@ impl Index for ReservedHeapSection { #[inline] fn index(&self, idx: usize) -> &Self::Output { debug_assert!(idx < self.heap_cell_len); - unsafe { &*(self.heap_ptr as *const HeapCellValue).add(idx) } + unsafe { &*self.heap_ptr.cast::().add(idx) } } } @@ -384,7 +386,13 @@ impl<'a> Index for HeapWriter<'a> { #[inline] fn index(&self, idx: usize) -> &Self::Output { debug_assert!(heap_index!(idx) < *self.heap_byte_len); - unsafe { &*(self.section.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue) } + unsafe { + &*self + .section + .heap_ptr + .add(heap_index!(idx)) + .cast::() + } } } @@ -392,7 +400,13 @@ impl<'a> IndexMut for HeapWriter<'a> { #[inline] fn index_mut(&mut self, idx: usize) -> &mut Self::Output { debug_assert!(heap_index!(idx) < *self.heap_byte_len); - unsafe { &mut *(self.section.heap_ptr.add(heap_index!(idx)) as *mut HeapCellValue) } + unsafe { + &mut *self + .section + .heap_ptr + .add(heap_index!(idx)) + .cast::() + } } } @@ -706,7 +720,7 @@ impl Heap { // is strictly less than `self.inner.byte_cap`. // - Asserted: `self.cell_len() * size_of::() <= self.inner.byte_cap`. // - Invariant: from `InnerHeap`, `self.inner.byte_cap < isize::MAX`. - let cell_ptr = (self.inner.ptr as *mut HeapCellValue).add(self.cell_len()); + let cell_ptr = self.inner.ptr.cast::().add(self.cell_len()); cell_ptr.write(cell); // self.pstr_vec.push(false); self.inner.byte_len += heap_index!(1); @@ -715,26 +729,6 @@ impl Heap { Ok(()) } - /* - pub(crate) fn pop_cell(&mut self) -> Option { - unsafe { - if self.inner.byte_len > 0 { - let cell_ptr = (self.inner.ptr as *const HeapCellValue) - .add(self.cell_len()) - .sub(1); - let cell = ptr::read(cell_ptr); - - self.inner.byte_len -= heap_index!(1); - self.pstr_vec.pop(); - - Some(cell) - } else { - None - } - } - } - */ - fn slice_range>(&self, range: R) -> Range { let start = match range.start_bound() { Bound::Included(lower_bound) => *lower_bound, @@ -805,14 +799,16 @@ impl Heap { let char_ptr = self.inner.ptr.add(loc); let slice = std::slice::from_raw_parts(char_ptr, self.inner.byte_len - loc); - let s = std::str::from_utf8_unchecked(&slice); + let s = std::str::from_utf8_unchecked(slice); let mut chars_iter = s.chars(); let c = chars_iter.next().unwrap(); - let succ_len = loc + c.len_utf8(); + let next_char_opt = chars_iter.next(); - if chars_iter.next() == Some('\u{0}') { - (c, heap_loc_as_cell!(Self::pstr_tail_idx(succ_len))) + if next_char_opt.is_none() || next_char_opt == Some('\u{0}') { + let tail_idx = scan_slice_to_str(slice).tail_idx + cell_index!(loc); + (c, heap_loc_as_cell!(tail_idx)) } else { + let succ_len = loc + c.len_utf8(); (c, pstr_loc_as_cell!(succ_len)) } } @@ -1033,23 +1029,26 @@ pub trait SizedHeap: Index { impl Index for Heap { type Output = HeapCellValue; + #[inline] fn index(&self, idx: usize) -> &Self::Output { - unsafe { &*(self.inner.ptr as *const HeapCellValue).add(idx) } + unsafe { &*self.inner.ptr.cast::().add(idx) } } } impl IndexMut for Heap { + #[inline] fn index_mut(&mut self, idx: usize) -> &mut Self::Output { - unsafe { &mut *(self.inner.ptr as *mut HeapCellValue).add(idx) } + unsafe { &mut *self.inner.ptr.cast::().add(idx) } } } impl SizedHeap for Heap { + #[inline] fn cell_len(&self) -> usize { self.cell_len() } - fn scan_slice_to_str<'a>(&'a self, slice_loc: usize) -> HeapStringScan<'a> { + fn scan_slice_to_str(&self, slice_loc: usize) -> HeapStringScan { let HeapStringScan { string, tail_idx } = unsafe { let slice = std::slice::from_raw_parts( self.inner.ptr.add(slice_loc), @@ -1065,6 +1064,7 @@ impl SizedHeap for Heap { } } + #[inline] fn as_slice(&self) -> &[u8] { unsafe { std::slice::from_raw_parts(self.inner.ptr, self.inner.byte_len) } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 554ffdb9..b684d3ed 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2486,14 +2486,12 @@ impl Machine { return; } - let pstr_h = self.machine_st.heap.cell_len(); - let pstr_loc_cell = step_or_resource_error!( self.machine_st, self.machine_st.heap.allocate_pstr(&*atom.as_str()) ); - let tail_loc = Heap::pstr_tail_idx(atom.as_str().len() + heap_index!(pstr_h)); + let tail_loc = self.machine_st.heap.cell_len(); step_or_resource_error!( self.machine_st, From 16b3bea48ea416edc903c604a6e1de5748cfc6b1 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 12 Apr 2025 00:22:29 -0700 Subject: [PATCH 023/122] correct and simplify compute_pstr_size --- src/machine/heap.rs | 49 ++++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index af26e4af..87f50732 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -92,7 +92,10 @@ pub struct HeapStringScan<'a> { // return the string at ptr and the tail location relative to ptr. unsafe fn scan_slice_to_str(heap_slice: &[u8]) -> HeapStringScan { - let string_len = heap_slice.iter().position(|b| *b == 0u8).unwrap(); + let string_len = heap_slice + .iter() + .position(|b| *b == 0u8) + .unwrap_or(heap_slice.len()); let zero_byte_addr = heap_slice.as_ptr().add(string_len); let sentinel_len = pstr_sentinel_length(zero_byte_addr as usize); @@ -889,44 +892,26 @@ impl Heap { /// Returns the number of bytes needed to store `src` as a `PStr`. /// Assumes the string will be allocated on a ALIGN-byte boundary. pub(crate) fn compute_pstr_size(src: &str) -> usize { - if src.is_empty() { - return 0; - } - let mut byte_size = 0; - let mut null_idx = 0; + let mut src_bytes = src.as_bytes(); - loop { - let src_bytes = src.as_bytes(); - - while null_idx < src_bytes.len() { - if src_bytes[null_idx] == 0u8 { - break; - } - - null_idx += 1; + while !src_bytes.is_empty() { + if src_bytes[0] == 0 { + // push a list_loc_as_cell! and null char atom to the heap and continue. + byte_size += heap_index!(2); + src_bytes = &src_bytes[1..]; + continue; } - byte_size += null_idx + pstr_sentinel_length(null_idx); + let HeapStringScan { string, tail_idx } = unsafe { scan_slice_to_str(src_bytes) }; - // each partial string must be buffered from its tail cell - // by at least two null bytes so one of them may be used - // to mark partial strings e.g. during iteration - - if (null_idx + 1).next_multiple_of(ALIGN) == null_idx + 1 { - byte_size += 2 * size_of::(); - } else { - byte_size += size_of::(); - } - - if null_idx + 1 >= src.len() { - break; - } else { - null_idx += 1; - } + src_bytes = &src_bytes[string.len()..]; + byte_size += heap_index!(tail_idx); } - byte_size + // add 1 cell to make up for the final tail cell. if src == "" it's written to the heap as + // empty_list_as_cell!() and the pstr_size is 0 + heap_index!(1). + byte_size + heap_index!(1) } pub(crate) const fn compute_functor_byte_size(functor: &[FunctorElement]) -> usize { From 634ccf22aaafb1c6cf5c232c44a39499e5ada400 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sat, 12 Apr 2025 22:54:04 +0200 Subject: [PATCH 024/122] mark done item --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cf95b327..0cf50422 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Extend Scryer Prolog to include the following, among other features: (`atom`, `var`, etc) with if/else ladders. (_in progress_) - [ ] Inlining all built-ins and system call instructions. - [x] Greatly reducing the number of instructions used to compile disjunctives. - - [ ] Storing short atoms to heap cells without writing them to the atom table. + - [x] Storing short atoms to heap cells without writing them to the atom table. - [ ] A compacting garbage collector satisfying the five properties of "[Precise Garbage Collection in Prolog](https://www.complang.tuwien.ac.at/ulrich/papers/PDF/2008-ciclops.pdf)." (_in progress_) - [ ] Mode declarations. From 46f259bf7dcef54da68b60567b351d7b32ab2317 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 12 Apr 2025 16:43:51 -0700 Subject: [PATCH 025/122] some cosmetic tweaks --- src/types.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/types.rs b/src/types.rs index 8c989d9b..d68f605d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -698,7 +698,7 @@ impl HeapCellValue { } } -const_assert!(mem::size_of::() == 8); +const_assert!(size_of::() == 8); #[bitfield] #[repr(u64)] @@ -738,7 +738,7 @@ impl From<*const IndexPtr> for UntypedArenaPtr { impl From for *const ArenaHeader { #[inline] fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader { - ptr.get_ptr() as *const ArenaHeader + ptr.get_ptr().cast::() } } @@ -758,14 +758,14 @@ impl UntypedArenaPtr { pub fn get_tag(self) -> ArenaHeaderTag { unsafe { debug_assert!(!self.get_ptr().is_null()); - let header = *(self.get_ptr() as *const ArenaHeader); + let header = *self.get_ptr().cast::(); header.get_tag() } } #[inline] pub fn payload_offset(self) -> *const u8 { - unsafe { self.get_ptr().add(mem::size_of::()) } + unsafe { self.get_ptr().add(size_of::()) } } /// # Safety From 907e64e1859d819af2bced15774c9568e68bf058 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 12 Apr 2025 17:32:11 -0700 Subject: [PATCH 026/122] fix root reading of complete strings (#2882) --- src/read.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/read.rs b/src/read.rs index 7b476b3e..4c6b033c 100644 --- a/src/read.rs +++ b/src/read.rs @@ -345,7 +345,7 @@ impl<'a> TermWriter<'a> { fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), CompilationError> { self.heap .push_cell(cell) - .map_err(|h| CompilationError::FiniteMemoryInHeap(h)) + .map_err(CompilationError::FiniteMemoryInHeap) } fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue { @@ -435,16 +435,22 @@ impl<'a> TermWriter<'a> { continue; } TermRef::CompleteString(lvl, _, src) => { + if let Level::Root = lvl { + self.push_stub_addr()?; + } + let cell = self .heap .allocate_cstr(src) .map_err(CompilationError::FiniteMemoryInHeap)?; - let h = self.heap.cell_len(); + let new_h = self.heap.cell_len(); self.push_cell(cell)?; if !matches!(lvl, Level::Root) { - self.modify_head_of_queue(&term, h); + self.modify_head_of_queue(&term, new_h); + } else { + self.heap[h] = cell; } continue; @@ -462,7 +468,7 @@ impl<'a> TermWriter<'a> { let tail_h = self.heap.cell_len(); self.push_stub_addr()?; - if let Level::Root = lvl { + if matches!(lvl, Level::Root) { self.heap[h] = cell; } else { self.push_cell(cell)?; From 1297a24469d015aa40b69dea8cfc2caf12c0324b Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 12 Apr 2025 18:48:47 -0700 Subject: [PATCH 027/122] ensure '\0' atom is static & never inlined (#2880) --- build/static_string_indexing.rs | 5 ++--- src/atom_table.rs | 27 ++++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/build/static_string_indexing.rs b/build/static_string_indexing.rs index 5135ab77..bffb5c13 100644 --- a/build/static_string_indexing.rs +++ b/build/static_string_indexing.rs @@ -87,7 +87,7 @@ impl<'ast> Visit<'ast> for StaticStrVisitor { const INLINED_ATOM_MAX_LEN: usize = 6; fn static_string_index(string: &str, index: usize) -> u64 { - if 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN { + if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') { let mut string_buf: [u8; 8] = [0u8; 8]; string_buf[..string.len()].copy_from_slice(string.as_bytes()); (u64::from_le_bytes(string_buf) << 1) | 1 @@ -183,8 +183,7 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea }) .collect(); - let static_strs_len = static_strs.len(); // visitor.static_strs.len(); - //let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect(); + let static_strs_len = static_strs.len(); quote! { static STRINGS: [&str; #static_strs_len] = [ diff --git a/src/atom_table.rs b/src/atom_table.rs index c9abafb7..8b366549 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -49,9 +49,9 @@ const_assert!(mem::size_of::() == 8); impl AtomCell { #[inline] - pub fn new_static(index: u64) -> Self { + fn new_static(index: u64) -> Self { // upper 23 bits of index must be 0 - debug_assert!(index & !((1 << 49) - 1) == 0); + debug_assert_eq!(index & !((1 << 49) - 1), 0); AtomCell::new() .with_name(index) .with_arity(0u8) @@ -62,7 +62,7 @@ impl AtomCell { } #[inline] - pub fn new_inlined(string: &str, arity: u8) -> Self { + fn new_inlined(string: &str, arity: u8) -> Self { debug_assert!(string.len() <= INLINED_ATOM_MAX_LEN); let mut string_buf: [u8; 8] = [0u8; 8]; @@ -80,6 +80,10 @@ impl AtomCell { #[inline] pub fn new_char_inlined(c: char) -> Self { + if c == '\u{0}' { + return Self::new_static(NULL_ATOM.flat_index()); + } + let mut char_buf = [0u8; 8]; c.encode_utf8(&mut char_buf); @@ -135,6 +139,7 @@ include!(concat!(env!("OUT_DIR"), "/static_atoms.rs")); // populate these in STRINGS so they can be used from build_functor const _: Atom = atom!("."); const _: Atom = atom!("[]"); +const NULL_ATOM: Atom = atom!("\0"); impl<'a> From<&'a Atom> for Atom { #[inline] @@ -222,16 +227,12 @@ pub enum AtomString<'a> { Dynamic(AtomTableRef), } +#[inline(always)] fn inlined_to_str(bytes: &[u8; 8]) -> &str { - // allow the '\0\' atom to be represented as the 0-valued inlined atom - let slice_len = if bytes[0] == 0 { - 1 - } else { - bytes - .iter() - .position(|&b| b == 0u8) - .unwrap_or(INLINED_ATOM_MAX_LEN) - }; + let slice_len = bytes + .iter() + .position(|&b| b == 0u8) + .unwrap_or(INLINED_ATOM_MAX_LEN); unsafe { str::from_utf8_unchecked(&bytes[..slice_len]) } } @@ -467,7 +468,7 @@ impl AtomTable { } pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom { - if 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') { + if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') { return Atom::new_inlined(string); } From e563fd8e4f8d2db271a685c0f768bd98bffebcb7 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 15 Apr 2025 22:10:02 -0700 Subject: [PATCH 028/122] generalize compare_pstr_segments --- src/machine/dispatch.rs | 8 +- src/machine/heap.rs | 149 +++++++++++++++++------------- src/machine/machine_state_impl.rs | 6 +- src/machine/unify.rs | 55 +---------- 4 files changed, 93 insertions(+), 125 deletions(-) diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 4c9db0e8..3cb1a8e5 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -2815,8 +2815,6 @@ impl Machine { (HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { - debug_assert!(store_v.is_ref()); - self.machine_st.heap[0] = store_v; let heap_pstr_iter = HeapPStrIter::new(&self.machine_st.heap, 0); @@ -2841,8 +2839,7 @@ impl Machine { self.machine_st.mode = MachineMode::Read; } None => { - self.machine_st.backtrack(); - continue; + self.machine_st.fail = true; } } } @@ -2862,8 +2859,7 @@ impl Machine { self.machine_st.mode = MachineMode::Write; } _ => { - self.machine_st.backtrack(); - continue; + self.machine_st.fail = true; } ); diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 87f50732..fa554437 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -4,7 +4,6 @@ use crate::functor_macro::*; use crate::types::*; use std::alloc; -use std::cmp::Ordering; use std::convert::TryFrom; use std::ops::{Bound, Index, IndexMut, Range, RangeBounds}; use std::ptr; @@ -112,11 +111,94 @@ unsafe fn scan_slice_to_str(heap_slice: &[u8]) -> HeapStringScan { } } +#[derive(Debug, Clone, Copy)] +pub(crate) enum PStrContinuable { + PStrOffset(usize), + TailIndex(usize), +} + +impl PStrContinuable { + #[inline] + pub(crate) fn offset_by(&self, pstr_loc: usize) -> HeapCellValue { + match self { + Self::PStrOffset(pstr_offset) => pstr_loc_as_cell!(pstr_loc + pstr_offset), + Self::TailIndex(tail_idx) => heap_loc_as_cell!(tail_idx + cell_index!(pstr_loc)), + } + } +} + #[derive(Debug, Clone, Copy)] pub(crate) enum PStrSegmentCmpResult { Less, Greater, - Continue(HeapCellValue, HeapCellValue), + Continue(PStrContinuable, PStrContinuable), +} + +pub(crate) fn compare_pstr_slices(slice1: &[u8], slice2: &[u8]) -> PStrSegmentCmpResult { + use std::cmp::Ordering; + + debug_assert!(!slice1.is_empty() && !slice2.is_empty()); + let find_tail = |slice| unsafe { scan_slice_to_str(slice).tail_idx }; + + match slice1 + .iter() + .zip(slice2.iter()) + .position(|(b1, b2)| b1 != b2 || *b1 == 0 || *b2 == 0) + { + Some(pos) => { + if slice1[pos] == 0 { + // subtract 1 from pos to offset the increment of scan_slice_to_str if the + // string is "\0\". + let tail1_idx = find_tail(&slice1[pos..]); + + if slice2[pos] == 0 { + let tail2_idx = find_tail(&slice2[pos..]); + + PStrSegmentCmpResult::Continue( + PStrContinuable::TailIndex(tail1_idx + cell_index!(pos)), + PStrContinuable::TailIndex(tail2_idx + cell_index!(pos)), + ) + } else { + PStrSegmentCmpResult::Continue( + PStrContinuable::TailIndex(tail1_idx + cell_index!(pos)), + PStrContinuable::PStrOffset(pos), + ) + } + } else if slice2[pos] == 0 { + let tail2_idx = find_tail(&slice2[pos..]); + + PStrSegmentCmpResult::Continue( + PStrContinuable::PStrOffset(pos), + PStrContinuable::TailIndex(tail2_idx + cell_index!(pos)), + ) + } else { + // Compute 7-byte chunks with the mismatching character at pos in the middle of + // each. This way, the character of which the byte at pos is a part will be + // validated and reached eventually by the utf8_chunks() iterator. + + let slice1_range = pos.saturating_sub(3)..(pos + 4).min(slice1.len()); + let slice2_range = pos.saturating_sub(3)..(pos + 4).min(slice2.len()); + + let chars1_iter = slice1[slice1_range].utf8_chunks(); + let chars2_iter = slice2[slice2_range].utf8_chunks(); + + for (chunk1, chunk2) in chars1_iter.zip(chars2_iter) { + let result = chunk1.valid().cmp(chunk2.valid()); + + if result == Ordering::Greater { + return PStrSegmentCmpResult::Greater; + } else if result == Ordering::Less { + return PStrSegmentCmpResult::Less; + } + } + + unreachable!() + } + } + None => { + unreachable!() + } + } } #[derive(Debug)] @@ -609,6 +691,7 @@ impl Heap { }); } + #[inline] pub(crate) fn compare_pstr_segments( &self, pstr_loc1: usize, @@ -617,67 +700,7 @@ impl Heap { let slice1 = &self.as_slice()[pstr_loc1..]; let slice2 = &self.as_slice()[pstr_loc2..]; - let find_tail = |null_idx: usize| -> usize { self.scan_slice_to_str(null_idx).tail_idx }; - - match slice1 - .iter() - .zip(slice2.iter()) - .position(|(b1, b2)| b1 != b2 || *b1 == 0 || *b2 == 0) - { - Some(pos) => { - if slice1[pos] == 0 { - // subtract 1 from pos to offset the increment of scan_slice_to_str if the - // string is "\0\". - let tail1_idx = find_tail(pstr_loc1 + pos); - - if slice2[pos] == 0 { - let tail2_idx = find_tail(pstr_loc2 + pos); - - PStrSegmentCmpResult::Continue( - heap_loc_as_cell!(tail1_idx), - heap_loc_as_cell!(tail2_idx), - ) - } else { - PStrSegmentCmpResult::Continue( - heap_loc_as_cell!(tail1_idx), - pstr_loc_as_cell!(pstr_loc2 + pos), - ) - } - } else if slice2[pos] == 0 { - let tail2_idx = find_tail(pstr_loc2 + pos); - - PStrSegmentCmpResult::Continue( - pstr_loc_as_cell!(pstr_loc1 + pos), - heap_loc_as_cell!(tail2_idx), - ) - } else { - // Compute 7-byte chunks with the mismatching character at pos in the middle of - // each. This way, the character of which the byte at pos is a part will be - // validated and reached eventually by the utf8_chunks() iterator. - - let slice1_range = pos.saturating_sub(3)..(pos + 4).min(slice1.len()); - let slice2_range = pos.saturating_sub(3)..(pos + 4).min(slice2.len()); - - let chars1_iter = slice1[slice1_range].utf8_chunks(); - let chars2_iter = slice2[slice2_range].utf8_chunks(); - - for (chunk1, chunk2) in chars1_iter.zip(chars2_iter) { - let result = chunk1.valid().cmp(chunk2.valid()); - - if result == Ordering::Greater { - return PStrSegmentCmpResult::Greater; - } else if result == Ordering::Less { - return PStrSegmentCmpResult::Less; - } - } - - unreachable!() - } - } - None => { - unreachable!() - } - } + compare_pstr_slices(slice1, slice2) } #[inline] diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index d2dfc18d..45c689a5 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -25,7 +25,7 @@ impl MachineState { pub(crate) fn new() -> Self { let mut heap = Heap::with_cell_capacity(256 * 256).unwrap(); - // this is an interstitial cell reserved for use by the runtime. + // the cell at index 0 is an interstitial cell reserved for use by the runtime. heap.push_cell(empty_list_as_cell!()).unwrap(); heap.store_resource_error(); @@ -636,8 +636,8 @@ impl MachineState { match self.heap.compare_pstr_segments(l1, l2) { PStrSegmentCmpResult::Continue(v1, v2) => { - self.pdl.push(v1); - self.pdl.push(v2); + self.pdl.push(v1.offset_by(l1)); + self.pdl.push(v2.offset_by(l2)); } PStrSegmentCmpResult::Less => { return Some(Ordering::Less); diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 7d451fc8..fdc996a0 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -136,8 +136,8 @@ pub(crate) trait Unifier: DerefMut { (HeapCellValueTag::PStrLoc, other_pstr_loc) => { match machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc) { PStrSegmentCmpResult::Continue(v1, v2) => { - machine_st.pdl.push(v1); - machine_st.pdl.push(v2); + machine_st.pdl.push(v1.offset_by(pstr_loc)); + machine_st.pdl.push(v2.offset_by(other_pstr_loc)); } _ => { machine_st.fail = true; @@ -161,18 +161,6 @@ pub(crate) trait Unifier: DerefMut { self.fail = !(arity == 0 && name == atom); } - /* - (HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => { - self.fail = cstr_atom != atom!(""); - } - (HeapCellValueTag::Char, c1) => { - if let Some(c2) = atom.as_char() { - self.fail = c1 != c2; - } else { - self.fail = true; - } - } - */ (HeapCellValueTag::AttrVar, h) => { Self::bind(self, Ref::attr_var(h), atom_as_cell!(atom)); } @@ -207,13 +195,6 @@ pub(crate) trait Unifier: DerefMut { self.fail = true; } } - /* - (HeapCellValueTag::Char, c2) => { - if c != c2 { - self.fail = true; - } - } - */ (HeapCellValueTag::AttrVar, h) => { Self::bind(self, Ref::attr_var(h), char_as_cell!(c)); } @@ -433,38 +414,6 @@ pub(crate) trait Unifier: DerefMut { tabu_list.insert((d1, d2)); } } - /* - (HeapCellValueTag::CStr) => { - read_heap_cell!(d2, - (HeapCellValueTag::AttrVar, h) => { - Self::bind(self, Ref::attr_var(h), d1); - continue; - } - (HeapCellValueTag::Var, h) => { - Self::bind(self, Ref::heap_cell(h), d1); - continue; - } - (HeapCellValueTag::StackVar, s) => { - Self::bind(self, Ref::stack_cell(s), d1); - continue; - } - (HeapCellValueTag::Str | - HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc) => { - } - (HeapCellValueTag::CStr) => { - self.fail = d1 != d2; - continue; - } - _ => { - self.fail = true; - return; - } - ); - - Self::unify_partial_string(self, d2, d1); - } - */ (HeapCellValueTag::F64, f1) => { Self::unify_f64(self, f1, d2); } From 4c46f0e54df9448d832ae0c701d6e47c51605280 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 16 Apr 2025 22:20:31 -0700 Subject: [PATCH 029/122] correct GetPartialString (#2887) --- src/machine/dispatch.rs | 166 +++++++++++++++++++++++++--------- src/machine/heap.rs | 113 ++++++++++++----------- src/machine/mod.rs | 10 +- src/machine/partial_string.rs | 2 +- 4 files changed, 184 insertions(+), 107 deletions(-) diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 3cb1a8e5..4494b8cd 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -2806,62 +2806,142 @@ impl Machine { self.machine_st.p += 1; } &Instruction::GetPartialString(_, ref string, reg) => { - use crate::machine::partial_string::{HeapPStrIter, PStrCmpResult}; + self.machine_st.heap[0] = self.machine_st[reg]; - let deref_v = self.machine_st.deref(self.machine_st[reg]); - let store_v = self.machine_st.store(deref_v); + let mut h = 0; + let mut string_cursor = string.as_str(); - read_heap_cell!(store_v, - (HeapCellValueTag::Str | - HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc) => { - self.machine_st.heap[0] = store_v; - let heap_pstr_iter = HeapPStrIter::new(&self.machine_st.heap, 0); + while let Some(c) = string_cursor.chars().next() { + read_heap_cell!(self.machine_st.heap[h], + (HeapCellValueTag::PStrLoc, pstr_loc) => { + let heap_slice = &self.machine_st.heap.as_slice()[pstr_loc ..]; - match heap_pstr_iter.compare_pstr_to_string(string) { - Some(PStrCmpResult::CompletePStrMatch { chars_matched, pstr_loc }) => { - self.machine_st.s_offset = chars_matched; - self.machine_st.s = HeapPtr::PStr(pstr_loc); + match compare_pstr_slices(heap_slice, string_cursor.as_bytes()) { + PStrSegmentCmpResult::Continue(v1, v2) => { + // for v2, the value of a TailIndex mustn't ever be read + // since string does not lie in the heap. + match (v1, v2) { + (PStrContinuable::TailIndex(tail_idx), PStrContinuable::TailIndex(_)) => { + self.machine_st.s = HeapPtr::HeapCell(tail_idx + cell_index!(pstr_loc)); + self.machine_st.s_offset = 0; + self.machine_st.mode = MachineMode::Read; + + break; + } + (PStrContinuable::TailIndex(tail_idx), PStrContinuable::PStrOffset(pos)) => { + h = tail_idx + cell_index!(pstr_loc); + string_cursor = &string_cursor[pos ..]; + } + (PStrContinuable::PStrOffset(pos), PStrContinuable::TailIndex(_)) => { + self.machine_st.s = HeapPtr::PStr(pstr_loc); + self.machine_st.s_offset = pos; + self.machine_st.mode = MachineMode::Read; + + break; + } + _ => unreachable!(), + } + } + _ => { + self.machine_st.fail = true; + break; + } + } + } + (HeapCellValueTag::Lis, l) => { + let cell = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l])); + + if let Some(d) = cell.as_char() { + if c != d { + self.machine_st.fail = true; + break; + } + } else if let Some(r) = cell.as_var() { + self.machine_st.bind(r, char_as_cell!(c)); + } else { + self.machine_st.fail = true; + } + + if self.machine_st.fail { + break; + } else { + h = l+1; + string_cursor = &string_cursor[c.len_utf8() ..]; + + if string_cursor.is_empty() { + self.machine_st.s = HeapPtr::HeapCell(h); + self.machine_st.s_offset = 0; + self.machine_st.mode = MachineMode::Read; + } + } + } + (HeapCellValueTag::Str, s) => { + let cell = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[s+1])); + + if let Some(d) = cell.as_char() { + if c != d { + self.machine_st.fail = true; + break; + } + } else if let Some(r) = cell.as_var() { + self.machine_st.bind(r, char_as_cell!(c)); + } else { + self.machine_st.fail = true; + } + + if self.machine_st.fail { + break; + } + + h = s+2; + string_cursor = &string_cursor[c.len_utf8() ..]; + + if string_cursor.is_empty() { + self.machine_st.s = HeapPtr::HeapCell(h); + self.machine_st.s_offset = 0; self.machine_st.mode = MachineMode::Read; } - Some(PStrCmpResult::PartialPStrMatch { string, var_loc }) => { - let cell = backtrack_on_resource_error!( + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, v) => { + if h == v { + let target_cell = backtrack_on_resource_error!( self.machine_st, - self.machine_st.heap.allocate_pstr(string) + self.machine_st.heap.allocate_pstr(string_cursor) + ); + + self.machine_st.bind( + self.machine_st.heap[h].as_var().unwrap(), + target_cell, ); self.machine_st.mode = MachineMode::Write; - unify!(self.machine_st, cell, heap_loc_as_cell!(var_loc)); - } - Some(PStrCmpResult::ListMatch { list_loc }) => { - self.machine_st.s_offset = 0; - self.machine_st.s = HeapPtr::HeapCell(list_loc); - self.machine_st.mode = MachineMode::Read; - } - None => { - self.machine_st.fail = true; + break; + } else { + h = v; } } - } - (HeapCellValueTag::AttrVar | - HeapCellValueTag::StackVar | - HeapCellValueTag::Var) => { - let target_cell = backtrack_on_resource_error!( - self.machine_st, - self.machine_st.heap.allocate_pstr(string) - ); + (HeapCellValueTag::StackVar, s) => { + debug_assert_eq!(h, 0); - self.machine_st.bind( - store_v.as_var().unwrap(), - target_cell, - ); + let target_cell = backtrack_on_resource_error!( + self.machine_st, + self.machine_st.heap.allocate_pstr(string_cursor) + ); - self.machine_st.mode = MachineMode::Write; - } - _ => { - self.machine_st.fail = true; - } - ); + self.machine_st.bind( + Ref::stack_cell(s), + target_cell, + ); + + self.machine_st.mode = MachineMode::Write; + break; + } + _ => { + self.machine_st.fail = true; + break; + } + ); + } step_or_fail!(self, self.machine_st.p += 1); } diff --git a/src/machine/heap.rs b/src/machine/heap.rs index fa554437..f682a1a0 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -135,69 +135,72 @@ pub(crate) enum PStrSegmentCmpResult { } pub(crate) fn compare_pstr_slices(slice1: &[u8], slice2: &[u8]) -> PStrSegmentCmpResult { - use std::cmp::Ordering; - debug_assert!(!slice1.is_empty() && !slice2.is_empty()); let find_tail = |slice| unsafe { scan_slice_to_str(slice).tail_idx }; + let calculate_result = |pos| { + use std::cmp::Ordering; + + if slice1.get(pos).cloned().unwrap_or(0) == 0 { + // subtract 1 from pos to offset the increment of scan_slice_to_str if the + // string is "\0\". + let tail1_idx = find_tail(&slice1[pos..]); + let offset_pos_1 = (ALIGN - slice1.as_ptr().align_offset(ALIGN)) % ALIGN; + + if slice2.get(pos).cloned().unwrap_or(0) == 0 { + let tail2_idx = find_tail(&slice2[pos..]); + let offset_pos_2 = (ALIGN - slice2.as_ptr().align_offset(ALIGN)) % ALIGN; + + PStrSegmentCmpResult::Continue( + PStrContinuable::TailIndex(tail1_idx + cell_index!(pos + offset_pos_1)), + PStrContinuable::TailIndex(tail2_idx + cell_index!(pos + offset_pos_2)), + ) + } else { + PStrSegmentCmpResult::Continue( + PStrContinuable::TailIndex(tail1_idx + cell_index!(pos)), + PStrContinuable::PStrOffset(pos), + ) + } + } else if slice2.get(pos).cloned().unwrap_or(0) == 0 { + let tail2_idx = find_tail(&slice2[pos..]); + let offset_pos_2 = (ALIGN - slice2.as_ptr().align_offset(ALIGN)) % ALIGN; + + PStrSegmentCmpResult::Continue( + PStrContinuable::PStrOffset(pos), + PStrContinuable::TailIndex(tail2_idx + cell_index!(pos + offset_pos_2)), + ) + } else { + // Compute 7-byte chunks with the mismatching character at pos in the middle of + // each. This way, the character of which the byte at pos is a part will be + // validated and reached eventually by the utf8_chunks() iterator. + + let slice1_range = pos.saturating_sub(3)..(pos + 4).min(slice1.len()); + let slice2_range = pos.saturating_sub(3)..(pos + 4).min(slice2.len()); + + let chars1_iter = slice1[slice1_range].utf8_chunks(); + let chars2_iter = slice2[slice2_range].utf8_chunks(); + + for (chunk1, chunk2) in chars1_iter.zip(chars2_iter) { + let result = chunk1.valid().cmp(chunk2.valid()); + + if result == Ordering::Greater { + return PStrSegmentCmpResult::Greater; + } else if result == Ordering::Less { + return PStrSegmentCmpResult::Less; + } + } + + unreachable!() + } + }; + match slice1 .iter() .zip(slice2.iter()) .position(|(b1, b2)| b1 != b2 || *b1 == 0 || *b2 == 0) { - Some(pos) => { - if slice1[pos] == 0 { - // subtract 1 from pos to offset the increment of scan_slice_to_str if the - // string is "\0\". - let tail1_idx = find_tail(&slice1[pos..]); - - if slice2[pos] == 0 { - let tail2_idx = find_tail(&slice2[pos..]); - - PStrSegmentCmpResult::Continue( - PStrContinuable::TailIndex(tail1_idx + cell_index!(pos)), - PStrContinuable::TailIndex(tail2_idx + cell_index!(pos)), - ) - } else { - PStrSegmentCmpResult::Continue( - PStrContinuable::TailIndex(tail1_idx + cell_index!(pos)), - PStrContinuable::PStrOffset(pos), - ) - } - } else if slice2[pos] == 0 { - let tail2_idx = find_tail(&slice2[pos..]); - - PStrSegmentCmpResult::Continue( - PStrContinuable::PStrOffset(pos), - PStrContinuable::TailIndex(tail2_idx + cell_index!(pos)), - ) - } else { - // Compute 7-byte chunks with the mismatching character at pos in the middle of - // each. This way, the character of which the byte at pos is a part will be - // validated and reached eventually by the utf8_chunks() iterator. - - let slice1_range = pos.saturating_sub(3)..(pos + 4).min(slice1.len()); - let slice2_range = pos.saturating_sub(3)..(pos + 4).min(slice2.len()); - - let chars1_iter = slice1[slice1_range].utf8_chunks(); - let chars2_iter = slice2[slice2_range].utf8_chunks(); - - for (chunk1, chunk2) in chars1_iter.zip(chars2_iter) { - let result = chunk1.valid().cmp(chunk2.valid()); - - if result == Ordering::Greater { - return PStrSegmentCmpResult::Greater; - } else if result == Ordering::Less { - return PStrSegmentCmpResult::Less; - } - } - - unreachable!() - } - } - None => { - unreachable!() - } + Some(pos) => calculate_result(pos), + None => calculate_result(slice1.len().min(slice2.len())), } } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index c0dcb6e4..674dda42 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -618,14 +618,8 @@ impl Machine { } ); } - &Instruction::GetPartialString( - Level::Shallow, - ref string, - RegType::Temp(t), - // has_tail, - ) => { + &Instruction::GetPartialString(Level::Shallow, ref string, RegType::Temp(t)) => { use crate::machine::partial_string::HeapPStrIter; - let cell = self.deref_register(t); read_heap_cell!(cell, @@ -633,7 +627,7 @@ impl Machine { self.machine_st.heap[0] = cell; let iter = HeapPStrIter::new(&self.machine_st.heap, 0); - if iter.compare_pstr_to_string(&string).is_none() { + if iter.compare_pstr_to_string(string).is_none() { return false; } diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 43163ce2..a8e908a9 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -60,7 +60,7 @@ impl<'a> HeapPStrIter<'a> { self.brent_st.hare } - pub fn compare_pstr_to_string<'b>(self, mut s: &'b str) -> Option> { + pub fn compare_pstr_to_string(self, mut s: &str) -> Option { let mut curr_hare = self.brent_st.hare; while !s.is_empty() { From bf31d3f9a9e1d4eb14831e2b38941826e925964f Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Thu, 17 Apr 2025 22:14:37 +0200 Subject: [PATCH 030/122] ENHANCED: dedicated faster branches for repositionable streams rebis-dev makes the speed difference especially apparent due to the linear scan of strings on the heap in partial_string_tail/2 which is now avoided for repositionable streams, notably files. This addresses #2888 reported and analyzed by @haijinSk. Many thanks! --- src/lib/pio.pl | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/lib/pio.pl b/src/lib/pio.pl index f13c9b85..0204a19e 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -39,7 +39,8 @@ % represented as a list of characters. phrase_from_stream(GRBody, Stream) :- - stream_to_lazy_list(Stream, Ls), + stream_property(Stream, reposition(Reposition)), + stream_to_lazy_list(Reposition, Stream, Ls), phrase(GRBody, Ls). %% phrase_from_file(+GRBody, +File) @@ -64,7 +65,7 @@ phrase_from_file(NT, File, Options) :- ; Type = text ), setup_call_cleanup( - open(File, read, Stream, Options), + open(File, read, Stream, [reposition(true)|Options]), phrase_from_stream(NT, Stream), close(Stream) ) @@ -73,34 +74,41 @@ phrase_from_file(NT, File, Options) :- % How many chars to read from stream and buffer in each step chars_to_read(4096). -stream_to_lazy_list(Stream, Ls) :- - get_stream_buffer_position(Stream, Pos), - freeze(Ls, render_step(Stream, Pos, Ls)). +stream_to_lazy_list(Reposition, Stream, Ls) :- + get_stream_buffer_position(Reposition, Stream, Pos), + freeze(Ls, render_step(Reposition, Stream, Pos, Ls)). -render_step(Stream, Pos, Ls) :- - set_stream_buffer_position(Stream, Pos), - ( buffer_at_end_of_stream(Stream) -> +render_step(Reposition, Stream, Pos, Ls) :- + set_stream_buffer_position(Reposition, Stream, Pos), + ( buffer_at_end_of_stream(Reposition, Stream) -> Ls = [] ; chars_to_read(CharsToRead), - buffer_get_n_chars(Stream, CharsToRead, Chars), + buffer_get_n_chars(Reposition, Stream, CharsToRead, Chars), partial_string(Chars, Ls, Ls0), - stream_to_lazy_list(Stream, Ls0) + stream_to_lazy_list(Reposition, Stream, Ls0) ). -buffer_at_end_of_stream(Stream) :- +buffer_at_end_of_stream(true, Stream) :- at_end_of_stream(Stream). +buffer_at_end_of_stream(false, Stream) :- stream_bufferids(Stream, _, BufferPosId, _), bb_get(BufferPosId, Pos), Pos = eof. -get_stream_buffer_position(Stream, Pos) :- +get_stream_buffer_position(true, Stream, Pos) :- + stream_property(Stream, position(Pos)). +get_stream_buffer_position(false, Stream, Pos) :- stream_bufferids(Stream, _, BufferPosId, _), bb_get(BufferPosId, Pos). -set_stream_buffer_position(Stream, Pos) :- +set_stream_buffer_position(true, Stream, Pos) :- + set_stream_position(Stream, Pos). +set_stream_buffer_position(false, Stream, Pos) :- stream_bufferids(Stream, _, BufferPosId, _), bb_put(BufferPosId, Pos). -buffer_get_n_chars(Stream, N, Chars) :- +buffer_get_n_chars(true, Stream, N, Chars) :- + get_n_chars(Stream, N, Chars). +buffer_get_n_chars(false, Stream, N, Chars) :- stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId), buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N), bb_get(BufferId, Buffer), From f3cd6326a37458daf857f6be0785e6c109a71f38 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 17 Apr 2025 20:20:38 -0700 Subject: [PATCH 031/122] remove compare_pstr_to_string and related result type --- src/machine/heap.rs | 25 --------- src/machine/mod.rs | 14 ++---- src/machine/partial_string.rs | 95 ----------------------------------- 3 files changed, 5 insertions(+), 129 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index f682a1a0..c08ba03f 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -657,33 +657,8 @@ impl Heap { self.inner.ptr = ptr::null_mut(); self.inner.byte_len = 0; self.inner.byte_cap = 0; - - // self.pstr_vec.clear(); } - // pub(crate) fn append(&mut self, heap_slice: HeapView) -> Result<(), usize> { - // unsafe { - // loop { - // if self.free_space() >= heap_index!(heap_slice.slice_cell_len) { - // ptr::copy_nonoverlapping( - // heap_slice.slice, - // self.inner.ptr.add(self.inner.byte_len), - // heap_index!(heap_slice.slice_cell_len), - // ); - - // self.inner.byte_len += heap_index!(heap_slice.slice_cell_len); - // // self.pstr_vec.extend(heap_slice.pstr_slice.iter()); - - // break; - // } else if !self.grow() { - // return Err(self.resource_error_offset()); - // } - // } - // } - - // Ok(()) - // } - pub(crate) fn store_resource_error(&mut self) { RESOURCE_ERROR_OFFSET_INIT.call_once(move || { let stub = functor!(atom!("resource_error"), [atom_as_cell((atom!("memory")))]); diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 674dda42..8f70b96f 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -619,20 +619,16 @@ impl Machine { ); } &Instruction::GetPartialString(Level::Shallow, ref string, RegType::Temp(t)) => { - use crate::machine::partial_string::HeapPStrIter; let cell = self.deref_register(t); read_heap_cell!(cell, - (HeapCellValueTag::PStrLoc) => { - self.machine_st.heap[0] = cell; - let iter = HeapPStrIter::new(&self.machine_st.heap, 0); + (HeapCellValueTag::PStrLoc, pstr_loc) => { + let heap_slice = &self.machine_st.heap.as_slice()[pstr_loc ..]; - if iter.compare_pstr_to_string(string).is_none() { - return false; + match compare_pstr_slices(heap_slice, string.as_bytes()) { + PStrSegmentCmpResult::Continue(..) => offset += 1, + _ => return false, } - - offset += 1; - } (HeapCellValueTag::Lis) => { offset += 1; diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index a8e908a9..ee0c2be9 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -6,7 +6,6 @@ use crate::machine::system_calls::BrentAlgState; use crate::types::*; use std::ops::Deref; -use std::str; #[derive(Clone, Copy)] pub struct HeapPStrIter<'a> { @@ -17,21 +16,6 @@ pub struct HeapPStrIter<'a> { stepper: fn(&mut HeapPStrIter<'a>) -> Option, } -#[derive(Debug, Clone, Copy)] -pub enum PStrCmpResult<'a> { - ListMatch { - list_loc: usize, - }, - CompletePStrMatch { - chars_matched: usize, - pstr_loc: usize, - }, - PartialPStrMatch { - string: &'a str, - var_loc: usize, - }, -} - struct PStrIterStep { iteratee: PStrIteratee, next_hare: usize, @@ -60,85 +44,6 @@ impl<'a> HeapPStrIter<'a> { self.brent_st.hare } - pub fn compare_pstr_to_string(self, mut s: &str) -> Option { - let mut curr_hare = self.brent_st.hare; - - while !s.is_empty() { - read_heap_cell!(self.heap[curr_hare], - (HeapCellValueTag::PStrLoc, h) => { - let t = self.heap.slice_to_str(h, self.heap.byte_len() - h); - - let mut bytes_matched = 0; - let mut chars_matched = 0; - - for (sc, tc) in s.chars().zip(t.chars()) { - if sc != tc { - if tc != '\u{0}' { - return None; - } else { - break; - } - } - - bytes_matched += sc.len_utf8(); - chars_matched += 1; - } - - s = &s[bytes_matched ..]; - - if s.is_empty() { - return Some(PStrCmpResult::CompletePStrMatch { chars_matched, pstr_loc: h }); - } else { - let next_hare = Heap::pstr_tail_idx(h + bytes_matched); - curr_hare = next_hare; - } - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h == curr_hare { - return Some(PStrCmpResult::PartialPStrMatch { string: s, var_loc: h }); - } - - curr_hare = h; - continue; - } - _ => { - match self.step(curr_hare).ok() { - Some(PStrIterStep { iteratee, next_hare }) => { - let value = if let PStrIteratee::Char { value, .. } = iteratee { - value - } else { - unreachable!() - }; - - let c = s.chars().next().unwrap(); - - if c == value { - s = &s[c.len_utf8() ..]; - - if s.is_empty() { - return Some( - PStrCmpResult::ListMatch { - list_loc: next_hare, - } - ); - } - - curr_hare = next_hare; - } else { - return None; - } - } - None => { - return None; - } - } - } - ); - } - - None - } - fn walk_hare_to_cycle_end(&mut self) { // walk_hare_to_cycle_end assumes a cycle has been found, // so it is always safe to unwrap self.step() From 4644ea24040ba48c1afd26c6a7a02e1bf9581ac6 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 18 Apr 2025 00:03:33 -0700 Subject: [PATCH 032/122] repair cyclic PStrLoc handling in heap_print.rs --- src/heap_print.rs | 9 +++++++-- src/machine/machine_state.rs | 4 ---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index f11fb4d5..c2b60657 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -879,7 +879,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } else { debug_assert!(cell.is_ref()); - let h = cell.get_value() as usize; + let h = if cell.get_tag() == HeapCellValueTag::PStrLoc { + self.iter.focus().value() + } else { + cell.get_value() + } as usize; + self.iter.push_stack(IterStackLoc::iterable_loc( h, HeapOrStackTag::Heap, @@ -909,7 +914,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { orig_cell = cell; continue; } - } + }; } } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 049f131c..7c8f1abe 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -731,10 +731,6 @@ impl MachineState { ) ); - 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 { From 995a39419acea117a30791c7db6e321804250f9f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 19 Apr 2025 23:51:26 -0700 Subject: [PATCH 033/122] fix read_s logic around HeapPtr::PStrLoc (#2894) --- src/machine/machine_state_impl.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 45c689a5..0358cfd4 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -345,8 +345,8 @@ impl MachineState { pub(crate) fn read_s(&mut self) -> HeapCellValue { match self.s { HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]), - HeapPtr::PStr(h) => { - let mut char_iter = self.heap.char_iter(h); + HeapPtr::PStr(byte_index) => { + let mut char_iter = self.heap.char_iter(byte_index); if self.s_offset == 0 { // read the car of the list @@ -354,10 +354,9 @@ impl MachineState { char_as_cell!(c) } else { // read the (self.s_offset)^{th} cdr of the list - let byte_offset: usize = - char_iter.take(self.s_offset).map(|c| c.len_utf8()).sum(); - let new_h = h + byte_offset; - + // self.s_offset is the number of bytes offset into the PStr + // in this context, *not* the number of heap cells. + let new_h = byte_index + self.s_offset; self.s_offset = 0; if self.heap.char_iter(new_h).next().is_some() { From e1e52338d69bc69d63b707c14ec4bbfe84f998f4 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 20 Apr 2025 00:07:55 -0700 Subject: [PATCH 034/122] fix typo in try_from_partial_string --- src/machine/machine_state_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 0358cfd4..1d6439d5 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1332,7 +1332,7 @@ impl MachineState { let end_cell = heap_pstr_iter.heap[heap_pstr_iter.focus()]; - if heap_pstr_iter.is_cyclic() || end_cell == empty_list_as_cell!() { + if heap_pstr_iter.is_cyclic() || end_cell != empty_list_as_cell!() { let err = self.type_error(ValidType::List, a1); return Err(self.error_form(err, stub_gen())); } From 6bcbb91e08bf5f0d7701b2568edc357fbd4524e5 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 20 Apr 2025 16:53:36 -0700 Subject: [PATCH 035/122] correctly increment s_offset for partial strings (#2897) --- src/machine/dispatch.rs | 66 ++++--------------------------- src/machine/machine_state_impl.rs | 10 ++--- 2 files changed, 13 insertions(+), 63 deletions(-) diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 4494b8cd..254f9adc 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -272,55 +272,6 @@ impl MachineState { ) } - /* - #[inline(always)] - pub(crate) fn constant_to_literal(&self, addr: HeapCellValue) -> Literal { - read_heap_cell!(addr, - (HeapCellValueTag::Char, c) => { - Literal::Char(c) - } - (HeapCellValueTag::Fixnum, n) => { - Literal::Fixnum(n) - } - (HeapCellValueTag::F64, f) => { - Literal::Float(f.as_offset()) - } - (HeapCellValueTag::Atom, (atom, arity)) => { - debug_assert_eq!(arity, 0); - Literal::Atom(atom) - } - (HeapCellValueTag::Str, s) => { - Literal::Atom(cell_as_atom_cell!(self.heap[s]).get_name()) - } - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::Rational, r) => { - Literal::Rational(r) - } - (ArenaHeaderTag::Integer, n) => { - let result = (&*n).try_into(); - - match result { - Ok(fixnum) => if let Ok(n) = Fixnum::build_with_checked(fixnum) { - Literal::Fixnum(n) - } else { - Literal::Integer(n) - }, - Err(_) => Literal::Integer(n) - } - } - _ => { - unreachable!() - } - ) - } - _ => { - unreachable!() - } - ) - } - */ - #[inline(always)] pub(crate) fn select_switch_on_structure_index( &self, @@ -3004,14 +2955,14 @@ impl Machine { &Instruction::UnifyConstant(v) => { match self.machine_st.mode { MachineMode::Read => { - let addr = self.machine_st.read_s(); + let (addr, s_offset_incr) = self.machine_st.read_s(); unify!(&mut self.machine_st, addr, v); if self.machine_st.fail { self.machine_st.backtrack(); continue; } else { - self.machine_st.s_offset += 1; + self.machine_st.s_offset += s_offset_incr; } } MachineMode::Write => { @@ -3025,7 +2976,7 @@ impl Machine { match self.machine_st.mode { MachineMode::Read => { let reg_addr = self.machine_st[reg]; - let value = self.machine_st.read_s(); + let (value, s_offset_incr) = self.machine_st.read_s(); unify_fn!(&mut self.machine_st, reg_addr, value); @@ -3033,7 +2984,7 @@ impl Machine { self.machine_st.backtrack(); continue; } else { - self.machine_st.s_offset += 1; + self.machine_st.s_offset += s_offset_incr; } } MachineMode::Write => { @@ -3066,13 +3017,12 @@ impl Machine { &Instruction::UnifyVariable(reg) => { match self.machine_st.mode { MachineMode::Read => { - let value = self.machine_st.read_s(); + let (value, s_offset_incr) = self.machine_st.read_s(); self.machine_st[reg] = value; - self.machine_st.s_offset += 1; + self.machine_st.s_offset += s_offset_incr; } MachineMode::Write => { let h = self.machine_st.heap.cell_len(); - push_cell!(self.machine_st, heap_loc_as_cell!(h)); self.machine_st[reg] = heap_loc_as_cell!(h); } @@ -3084,7 +3034,7 @@ impl Machine { match self.machine_st.mode { MachineMode::Read => { let reg_addr = self.machine_st[reg]; - let value = self.machine_st.read_s(); + let (value, s_offset_incr) = self.machine_st.read_s(); unify_fn!(&mut self.machine_st, reg_addr, value); @@ -3092,7 +3042,7 @@ impl Machine { self.machine_st.backtrack(); continue; } else { - self.machine_st.s_offset += 1; + self.machine_st.s_offset += s_offset_incr; } } MachineMode::Write => { diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 1d6439d5..ede17fa6 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -342,16 +342,16 @@ impl MachineState { } // return the read value and the succeeding HeapPtr - pub(crate) fn read_s(&mut self) -> HeapCellValue { + pub(crate) fn read_s(&mut self) -> (HeapCellValue, usize) { match self.s { - HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]), + HeapPtr::HeapCell(h) => (self.deref(self.heap[h + self.s_offset]), 1), HeapPtr::PStr(byte_index) => { let mut char_iter = self.heap.char_iter(byte_index); if self.s_offset == 0 { // read the car of the list let c = char_iter.next().unwrap(); - char_as_cell!(c) + (char_as_cell!(c), c.len_utf8()) } else { // read the (self.s_offset)^{th} cdr of the list // self.s_offset is the number of bytes offset into the PStr @@ -361,11 +361,11 @@ impl MachineState { if self.heap.char_iter(new_h).next().is_some() { self.s = HeapPtr::PStr(new_h); - pstr_loc_as_cell!(new_h) + (pstr_loc_as_cell!(new_h), 0) } else { let h = Heap::pstr_tail_idx(new_h); self.s = HeapPtr::HeapCell(h); - self.deref(heap_loc_as_cell!(h)) + (self.deref(heap_loc_as_cell!(h)), 0) } } } From 41b90c6e46d288d0ab3c466fc419cd4139511c20 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 20 Apr 2025 17:14:13 -0700 Subject: [PATCH 036/122] correct heap_print.rs for null characters being excluded from pstr regions of heap (#2890) --- src/heap_print.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index c2b60657..7bd227e2 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1252,7 +1252,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { HeapCellValueTag::PStrLoc => { self.iter.pop_stack(); } - // HeapCellValueTag::CStr => {} _ => { unreachable!(); } @@ -1572,10 +1571,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let c = self.iter.heap.char_at(pstr_loc); - if c != '\u{0}' || pstr_loc % std::mem::size_of::() == 0 { - // if a null character in a pstr has location aligned - // to a cell boundary, the string is ['\\x0\\']. - + if c != '\u{0}' { if !self.max_depth_exhausted(max_depth) { self.state_stack .push(TokenOrRedirect::CommaSeparatedCharList( @@ -1724,7 +1720,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { (HeapCellValueTag::F64, f) => { self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(*f)), &op); } - (HeapCellValueTag::PStrLoc) => { // HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + (HeapCellValueTag::PStrLoc) => { self.print_list_like(max_depth); } (HeapCellValueTag::Lis) => { From 39ea2d5899fdbcbe87be2f7f7c254530c3900402 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 21 Apr 2025 20:25:50 -0700 Subject: [PATCH 037/122] make self.s_offset use bytes in case of HeapPtr::PStr in UnifyVoid (#2897) --- src/machine/dispatch.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 254f9adc..94b26ad3 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -3072,9 +3072,19 @@ impl Machine { } &Instruction::UnifyVoid(n) => { match self.machine_st.mode { - MachineMode::Read => { - self.machine_st.s_offset += n; - } + MachineMode::Read => match &self.machine_st.s { + HeapPtr::HeapCell(_) => self.machine_st.s_offset += n, + &HeapPtr::PStr(pstr_loc) => { + debug_assert!(n <= 2); + let mut char_iter = self.machine_st.heap.char_iter(pstr_loc); + + // this only matters in the case that n == 1, but the case + // analysis isn't worth doing since the effect is benign if n == + // 2 + self.machine_st.s_offset += + char_iter.next().unwrap().len_utf8(); + } + }, MachineMode::Write => { let h = self.machine_st.heap.cell_len(); From 258244caf2eb61dd09b40b558609a093d0b78b33 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 23 Apr 2025 18:55:50 -0700 Subject: [PATCH 038/122] restore tab completion to REPL (#2575) --- src/repl_helper.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/repl_helper.rs b/src/repl_helper.rs index 26199c22..afec4fd2 100644 --- a/src/repl_helper.rs +++ b/src/repl_helper.rs @@ -6,7 +6,7 @@ use rustyline::{Context, Helper as RlHelper, Result}; use std::sync::Weak; -use crate::atom_table::{AtomString, AtomTable}; //, STATIC_ATOMS_MAP}; +use crate::atom_table::{AtomString, AtomTable, STATIC_ATOMS_MAP}; // TODO: Maybe add validation to the helper pub struct Helper { @@ -74,7 +74,7 @@ impl Completer for Helper { let mut matching = index_set .iter() - // .chain(STATIC_ATOMS_MAP.values()) + .chain(STATIC_ATOMS_MAP.values()) .map(|a| a.as_str()) .filter(|a| a.starts_with(sub_str)) .collect::>(); From 706ffe7ad92e8a7b2e9a752898a12ef03b214b3a Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 23 Apr 2025 22:49:03 -0700 Subject: [PATCH 039/122] fix functor! size calculations around indexing_code_ptr --- src/functor_macro.rs | 29 +++++++++++++++-------------- src/machine/dispatch.rs | 1 - src/machine/heap.rs | 2 +- src/machine/system_calls.rs | 9 ++++----- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/functor_macro.rs b/src/functor_macro.rs index ee69679f..444c8432 100644 --- a/src/functor_macro.rs +++ b/src/functor_macro.rs @@ -61,10 +61,17 @@ macro_rules! build_functor { [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({ + let (inner_functor, cell_size) = indexing_code_ptr($e); + let referent = if cell_size == 1 { + heap_loc_as_cell!(1u64 + count!($($dt)*) + $res_len) + } else { + str_loc_as_cell!(1u64 + count!($($dt)*) + $res_len) + }; + build_functor!([$($dt($($value),*)),*], - [$($res, )* FunctorElement::Cell(str_loc_as_cell!(1u64 + count!($($dt)*) + $res_len))], - 3 + $res_len, - [$($subfunctor, )* FunctorElement::InnerFunctor(2, indexing_code_ptr($e))]) + [$($res, )* FunctorElement::Cell(referent)], + 1 + cell_size + $res_len, + [$($subfunctor, )* FunctorElement::InnerFunctor(cell_size, inner_functor)]) }); ([fixnum($e:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], @@ -171,20 +178,14 @@ macro_rules! build_functor { }); } -pub(crate) fn indexing_code_ptr(code_ptr: IndexingCodePtr) -> Vec { +pub(crate) fn indexing_code_ptr(code_ptr: IndexingCodePtr) -> (Vec, u64) { match code_ptr { IndexingCodePtr::DynamicExternal(o) => { - functor!(atom!("dynamic_external"), [fixnum(o)]) - } - IndexingCodePtr::External(o) => { - functor!(atom!("external"), [fixnum(o)]) - } - IndexingCodePtr::Internal(o) => { - functor!(atom!("internal"), [fixnum(o)]) - } - IndexingCodePtr::Fail => { - vec![FunctorElement::Cell(atom_as_cell!(atom!("fail")))] + (functor!(atom!("dynamic_external"), [fixnum(o)]), 2) } + IndexingCodePtr::External(o) => (functor!(atom!("external"), [fixnum(o)]), 2), + IndexingCodePtr::Internal(o) => (functor!(atom!("internal"), [fixnum(o)]), 2), + IndexingCodePtr::Fail => (vec![FunctorElement::Cell(atom_as_cell!(atom!("fail")))], 1), } } diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 94b26ad3..3a88221a 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -242,7 +242,6 @@ impl MachineState { c } (HeapCellValueTag::Atom, (_name, arity)) => { - // if arity == 0 { c } else { s } debug_assert!(arity == 0); c } diff --git a/src/machine/heap.rs b/src/machine/heap.rs index c08ba03f..b03d5efa 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1092,7 +1092,7 @@ pub fn heap_bound_store(heap: &impl SizedHeap, value: HeapCellValue) -> HeapCell } #[allow(dead_code)] -pub fn print_heap_terms(heap: &Heap, h: usize) { +pub fn print_heap_terms(heap: &impl SizedHeap, h: usize) { for idx in 0..heap.cell_len() { let term = heap[idx]; println!("{} : {:?}", h + idx, term); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index b684d3ed..43bd632a 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -7307,20 +7307,19 @@ impl Machine { walk_code(&self.code, index_ptr, |instr| { let old_len = functors.len(); instr.enqueue_functors(&mut self.machine_st.arena, &mut functors); - let new_len = functors.len(); - for index in old_len..new_len { - let functor_len = functors[index].len(); + for functor in &functors[old_len..] { + let functor_len = functor.len(); match functor_len { 0 => {} 1 => { functor_list.push(heap_loc_as_cell!(h)); - h += cell_index!(Heap::compute_functor_byte_size(&functors[index])); + h += cell_index!(Heap::compute_functor_byte_size(functor)); } _ => { functor_list.push(str_loc_as_cell!(h)); - h += cell_index!(Heap::compute_functor_byte_size(&functors[index])); + h += cell_index!(Heap::compute_functor_byte_size(functor)); } }; } From b12d1ece1783755a3fe96df310366721c079e30e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 24 Apr 2025 22:20:40 -0700 Subject: [PATCH 040/122] correct heap-to-cell-index comparison in copy_slice_to_end (#2906) --- src/machine/heap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index b03d5efa..c12af9d1 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -870,7 +870,7 @@ impl Heap { unsafe { loop { - if self.free_space() >= len { + if self.free_space() >= heap_index!(len) { ptr::copy_nonoverlapping( self.inner.ptr.add(heap_index!(range.start)), self.inner.ptr.add(self.inner.byte_len), From e9bb41f0d69e0fbaa848ff3a25d9d2dd04a80487 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Thu, 24 Apr 2025 18:19:05 +0200 Subject: [PATCH 041/122] ENHANCED: use a fast test for the expected case of chars in atom_chars/2 etc. Suggested by Oleg Finkelstein, thank you a lot! Example, before this change: ?- t+\(length(As, 1_000_000), maplist(=(a), As), time(atom_chars(A, As))). % CPU time: 0.693s, 7_000_041 inferences true. Now: ?- t+\(length(As, 1_000_000), maplist(=(a), As), time(atom_chars(A, As))). % CPU time: 0.080s, 40 inferences true. This also partially ameliorates #2907. --- src/lib/builtins.pl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index ca07e0c6..df7696f9 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1719,20 +1719,27 @@ must_be_number(N, PI) :- ). -chars_or_vars(Cs, _) :- +chars_or_vars(Cs, PI) :- + ( '$is_partial_string'(Cs) -> + % use a fast test for the expected case + true + ; chars_or_vars_(Cs, PI) + ). + +chars_or_vars_(Cs, _) :- ( var(Cs) -> ! ; Cs == [] -> ! ). -chars_or_vars([C|Cs], PI) :- +chars_or_vars_([C|Cs], PI) :- ( nonvar(C) -> ( atom(C), atom_length(C, 1) -> chars_or_vars(Cs, PI) ; throw(error(type_error(character, C), PI)) ) - ; chars_or_vars(Cs, PI) + ; chars_or_vars_(Cs, PI) ). From d51cbd67e0a000928da6dd4af9441e3a09e7a5d0 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Fri, 25 Apr 2025 22:16:44 +0200 Subject: [PATCH 042/122] ENHANCED: partial_string/3 no longer creates atoms As a consequence, resulting strings are now quickly reclaimed on backtracking. This addresses #2912. Test case: :- use_module(library(iso_ext)). :- use_module(library(lists)). ab(a). ab(b). Sample query: ?- length(Ls, 1_000_000), maplist(ab, Ls), partial_string(Ls, Es0, []), Es0 == Ls. Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; Ls = "aaaaaaaaaaaaaaaaaaa ...", Es0 = "aaaaaaaaaaaaaaaaaaa ..." ; ... . running in constant memory. --- src/lib/iso_ext.pl | 13 ++++++------- src/machine/system_calls.rs | 38 +++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index 5c779b10..fc36f5dd 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -22,6 +22,7 @@ but they're not part of the ISO Prolog standard at the moment. copy_term/3]). :- use_module(library(error), [can_be/2, + must_be/2, domain_error/3, instantiation_error/1, type_error/3]). @@ -275,17 +276,15 @@ call_with_inference_limit(_, _, R, Bb, B) :- ; nonvar(R) ). -%% partial_string(String, L, L0) +%% partial_string(String, Ls0, Ls) % % Explicitly construct a partial string "manually". It can be used as an optimized append/3. % It's not recommended to use this predicate in application code. -partial_string(String, L, L0) :- +partial_string(String, Ls0, Ls) :- + must_be(chars, String), ( String == [] -> - L = L0 - ; catch(atom_chars(Atom, String), - error(E, _), - throw(error(E, partial_string/3))), - '$create_partial_string'(Atom, L, L0) + Ls0 = Ls + ; '$create_partial_string'(String, Ls0, Ls) ). %% partial_string(+String) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 43bd632a..0570e1e3 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2479,30 +2479,32 @@ impl Machine { #[inline(always)] pub(crate) fn create_partial_string(&mut self) { - let atom = cell_as_atom!(self.deref_register(1)); + let a1 = self.deref_register(1); - if atom == atom!("") { - self.machine_st.fail = true; - return; - } + if let Some(str_like) = self.machine_st.value_to_str_like(a1) { + let str = match str_like { + AtomOrString::String(string) => string, + _ => { + unreachable!() + } + }; - let pstr_loc_cell = step_or_resource_error!( - self.machine_st, - self.machine_st.heap.allocate_pstr(&*atom.as_str()) - ); + let pstr_loc_cell = + step_or_resource_error!(self.machine_st, self.machine_st.heap.allocate_pstr(&str)); - let tail_loc = self.machine_st.heap.cell_len(); + let tail_loc = self.machine_st.heap.cell_len(); - step_or_resource_error!( - self.machine_st, - self.machine_st.heap.push_cell(heap_loc_as_cell!(tail_loc)) - ); + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.push_cell(heap_loc_as_cell!(tail_loc)) + ); - unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_cell); + unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_cell); - if !self.machine_st.fail { - let tail = self.machine_st.registers[3]; - unify!(self.machine_st, tail, heap_loc_as_cell!(tail_loc)); + if !self.machine_st.fail { + let tail = self.machine_st.registers[3]; + unify!(self.machine_st, tail, heap_loc_as_cell!(tail_loc)); + } } } From 073ec4c1d0c81d165cb33483e01c0a2ebc038829 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Fri, 25 Apr 2025 18:39:21 +0200 Subject: [PATCH 043/122] FIXED: invoke correct predicate Noted by Oleg Finkelstein. Many thanks! --- src/lib/builtins.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index df7696f9..3100f7f9 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1736,7 +1736,7 @@ chars_or_vars_([C|Cs], PI) :- ( nonvar(C) -> ( atom(C), atom_length(C, 1) -> - chars_or_vars(Cs, PI) + chars_or_vars_(Cs, PI) ; throw(error(type_error(character, C), PI)) ) ; chars_or_vars_(Cs, PI) From cb9b988905561b7dd90951b9ac1d3ce1f39fbfe7 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 26 Apr 2025 21:11:27 -0700 Subject: [PATCH 044/122] allow unused_parens around let statement in functor! macro --- src/functor_macro.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/functor_macro.rs b/src/functor_macro.rs index 444c8432..7cc48eaa 100644 --- a/src/functor_macro.rs +++ b/src/functor_macro.rs @@ -131,6 +131,7 @@ macro_rules! build_functor { [$($subfunctor),*]) }); ([string($s:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({ + #[allow(unused_parens)] let string = $s; let pstr_len = cell_index!(Heap::compute_pstr_size(&string)) as u64; let result_len = 1 + count!($($dt)*) + $res_len; From a9847eef656de437647bce896a1d65837c5c1758 Mon Sep 17 00:00:00 2001 From: bakaq Date: Sat, 26 Apr 2025 23:34:53 -0300 Subject: [PATCH 045/122] Migrate to strict and exposed provenance --- src/arena.rs | 4 +- src/atom_table.rs | 4 +- src/ffi.rs | 2 +- src/heap_print.rs | 2 +- src/machine/heap.rs | 2 +- src/machine/lib_machine/mod.rs | 2 +- src/machine/stack.rs | 85 ++++++++++++++++------------------ src/macros.rs | 10 ++-- src/offset_table.rs | 7 ++- src/raw_block.rs | 10 ++-- src/types.rs | 14 +++--- 11 files changed, 69 insertions(+), 73 deletions(-) diff --git a/src/arena.rs b/src/arena.rs index 47de6fa3..a9f9a76b 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -611,12 +611,12 @@ mod tests { let mut wam = MockWAM::new(); #[cfg(target_pointer_width = "32")] let const_value = HeapCellValue::from(ConsPtr::build_with( - 0x0000_0431 as *const _, + std::ptr::without_provenance(0x0000_0431), ConsPtrMaskTag::Cons, )); #[cfg(target_pointer_width = "64")] let const_value = HeapCellValue::from(ConsPtr::build_with( - 0x0000_5555_ff00_0431 as *const _, + std::ptr::without_provenance(0x0000_5555_ff00_0431), ConsPtrMaskTag::Cons, )); diff --git a/src/atom_table.rs b/src/atom_table.rs index 8b366549..12910753 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -516,12 +516,12 @@ impl AtomTable { } }; - let ptr_base = block_epoch.block.base as usize; + let ptr_base = block_epoch.block.base.addr(); write_to_ptr(string, len_ptr); let atom = AtomCell::new() - .with_name((STRINGS.len() + len_ptr as usize - ptr_base) as u64) + .with_name((STRINGS.len() + len_ptr.addr() - ptr_base) as u64) .with_arity(0) .with_f(false) .with_m(false) diff --git a/src/ffi.rs b/src/ffi.rs index 4832bad1..a3015b6d 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -517,7 +517,7 @@ impl Value { fn as_ptr(&mut self) -> Result<*mut c_void, FFIError> { match self { Value::CString(ref mut cstr) => Ok(&mut *cstr as *mut _ as *mut c_void), - Value::Int(n) => Ok(*n as *mut c_void), + Value::Int(n) => Ok(std::ptr::with_exposed_provenance_mut(*n as usize)), _ => Err(FFIError::ValueCast), } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 7bd227e2..9f1efee7 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -984,7 +984,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { #[inline] fn print_raw_ptr(&mut self, ptr: *const ArenaHeader) { - append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize)); + append_str!(self, &format!("0x{:x}", ptr.addr())); } fn print_number(&mut self, max_depth: usize, n: NumberFocus, op: &Option) { diff --git a/src/machine/heap.rs b/src/machine/heap.rs index c12af9d1..8d832f29 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -97,7 +97,7 @@ unsafe fn scan_slice_to_str(heap_slice: &[u8]) -> HeapStringScan { .unwrap_or(heap_slice.len()); let zero_byte_addr = heap_slice.as_ptr().add(string_len); - let sentinel_len = pstr_sentinel_length(zero_byte_addr as usize); + let sentinel_len = pstr_sentinel_length(zero_byte_addr.addr()); let tail_idx = cell_index!( (string_len + sentinel_len).next_multiple_of(ALIGN) + if sentinel_len <= 1 { heap_index!(1) } else { 0 } diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index d11419e0..7e87dc00 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -297,7 +297,7 @@ impl Term { Term::atom(alias.as_str().to_string()) } else { Term::compound("$stream", [ - Term::integer(stream.as_ptr() as usize) + Term::integer(stream.as_ptr().addr()) ]) }; term_stack.push(stream_term); diff --git a/src/machine/stack.rs b/src/machine/stack.rs index f0b136fa..4247149f 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -59,9 +59,10 @@ impl Index for AndFrame { unsafe { let ptr = self as *const crate::machine::stack::AndFrame as *const u8; - let ptr = ptr as usize + prelude_offset + index_offset; - &*(ptr as *const HeapCellValue) + // This address falls outside the provenance for self, therefore we have to get it + // from exposed provenance. + &*std::ptr::with_exposed_provenance(ptr.addr() + prelude_offset + index_offset) } } } @@ -72,10 +73,11 @@ impl IndexMut for AndFrame { let index_offset = (index - 1) * mem::size_of::(); unsafe { - let ptr = self as *mut crate::machine::stack::AndFrame as *const u8; - let ptr = ptr as usize + prelude_offset + index_offset; + let ptr = self as *mut crate::machine::stack::AndFrame as *mut u8; - &mut *(ptr as *mut HeapCellValue) + // This address falls outside the provenance for self, therefore we have to get it + // from exposed provenance. + &mut *std::ptr::with_exposed_provenance_mut(ptr.addr() + prelude_offset + index_offset) } } } @@ -85,20 +87,14 @@ impl Index for Stack { #[inline] fn index(&self, index: usize) -> &Self::Output { - unsafe { - let ptr = self.buf.base as usize + index; - &*(ptr as *const HeapCellValue) - } + unsafe { &*self.buf.base.add(index).cast() } } } impl IndexMut for Stack { #[inline] fn index_mut(&mut self, index: usize) -> &mut Self::Output { - unsafe { - let ptr = self.buf.base as usize + index; - &mut *(ptr as *mut HeapCellValue) - } + unsafe { &mut *self.buf.base.add(index).cast_mut().cast() } } } @@ -132,9 +128,10 @@ impl Index for OrFrame { unsafe { let ptr = self as *const crate::machine::stack::OrFrame as *const u8; - let ptr = ptr as usize + prelude_offset + index_offset; - &*(ptr as *const HeapCellValue) + // This address falls outside the provenance for self, therefore we have to get it + // from exposed provenance. + &*std::ptr::with_exposed_provenance(ptr.addr() + prelude_offset + index_offset) } } } @@ -146,10 +143,11 @@ impl IndexMut for OrFrame { let index_offset = index * mem::size_of::(); unsafe { - let ptr = self as *mut crate::machine::stack::OrFrame as *const u8; - let ptr = ptr as usize + prelude_offset + index_offset; + let ptr = self as *mut crate::machine::stack::OrFrame as *mut u8; - &mut *(ptr as *mut HeapCellValue) + // This address falls outside the provenance for self, therefore we have to get it + // from exposed provenance. + &mut *std::ptr::with_exposed_provenance_mut(ptr.addr() + prelude_offset + index_offset) } } } @@ -187,15 +185,19 @@ impl Stack { let frame_size = AndFrame::size_of(num_cells); unsafe { - let e = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize; + let e = (*self.buf.ptr.get_mut()).addr() - self.buf.base.addr(); let new_ptr = self.alloc(frame_size); let mut offset = prelude_size::(); for idx in 0..num_cells { - ptr::write( - new_ptr.add(offset) as *mut HeapCellValue, - stack_loc_as_cell!(AndFrame, e, idx + 1), - ); + let cell_ptr = new_ptr.add(offset) as *mut HeapCellValue; + ptr::write(cell_ptr, stack_loc_as_cell!(AndFrame, e, idx + 1)); + + // Because in the Index and IndexMut inplementations we need to get this from + // exposed provenance, we need to expose the provenance here, even though we don't + // actually use the value for anything. This is a reminder that `expose_provenance` + // isn't just a cast from a pointer to an integer but has actual side effects. + cell_ptr.expose_provenance(); offset += mem::size_of::(); } @@ -208,22 +210,26 @@ impl Stack { } pub(crate) fn top(&self) -> usize { - unsafe { (*self.buf.ptr.get()) as usize - self.buf.base as usize } + unsafe { (*self.buf.ptr.get()).addr() - self.buf.base.addr() } } pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> usize { let frame_size = OrFrame::size_of(num_cells); unsafe { - let b = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize; + let b = (*self.buf.ptr.get_mut()).addr() - self.buf.base.addr(); let new_ptr = self.alloc(frame_size); let mut offset = prelude_size::(); for idx in 0..num_cells { - ptr::write( - new_ptr.byte_add(offset) as *mut HeapCellValue, - stack_loc_as_cell!(OrFrame, b, idx), - ); + let cell_ptr = new_ptr.byte_add(offset) as *mut HeapCellValue; + ptr::write(cell_ptr, stack_loc_as_cell!(OrFrame, b, idx)); + + // Because in the Index and IndexMut inplementations we need to get this from + // exposed provenance, we need to expose the provenance here, even though we don't + // actually use the value for anything. This is a reminder that `expose_provenance` + // isn't just a cast from a pointer to an integer but has actual side effects. + cell_ptr.expose_provenance(); offset += mem::size_of::(); } @@ -237,10 +243,7 @@ impl Stack { #[inline(always)] pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame { - unsafe { - let ptr = self.buf.base as usize + e; - &*(ptr as *const AndFrame) - } + unsafe { &*self.buf.base.add(e).cast() } } #[inline(always)] @@ -254,26 +257,20 @@ impl Stack { #[inline(always)] pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame { - unsafe { - let ptr = self.buf.base as usize + b; - &*(ptr as *const OrFrame) - } + unsafe { &*self.buf.base.add(b).cast() } } #[inline(always)] pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame { - unsafe { - let ptr = self.buf.base as usize + b; - &mut *(ptr as *mut OrFrame) - } + unsafe { &mut *self.buf.base.add(b).cast_mut().cast() } } #[inline(always)] pub(crate) fn truncate(&mut self, b: usize) { - let base = self.buf.base as usize + b; + let base = unsafe { self.buf.base.add(b) }; - if base < (*self.buf.ptr.get_mut()) as usize { - *self.buf.ptr.get_mut() = base as *mut _; + if base < (*self.buf.ptr.get_mut()) { + *self.buf.ptr.get_mut() = base.cast_mut(); } } } diff --git a/src/macros.rs b/src/macros.rs index 7aeba996..5347af3c 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -146,11 +146,11 @@ macro_rules! typed_arena_ptr_as_cell { macro_rules! raw_ptr_as_cell { ($ptr:expr) => {{ // Cell is 64-bit, but raw ptr is 32-bit in 32-bit systems - // TODO use <*{const,mut} _>::addr instead of as when the strict_provenance feature is stable rust-lang/rust#95228 - // we might need <*{const,mut} _>::expose_provenance for strict provenance, depending on how we recreate a pointer later - let ptr : *const _ = $ptr; - debug_assert!(!$ptr.is_null()); - HeapCellValue::from_ptr_addr(ptr as usize) + let ptr: *const _ = $ptr; + // This needs to expose provenance because it needs to be turned back into a pointer + // in contexts where there is no available provenance locally. For example, in + // `ConsPtr::as_ptr`. + HeapCellValue::from_ptr_addr(ptr.expose_provenance()) }}; } diff --git a/src/offset_table.rs b/src/offset_table.rs index 5afcf89b..7b47b96f 100644 --- a/src/offset_table.rs +++ b/src/offset_table.rs @@ -141,9 +141,8 @@ where ptr::write(ptr as *mut T, value); - let value = as OffsetTable>::Offset::from( - ptr as usize - block_epoch.base as usize, - ); + let value = + as OffsetTable>::Offset::from(ptr.addr() - block_epoch.base.addr()); // AtomTable would have to update the index table at this point // explicit drop to ensure we don't accidentally drop it early @@ -270,7 +269,7 @@ where #[inline(always)] pub fn as_offset(&self) -> as OffsetTable>::Offset { as OffsetTable>::Offset::from( - self.0.get() as usize - RcuRef::get_root(&self.0).base as usize, + self.0.get().addr() - RcuRef::get_root(&self.0).base.addr(), ) } } diff --git a/src/raw_block.rs b/src/raw_block.rs index da757415..3c39c77d 100644 --- a/src/raw_block.rs +++ b/src/raw_block.rs @@ -66,8 +66,8 @@ impl RawBlock { false } else { self.base = new_base; - self.top = (self.base as usize + size * 2) as *const _; - *self.ptr.get_mut() = (self.base as usize + size) as *mut _; + self.top = self.base.add(size * 2); + *self.ptr.get_mut() = self.base.add(size).cast_mut(); true } } @@ -83,7 +83,7 @@ impl RawBlock { // allocation failed None } else { - let allocated = (*self.ptr.get()) as usize - self.base as usize; + let allocated = (*self.ptr.get()).addr() - self.base.addr(); self.base.copy_to(new_block.base.cast_mut(), allocated); *new_block.ptr.get_mut() = new_block.base.add(allocated).cast_mut(); Some(new_block) @@ -93,7 +93,7 @@ impl RawBlock { #[inline] pub fn size(&self) -> usize { - self.top as usize - self.base as usize + self.top.addr() - self.base.addr() } #[inline(always)] @@ -105,7 +105,7 @@ impl RawBlock { self.base ); - self.top as usize - (*self.ptr.get()) as usize + self.top.addr() - (*self.ptr.get()).addr() } pub unsafe fn alloc(&self, size: usize) -> *mut u8 { diff --git a/src/types.rs b/src/types.rs index d68f605d..e6dda7d9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -93,7 +93,7 @@ impl ConsPtr { #[inline(always)] pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self { ConsPtr::new() - .with_ptr(ptr as *const u8 as u64) + .with_ptr(ptr.expose_provenance() as u64) .with_f(false) .with_m(false) .with_tag(tag) @@ -102,7 +102,7 @@ impl ConsPtr { #[inline(always)] pub fn as_ptr(self) -> *mut u8 { let addr: u64 = self.ptr(); - addr as usize as *mut _ + std::ptr::with_exposed_provenance_mut(addr as usize) } #[inline(always)] @@ -377,7 +377,7 @@ where { #[inline] fn from(arena_ptr: TypedArenaPtr) -> HeapCellValue { - HeapCellValue::from(arena_ptr.header_ptr() as u64) + HeapCellValue::from(arena_ptr.header_ptr().expose_provenance() as u64) } } @@ -402,7 +402,7 @@ impl From for HeapCellValue { #[inline(always)] fn from(cons_ptr: ConsPtr) -> HeapCellValue { HeapCellValue::from_bytes( - ConsPtr::from(cons_ptr.as_ptr() as u64) + ConsPtr::from(cons_ptr.as_ptr().expose_provenance() as u64) .with_tag(ConsPtrMaskTag::Cons) .with_m(false) .into_bytes(), @@ -724,14 +724,14 @@ const_assert!(mem::size_of::() == 8); impl From<*const ArenaHeader> for UntypedArenaPtr { #[inline] fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr { - UntypedArenaPtr::build_with(ptr as usize) + UntypedArenaPtr::build_with(ptr.expose_provenance()) } } impl From<*const IndexPtr> for UntypedArenaPtr { #[inline] fn from(ptr: *const IndexPtr) -> UntypedArenaPtr { - UntypedArenaPtr::build_with(ptr as usize) + UntypedArenaPtr::build_with(ptr.expose_provenance()) } } @@ -751,7 +751,7 @@ impl UntypedArenaPtr { #[inline] pub fn get_ptr(self) -> *const u8 { let addr: u64 = self.ptr(); - addr as usize as *const u8 + std::ptr::with_exposed_provenance(addr as usize) } #[inline] From 4e0493474e911e0a7039f461842c30bb0a77a8da Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 27 Apr 2025 22:27:12 -0700 Subject: [PATCH 046/122] replace deprecated unify_complete_string call with allocate_cstr --- src/machine/system_calls.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 0570e1e3..d47b36e9 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -5115,9 +5115,10 @@ impl Machine { let result_reg = self.deref_register(2); if let Some(code) = self.machine_st.value_to_str_like(code) { match js_sys::eval(&code.as_str()) { - Ok(result) => self.unify_js_value(result, result_reg), - Err(result) => self.unify_js_value(result, result_reg), + Ok(result) => self.unify_js_value(result, result_reg)?, + Err(result) => self.unify_js_value(result, result_reg)?, }; + return Ok(()); } self.machine_st.fail = true; @@ -5125,7 +5126,11 @@ impl Machine { } #[cfg(target_arch = "wasm32")] - fn unify_js_value(&mut self, result: wasm_bindgen::JsValue, result_reg: HeapCellValue) { + fn unify_js_value( + &mut self, + result: wasm_bindgen::JsValue, + result_reg: HeapCellValue, + ) -> CallResult { match result.as_bool() { Some(result) => match result { true => self.machine_st.unify_atom(atom!("true"), result_reg), @@ -5138,8 +5143,10 @@ impl Machine { } None => match result.as_string() { Some(result) => { - let result = AtomTable::build_with(&self.machine_st.atom_tbl, &result); - self.machine_st.unify_complete_string(result, result_reg); + resource_error_call_result!( + self.machine_st, + self.machine_st.heap.allocate_cstr(result.as_str()) + ); } None => { if result.is_null() { @@ -5164,6 +5171,8 @@ impl Machine { }, }, } + + Ok(()) } #[inline(always)] From d6b6eda77d5d31ec0564d05434c14bb9ab37c7c4 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 28 Apr 2025 23:39:52 -0700 Subject: [PATCH 047/122] fix cont function crashes (#2920) --- src/machine/compile.rs | 4 ---- src/machine/machine_state.rs | 18 ------------------ src/machine/system_calls.rs | 17 +++++++++++------ 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 4f0fb1b6..1b2f6bff 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1261,10 +1261,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let code_len = self.wam_prelude.code.len(); let mut code_ptr = code_len; - if key == (atom!("..."), 2) { - print!(""); - } - let mut clauses = vec![]; let mut preprocessor = Preprocessor::new(settings); diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 7c8f1abe..941d9f4d 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -186,26 +186,8 @@ impl IndexMut for MachineState { pub type CallResult = Result<(), Vec>; -/* -#[inline(always)] -pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) { - read_heap_cell!(heap[index], - (HeapCellValueTag::PStr | HeapCellValueTag::CStr) => { - (index, Fixnum::build_with(0)) - } - (HeapCellValueTag::PStrOffset, h) => { - (h, cell_as_fixnum!(heap[index+1])) - } - _ => { - unreachable!() - } - ) -} -*/ - // size may be an upper bound. // true_size is calculated to compute the exact offset. - fn push_var_eq_functors<'a>( heap: &mut Heap, size: usize, diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index d47b36e9..6875edfb 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -5711,7 +5711,6 @@ impl Machine { if addr.get_tag() == HeapCellValueTag::StackVar { section.push_cell(heap_loc_as_cell!(h + 1 + idx)); - self.machine_st.stack[stack_offset] = heap_loc_as_cell!(h + 1 + idx); // have to inline the TrailRef::Ref(RefTag::StackCell) case of MachineState::trail @@ -5730,7 +5729,7 @@ impl Machine { } }); - let chunk = str_loc_as_cell!(self.machine_st.heap.cell_len()); + let chunk = str_loc_as_cell!(h); unify!(self.machine_st, self.machine_st.registers[3], chunk); } @@ -6317,13 +6316,13 @@ impl Machine { let e = and_frame.prelude.e; let e = Fixnum::build_with(i64::try_from(e).unwrap()); - let mut writer = Heap::functor_writer(functor!(atom!("dir_entry"), [fixnum(cp)])); - - let p_functor_cell = step_or_resource_error!(machine_st, writer(&mut machine_st.heap)); - machine_st.unify_fixnum(e, machine_st.registers[2]); if !machine_st.fail { + let mut writer = Heap::functor_writer(functor!(atom!("dir_entry"), [fixnum(cp)])); + let p_functor_cell = + step_or_resource_error!(machine_st, writer(&mut machine_st.heap)); + unify!(machine_st, p_functor_cell, machine_st.registers[3]); } }; @@ -6350,6 +6349,12 @@ impl Machine { // active permanent variables can be read from // it later. let and_frame = self.machine_st.stack.index_and_frame(e); + + if and_frame.prelude.cp == 0 { + self.machine_st.fail = true; + return; + } + let cp = and_frame.prelude.cp - 1; let mut writer = Heap::functor_writer(functor!(atom!("dir_entry"), [fixnum(cp)])); From 8763a42c98b2b16e9cbb649cc16e093382c3444f Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 29 Apr 2025 22:48:13 +0200 Subject: [PATCH 048/122] FIXED: arg/3 for partial strings This address #2924, reported by @haijinSk. Thank you a lot! Example: ?- arg(2, "a", A). A = []. The fact that such a mistake in macro usage is even possible could be a sign that the macro definition should be stricter. --- src/machine/machine_state_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index ede17fa6..baa25394 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -934,7 +934,7 @@ impl MachineState { unify_fn!(*self, pstr_loc_as_cell!(pstr_loc + c.len_utf8()), a3); } else { let tail_idx = Heap::pstr_tail_idx(pstr_loc); - unify_fn!(*self, self.heap[tail_idx]); + unify_fn!(*self, self.heap[tail_idx], a3); } /* From 709dc041ebf7cc47d41a05dc35f7a9a18c8d3691 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Thu, 1 May 2025 09:18:00 +0200 Subject: [PATCH 049/122] FIXED: correct partial string tail calculation in arg/3 This addresses another aspect of #2924, found by @haijinSk. Thank you again! Example: ?- "aaaaaaa" = [_,_,_,_,_,_|T], arg(2, T, 2). false. --- src/machine/machine_state_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index baa25394..038a16d7 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -933,7 +933,7 @@ impl MachineState { if char_iter.next().is_some() { unify_fn!(*self, pstr_loc_as_cell!(pstr_loc + c.len_utf8()), a3); } else { - let tail_idx = Heap::pstr_tail_idx(pstr_loc); + let tail_idx = Heap::pstr_tail_idx(pstr_loc + c.len_utf8()); unify_fn!(*self, self.heap[tail_idx], a3); } From 8b009448f4630b6efa3dfd84f199895cd3f106f3 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 3 May 2025 22:04:04 -0700 Subject: [PATCH 050/122] correct threshold marking in copy_structure (#2920) --- src/machine/copier.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/machine/copier.rs b/src/machine/copier.rs index 57e034af..78658c4a 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -426,7 +426,7 @@ impl CopyTermState { let index_cell = self.target[addr.saturating_sub(1)]; - *self.value_at_scan() = if get_structure_index(index_cell).is_some() { + let str_cell = if get_structure_index(index_cell).is_some() { // copy the index pointer trailing this // inlined or expanded goal. let mut writer = self.target.reserve(1).unwrap(); @@ -440,11 +440,12 @@ impl CopyTermState { str_loc_as_cell!(threshold) }; + *self.value_at_scan() = str_cell; self.target.copy_slice_to_end(addr .. addr + 1 + arity)?; let trail_item = mem::replace( &mut self.target[addr], - str_loc_as_cell!(threshold), + str_cell, ); self.trail.push((TrailRef::heap_cell(addr), trail_item)); From d01557f3c188358d16927075414fac492a9631a4 Mon Sep 17 00:00:00 2001 From: bakaq Date: Sun, 4 May 2025 21:01:50 -0300 Subject: [PATCH 051/122] Add scan_slice_to_str_from_start --- src/machine/heap.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 8d832f29..7711b3b2 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -89,7 +89,7 @@ pub struct HeapStringScan<'a> { pub tail_idx: usize, } -// return the string at ptr and the tail location relative to ptr. +// The heap_slice should be inside the heap unsafe fn scan_slice_to_str(heap_slice: &[u8]) -> HeapStringScan { let string_len = heap_slice .iter() @@ -111,6 +111,28 @@ unsafe fn scan_slice_to_str(heap_slice: &[u8]) -> HeapStringScan { } } +// Same as scan_slice_to_str but assumes that the slice is from the start of a string. +// Can be used on strings out of the heap. +unsafe fn scan_slice_to_str_from_start(heap_slice: &[u8]) -> HeapStringScan { + let string_len = heap_slice + .iter() + .position(|b| *b == 0u8) + .unwrap_or(heap_slice.len()); + + let sentinel_len = pstr_sentinel_length(string_len); + let tail_idx = cell_index!( + (string_len + sentinel_len).next_multiple_of(ALIGN) + + if sentinel_len <= 1 { heap_index!(1) } else { 0 } + ); + + let str_slice = &heap_slice[..string_len]; + + HeapStringScan { + string: std::str::from_utf8_unchecked(str_slice), + tail_idx, + } +} + #[derive(Debug, Clone, Copy)] pub(crate) enum PStrContinuable { PStrOffset(usize), @@ -904,7 +926,8 @@ impl Heap { continue; } - let HeapStringScan { string, tail_idx } = unsafe { scan_slice_to_str(src_bytes) }; + let HeapStringScan { string, tail_idx } = + unsafe { scan_slice_to_str_from_start(src_bytes) }; src_bytes = &src_bytes[string.len()..]; byte_size += heap_index!(tail_idx); From 87ca083cfab811bfd755e22b55a0ac02f36b2bc6 Mon Sep 17 00:00:00 2001 From: bakaq Date: Mon, 5 May 2025 00:15:14 -0300 Subject: [PATCH 052/122] Align the heap to the size of heap cells --- src/machine/heap.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 7711b3b2..dc4d2ce0 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -21,7 +21,9 @@ impl Drop for Heap { fn drop(&mut self) { if !self.inner.ptr.is_null() { unsafe { - let layout = alloc::Layout::array::(self.inner.byte_cap).unwrap(); + let layout = + alloc::Layout::from_size_align(self.inner.byte_cap, size_of::()) + .unwrap(); alloc::dealloc(self.inner.ptr, layout); } } @@ -53,7 +55,8 @@ impl InnerHeap { 2 * self.byte_cap }; - let new_layout = alloc::Layout::array::(new_cap).unwrap(); + let new_layout = + alloc::Layout::from_size_align(new_cap, size_of::()).unwrap(); assert!( new_layout.size() <= isize::MAX as usize, @@ -63,7 +66,8 @@ impl InnerHeap { let new_ptr = if self.byte_cap == 0 { alloc::alloc(new_layout) } else { - let old_layout = alloc::Layout::array::(self.byte_cap).unwrap(); + let old_layout = + alloc::Layout::from_size_align(self.byte_cap, size_of::()).unwrap(); alloc::realloc(self.ptr, old_layout, new_layout.size()) }; @@ -585,7 +589,11 @@ impl Heap { pub(crate) fn with_cell_capacity(cap: usize) -> Result { let ptr = unsafe { - let layout = alloc::Layout::array::(cap).unwrap(); + let layout = alloc::Layout::from_size_align( + cap * size_of::(), + size_of::(), + ) + .unwrap(); alloc::alloc(layout) }; @@ -672,7 +680,9 @@ impl Heap { pub(crate) fn clear(&mut self) { unsafe { - let layout = alloc::Layout::array::(self.inner.byte_cap).unwrap(); + let layout = + alloc::Layout::from_size_align(self.inner.byte_cap, size_of::()) + .unwrap(); alloc::dealloc(self.inner.ptr, layout); } From cbdd0fbf150c68126d5f2cccf13badc3c38cc1ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Wed, 22 Jan 2025 21:10:44 +0100 Subject: [PATCH 053/122] make Fixnum::build_with harder to accidentally misuse change trait bound order for better --- src/arena.rs | 54 +++--- src/arithmetic.rs | 20 ++- src/forms.rs | 4 +- src/functor_macro.rs | 2 +- src/heap_print.rs | 7 +- src/indexing.rs | 6 +- src/machine/arithmetic_ops.rs | 9 +- src/machine/attributed_variables.rs | 18 +- src/machine/dispatch.rs | 73 +++++--- src/machine/loader.rs | 4 +- src/machine/machine_state.rs | 5 +- src/machine/machine_state_impl.rs | 14 +- src/machine/mod.rs | 6 +- src/machine/system_calls.rs | 253 +++++++++++++++++----------- src/macros.rs | 6 - src/parser/ast.rs | 131 +++++++++++--- src/parser/lexer.rs | 17 +- src/parser/parser.rs | 6 +- src/types.rs | 10 ++ 19 files changed, 422 insertions(+), 223 deletions(-) diff --git a/src/arena.rs b/src/arena.rs index a9f9a76b..a6ccb921 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -784,7 +784,9 @@ mod tests { _ => { unreachable!() } ); - let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 54)); + let fixnum_b_cell = fixnum_as_cell!( + Fixnum::build_with_checked(1i64 << 54).expect("1 << 54 fits in Fixnum") + ); assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum); @@ -793,41 +795,29 @@ mod tests { None => unreachable!(), } - if Fixnum::build_with_checked(1 << 56).is_ok() { - unreachable!() - } + Fixnum::build_with_checked(1i64 << 56).expect_err("1 << 56 is too large for fixnum"); - if Fixnum::build_with_checked(i64::MAX).is_ok() { - unreachable!() - } + Fixnum::build_with_checked(i64::MAX).expect_err("i64::MAX is too large for Fixnum"); + Fixnum::build_with_checked(i64::MIN).expect_err("i64::MIN is too small for Fixnum"); + assert_eq!( + Fixnum::build_with_checked(-1i64) + .expect("-1 fits in fixnum") + .get_num(), + -1 + ); - if Fixnum::build_with_checked(i64::MIN).is_ok() { - unreachable!() - } + Fixnum::build_with_checked((1i64 << 55) - 1) + .expect("(1 << 55) - 1 is the largest value that fits in Fixnum"); - match Fixnum::build_with_checked(-1) { - Ok(n) => assert_eq!(n.get_num(), -1), - _ => unreachable!(), - } + Fixnum::build_with_checked(-(1i64 << 55)) + .expect("-(1 << 55) is the smallest value that fits in fixnum"); + Fixnum::build_with_checked(-(1i64 << 55) - 1) + .expect_err("-(1<<55) - 1 is too small for Fixnum"); - match Fixnum::build_with_checked((1 << 55) - 1) { - Ok(n) => assert_eq!(n.get_num(), (1 << 55) - 1), - _ => unreachable!(), - } - - match Fixnum::build_with_checked(-(1 << 55)) { - Ok(n) => assert_eq!(n.get_num(), -(1 << 55)), - _ => unreachable!(), - } - - if Fixnum::build_with_checked(-(1 << 55) - 1).is_ok() { - unreachable!() - } - - match Fixnum::build_with_checked(-1) { - Ok(n) => assert_eq!(-n, Fixnum::build_with(1)), - _ => unreachable!(), - } + assert_eq!( + -Fixnum::build_with_checked(-1i64).expect("-1 fits in Fixnum"), + Fixnum::build_with(1) + ); // float diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 2bdcc315..2f0df28d 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -358,9 +358,8 @@ impl<'a> ArithmeticEvaluator<'a> { pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result { match n { &Number::Integer(i) => { - let result = (&*i).try_into(); - if let Ok(value) = result { - Ok(fixnum!(Number, value, arena)) + if let Ok(value) = Fixnum::build_with_checked(&*i) { + Ok(Number::Fixnum(value)) } else { Ok(*n) } @@ -369,11 +368,14 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result { let f = f.floor(); - const I64_MIN_TO_F: OrderedFloat = OrderedFloat(i64::MIN as f64); - const I64_MAX_TO_F: OrderedFloat = OrderedFloat(i64::MAX as f64); + const FIXNUM_MIN_TO_F: OrderedFloat = OrderedFloat(Fixnum::MIN as f64); + const FIXNUM_MAX_TO_F: OrderedFloat = OrderedFloat(Fixnum::MAX as f64); - if I64_MIN_TO_F <= f && f <= I64_MAX_TO_F { - Ok(fixnum!(Number, f.into_inner() as i64, arena)) + if (FIXNUM_MIN_TO_F..=FIXNUM_MAX_TO_F).contains(&f) { + Ok(Number::Fixnum( + // Safety: We checked that the value is in range + unsafe { Fixnum::build_with_unchecked(f.into_inner() as i64) }, + )) } else { Ok(Number::Integer(arena_alloc!( Integer::try_from(classify_float(f.0)?).unwrap_or_else(|_| { @@ -386,8 +388,8 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result { let floor = r.floor(); - if let Ok(value) = (&floor).try_into() { - Ok(fixnum!(Number, value, arena)) + if let Ok(value) = Fixnum::build_with_checked(&floor) { + Ok(Number::Fixnum(value)) } else { Ok(Number::Integer(arena_alloc!(floor, arena))) } diff --git a/src/forms.rs b/src/forms.rs index 21a5cc91..0779d5b8 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -697,14 +697,14 @@ impl ArenaFrom for Number { impl ArenaFrom for Number { #[inline] fn arena_from(value: u32, _arena: &mut Arena) -> Number { - Number::Fixnum(Fixnum::build_with(value as i64)) + Number::Fixnum(Fixnum::build_with(value)) } } impl ArenaFrom for Number { #[inline] fn arena_from(value: i32, _arena: &mut Arena) -> Number { - Number::Fixnum(Fixnum::build_with(value as i64)) + Number::Fixnum(Fixnum::build_with(value)) } } diff --git a/src/functor_macro.rs b/src/functor_macro.rs index 7cc48eaa..2725aa9d 100644 --- a/src/functor_macro.rs +++ b/src/functor_macro.rs @@ -78,7 +78,7 @@ macro_rules! build_functor { $res_len:expr, [$($subfunctor:expr),*]) => ({ build_functor!([$($dt($($value),*)),*], - [$($res, )* FunctorElement::Cell(fixnum_as_cell!(Fixnum::build_with($e as i64)))], + [$($res, )* FunctorElement::Cell(fixnum_as_cell!(/*FIXME this is not safe*/ unsafe{Fixnum::build_with_unchecked($e as i64)}))], 1 + $res_len, [$($subfunctor),*]) }); diff --git a/src/heap_print.rs b/src/heap_print.rs index 9f1efee7..c23344bf 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1500,7 +1500,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::NumberFocus( max_depth, - NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port as i64))), + NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port))), None, )); self.state_stack.push(TokenOrRedirect::Comma); @@ -1527,7 +1527,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { TokenOrRedirect::NumberFocus( max_depth, - NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx_ptr_p))), + NumberFocus::Unfocused(Number::Fixnum( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(idx_ptr_p) }, + )), None, ) }; diff --git a/src/indexing.rs b/src/indexing.rs index b9bdfc28..345533ad 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1104,11 +1104,7 @@ pub(crate) fn constant_key_alternatives(constant: Literal) -> Option { _ => return None, }; - if let Ok(n) = n.try_into() { - Fixnum::build_with_checked(n).map(Literal::Fixnum).ok() - } else { - None - } + Fixnum::build_with_checked(n).map(Literal::Fixnum).ok() } #[derive(Debug)] diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 43bb3723..d1667795 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -198,11 +198,10 @@ pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number { pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number { match n { Number::Fixnum(n) => { - if let Some(n) = n.get_num().checked_abs() { - fixnum!(Number, n, arena) + if let Some(n) = n.checked_abs() { + Number::Fixnum(n) } else { - let arena_int = Integer::from(n.get_num()); - Number::arena_from(arena_int.abs(), arena) + Number::arena_from(Integer::from(Fixnum::MAX + 1), arena) } } Number::Integer(n) => { @@ -1105,7 +1104,7 @@ pub(crate) fn round(num: Number, arena: &mut Arena) -> Result Result { match n1 { - Number::Fixnum(n) => Ok(Number::Fixnum(Fixnum::build_with(!n.get_num()))), + Number::Fixnum(n) => Ok(Number::Fixnum(!n)), Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)), _ => { let stub_gen = || { diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 34e4755d..4aaf45ee 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -120,9 +120,21 @@ impl MachineState { and_frame[i] = self.registers[i]; } - and_frame[arity + 1] = fixnum_as_cell!(Fixnum::build_with(self.b0 as i64)); - and_frame[arity + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64)); - and_frame[arity + 3] = fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64)); + and_frame[arity + 1] = + fixnum_as_cell!( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(self.b0 as i64) } + ); + and_frame[arity + 2] = + fixnum_as_cell!( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(self.num_of_args as i64) } + ); + and_frame[arity + 3] = + fixnum_as_cell!( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(self.attr_var_init.cp as i64) } + ); self.verify_attributes()?; diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 3a88221a..20dfd8ee 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -1021,9 +1021,13 @@ impl Machine { match self.find_living_dynamic_else(p + next_i) { Some(_) => { self.machine_st.registers - [self.machine_st.num_of_args + 1] = fixnum_as_cell!( - Fixnum::build_with(self.machine_st.cc as i64) - ); + [self.machine_st.num_of_args + 1] = + fixnum_as_cell!(unsafe { + /* FIXME this is not safe */ + Fixnum::build_with_unchecked( + self.machine_st.cc as i64, + ) + }); self.machine_st.num_of_args += 1; self.try_me_else(next_i); @@ -1042,10 +1046,11 @@ impl Machine { .prelude .num_cells; - self.machine_st.cc = cell_as_fixnum!( + self.machine_st.cc = unsafe { self.machine_st.stack [stack_loc!(OrFrame, self.machine_st.b, n - 1)] - ) + .to_fixnum_or_cut_point_unchecked() + } .get_num() as usize; @@ -1095,7 +1100,12 @@ impl Machine { Some(_) => { self.machine_st.registers [self.machine_st.num_of_args + 1] = fixnum_as_cell!( - Fixnum::build_with(self.machine_st.cc as i64) + /* FIXME this is not safe */ + unsafe { + Fixnum::build_with_unchecked( + self.machine_st.cc as i64, + ) + } ); self.machine_st.num_of_args += 1; @@ -1115,10 +1125,11 @@ impl Machine { .prelude .num_cells; - self.machine_st.cc = cell_as_fixnum!( + self.machine_st.cc = unsafe { self.machine_st.stack [stack_loc!(OrFrame, self.machine_st.b, n - 1)] - ) + .to_fixnum_or_cut_point_unchecked() + } .get_num() as usize; @@ -1174,7 +1185,10 @@ impl Machine { &Instruction::GetLevel(r) => { let b0 = self.machine_st.b0; - self.machine_st[r] = fixnum_as_cell!(Fixnum::as_cutpoint(b0 as i64)); + self.machine_st[r] = fixnum_as_cell!( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(b0 as i64) }.as_cutpoint() + ); self.machine_st.p += 1; } &Instruction::GetPrevLevel(r) => { @@ -1185,12 +1199,18 @@ impl Machine { .prelude .b; - self.machine_st[r] = fixnum_as_cell!(Fixnum::as_cutpoint(prev_b as i64)); + self.machine_st[r] = fixnum_as_cell!( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(prev_b as i64) }.as_cutpoint() + ); self.machine_st.p += 1; } &Instruction::GetCutPoint(r) => { self.machine_st[r] = - fixnum_as_cell!(Fixnum::as_cutpoint(self.machine_st.b as i64)); + fixnum_as_cell!(/* FIXME this is not safe */ unsafe { + Fixnum::build_with_unchecked(self.machine_st.b as i64) + } + .as_cutpoint()); self.machine_st.p += 1; } &Instruction::Cut(r) => { @@ -3150,10 +3170,14 @@ impl Machine { match self.find_living_dynamic(oi, ii + 1) { Some(_) => { self.machine_st.registers - [self.machine_st.num_of_args + 1] = - fixnum_as_cell!(Fixnum::build_with( - self.machine_st.cc as i64 - )); + [self.machine_st.num_of_args + 1] = fixnum_as_cell!( + /* FIXME this is not safe */ + unsafe { + Fixnum::build_with_unchecked( + self.machine_st.cc as i64, + ) + } + ); self.machine_st.num_of_args += 1; self.indexed_try(offset); @@ -3175,10 +3199,11 @@ impl Machine { .prelude .num_cells; - self.machine_st.cc = cell_as_fixnum!( + self.machine_st.cc = unsafe { self.machine_st.stack [stack_loc!(OrFrame, b, n - 1)] - ) + .to_fixnum_or_cut_point_unchecked() + } .get_num() as usize; @@ -5256,8 +5281,11 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st.registers[5])); - self.machine_st - .unify_fixnum(Fixnum::build_with(n as i64), r); + self.machine_st.unify_fixnum( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(n as i64) }, + r, + ); } self.machine_st.call_at_index(2, p); @@ -5299,8 +5327,11 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st.registers[5])); - self.machine_st - .unify_fixnum(Fixnum::build_with(n as i64), r); + self.machine_st.unify_fixnum( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(n as i64) }, + r, + ); } self.machine_st.execute_at_index(2, p); diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 89b83ed3..c18eceda 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -2344,7 +2344,9 @@ impl Machine { MetaSpec::Either => atom_as_cell!(atom!("?")), MetaSpec::Colon => atom_as_cell!(atom!(":")), MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { - fixnum_as_cell!(Fixnum::build_with(*arg_num as i64)) + fixnum_as_cell!(/* FIXME this is not safe */ unsafe { + Fixnum::build_with_unchecked(*arg_num as i64) + }) } }); } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 941d9f4d..e3236483 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -1003,7 +1003,10 @@ impl MachineState { arity: HeapCellValue, ) -> (Atom, usize) { let name = cell_as_atom!(self.store(self.deref(name))); - let arity = cell_as_fixnum!(self.store(self.deref(arity))); + let arity = unsafe { + self.store(self.deref(arity)) + .to_fixnum_or_cut_point_unchecked() + }; (name, usize::try_from(arity.get_num()).unwrap()) } diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 038a16d7..b72b18d2 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -940,7 +940,7 @@ impl MachineState { /* if pstr_atom.len() > offset as usize { self.heap.push(pstr_offset_as_cell!(h)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); + self.heap.push(fixnum_as_cell!(Fixnum::build_with_unchecked(offset as i64))); unify_fn!(*self, pstr_loc_as_cell!(h_len), a3); } else { @@ -973,13 +973,13 @@ impl MachineState { if n == 1 { self.unify_char(c, self.store(self.deref(self.registers[3]))); } else if n == 2 { - let offset = c.len_utf8() as i64; + let offset = c.len_utf8(); let h_len = self.heap.len(); - if cstr_atom.len() > offset as usize { + if cstr_atom.len() > offset{ self.heap.push(atom_as_cstr_cell!(cstr_atom)); self.heap.push(pstr_offset_as_cell!(h_len)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); + self.heap.push(fixnum_as_cell!(Fixnum::build_with_unchecked(offset as i64))); unify_fn!(*self, pstr_loc_as_cell!(h_len+1), self.registers[3]); } else { @@ -1027,7 +1027,11 @@ impl MachineState { if !self.fail { let a3 = self.store(self.deref(self.registers[3])); - self.unify_fixnum(Fixnum::build_with(arity as i64), a3); + self.unify_fixnum( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(arity as i64) }, + a3, + ); } } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 8f70b96f..4c987373 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1161,8 +1161,10 @@ impl Machine { let (idx, arity) = if self.machine_st.effective_block() > prev_block { (r_c_w_h, 0) } else { - self.machine_st.registers[1] = - fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64)); + self.machine_st.registers[1] = fixnum_as_cell!( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(b_cutoff as i64) } + ); (r_c_wo_h, 1) }; diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 6875edfb..3bee79d4 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -578,9 +578,11 @@ impl MachineState { while lh_offset + 4 < self.lifted_heap.cell_len() { let cell_threshold = - cell_as_fixnum!(self.lifted_heap[lh_offset + 3]).get_num() as usize; + unsafe { self.lifted_heap[lh_offset + 3].to_fixnum_or_cut_point_unchecked() } + .get_num() as usize; let pstr_upper_threshold = - cell_as_fixnum!(self.lifted_heap[lh_offset + 4]).get_num() as usize; + unsafe { self.lifted_heap[lh_offset + 4].to_fixnum_or_cut_point_unchecked() } + .get_num() as usize; for idx in lh_offset..cell_threshold { section.push_cell(self.lifted_heap[idx] + offset); @@ -740,7 +742,11 @@ impl MachineState { // self.heap.pop_cell(); let target_n = self.store(self.deref(self.registers[1])); - self.unify_fixnum(Fixnum::build_with(brent_st.num_steps() as i64), target_n); + self.unify_fixnum( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(brent_st.num_steps() as i64) }, + target_n, + ); if !self.fail { unify!(self, self.registers[4], self.heap[prev_hare]); @@ -749,7 +755,10 @@ impl MachineState { fn finalize_skip_max_list(&mut self, n: i64, value: HeapCellValue) { let target_n = self.store(self.deref(self.registers[1])); - self.unify_fixnum(Fixnum::build_with(n), target_n); + self.unify_fixnum( + /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(n) }, + target_n, + ); if !self.fail { let xs = self.registers[4]; @@ -881,7 +890,11 @@ impl MachineState { let value = self.store(self.deref(value)); self.block = self.b; - self.unify_fixnum(Fixnum::build_with(self.block as i64), value); + self.unify_fixnum( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(self.block as i64) }, + value, + ); self.block } @@ -959,7 +972,7 @@ impl MachineState { let mut tokens = vec![]; match lexer.next_number_token() { - Ok(token @ Token::Literal(Literal::Atom(atom!("-")) | Literal::Char('-'))) => { + Ok(token @ Token::Literal(Literal::Atom(atom!("-")))) => { tokens.push(token); if let Ok(token) = lexer.next_number_token() { @@ -1051,7 +1064,10 @@ impl MachineState { for index in s + 2..s + 2 + num_cells { if let HeapCellValueTag::CutPoint = self.heap[index].get_tag() { // adjust cut point to occur after call_continuation. - and_frame[index - (s + 1)] = fixnum_as_cell!(Fixnum::as_cutpoint(self.b as i64)); + and_frame[index - (s + 1)] = fixnum_as_cell!( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(self.b as i64) }.as_cutpoint() + ); } else { and_frame[index - (s + 1)] = self.heap[index]; } @@ -2332,7 +2348,7 @@ impl Machine { (HeapCellValueTag::Char, c) => { let h = self.machine_st.heap.len(); - self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64))); + self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(u32::from(c)))); self.machine_st.heap.push(empty_list_as_cell!()); unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]); @@ -2342,7 +2358,7 @@ impl Machine { debug_assert_eq!(arity, 0); let name = name.as_str(); - let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); + let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c))); let list_cell = resource_error_call_result!( self.machine_st, @@ -2439,7 +2455,10 @@ impl Machine { ); let a2 = self.deref_register(2); - self.machine_st.unify_fixnum(Fixnum::build_with(len), a2); + self.machine_st.unify_fixnum( + /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(len) }, + a2, + ); } #[inline(always)] @@ -2593,7 +2612,7 @@ impl Machine { Ok(Number::Integer(n)) => { let result: Result = (&*n).try_into(); if let Ok(value) = result { - fixnum_as_cell!(Fixnum::build_with(value as i64)) + fixnum_as_cell!(Fixnum::build_with(value)) } else { let err = self.machine_st.type_error(ValidType::InByte, addr); return Err(self.machine_st.error_form(err, stub_gen())); @@ -2601,7 +2620,7 @@ impl Machine { } Ok(Number::Fixnum(n)) => { if let Ok(nb) = u8::try_from(n.get_num()) { - fixnum_as_cell!(Fixnum::build_with(nb as i64)) + fixnum_as_cell!(Fixnum::build_with(nb)) } else { let err = self.machine_st.type_error(ValidType::InByte, addr); return Err(self.machine_st.error_form(err, stub_gen())); @@ -2617,8 +2636,7 @@ impl Machine { loop { match stream.peek_byte().map_err(|e| e.kind()) { Ok(b) => { - self.machine_st - .unify_fixnum(Fixnum::build_with(b as i64), addr); + self.machine_st.unify_fixnum(Fixnum::build_with(b), addr); break; } Err(ErrorKind::PermissionDenied) => { @@ -2783,10 +2801,8 @@ impl Machine { Ok(Number::Integer(n)) => { let n: u32 = (&*n).try_into().unwrap(); - let n = std::char::from_u32(n).map(|_| n); - - if let Some(n) = n { - fixnum_as_cell!(Fixnum::build_with(n as i64)) + if std::char::from_u32(n).is_some() { + fixnum_as_cell!(Fixnum::build_with(n)) } else { let err = self.machine_st.representation_error(RepFlag::InCharacterCode); return Err(self.machine_st.error_form(err, stub_gen())); @@ -2798,7 +2814,7 @@ impl Machine { .and_then(|n| std::char::from_u32(n).map(|_| n)); if let Some(n) = n { - fixnum_as_cell!(Fixnum::build_with(n as i64)) + fixnum_as_cell!(Fixnum::build_with(n)) } else { let err = self.machine_st.representation_error(RepFlag::InCharacterCode); return Err(self.machine_st.error_form(err, stub_gen())); @@ -2818,7 +2834,7 @@ impl Machine { match result.map(|result| result.map_err(|e| e.kind())) { Some(Ok(c)) => { self.machine_st - .unify_fixnum(Fixnum::build_with(c as i64), addr); + .unify_fixnum(Fixnum::build_with(u32::from(c)), addr); break; } Some(Err(ErrorKind::PermissionDenied)) => { @@ -2896,7 +2912,7 @@ impl Machine { let codes = string .trim() .chars() - .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); + .map(|c| fixnum_as_cell!(Fixnum::build_with(u32::from(c)))); let list_cell = step_or_resource_error!( self.machine_st, @@ -2939,7 +2955,9 @@ impl Machine { #[inline(always)] pub(crate) fn lifted_heap_length(&mut self) { let a1 = self.machine_st.registers[1]; - let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.cell_len() as i64); + /* FIXME this is not safe */ + let lh_len = + unsafe { Fixnum::build_with_unchecked(self.machine_st.lifted_heap.cell_len() as i64) }; self.machine_st.unify_fixnum(lh_len, a1); } @@ -3002,7 +3020,7 @@ impl Machine { ); self.machine_st - .unify_fixnum(Fixnum::build_with(c as i64), a2); + .unify_fixnum(Fixnum::build_with(u32::from(c)), a2); Ok(()) } @@ -3132,7 +3150,7 @@ impl Machine { #[inline(always)] pub(crate) fn check_cut_point(&mut self) { let addr = self.deref_register(1); - let old_b = cell_as_fixnum!(addr).get_num() as usize; + let old_b = unsafe { addr.to_fixnum_or_cut_point_unchecked() }.get_num() as usize; let prev_b = self .machine_st @@ -3442,7 +3460,7 @@ impl Machine { let n: Result = (&*n).try_into(); if let Ok(value) = n { - fixnum_as_cell!(Fixnum::build_with(value as i64)) + fixnum_as_cell!(Fixnum::build_with(value)) } else { let err = self.machine_st.type_error(ValidType::InByte, addr); return Err(self.machine_st.error_form(err, stub_gen())); @@ -3450,7 +3468,7 @@ impl Machine { } Ok(Number::Fixnum(n)) => { if let Ok(nb) = u8::try_from(n.get_num()) { - fixnum_as_cell!(Fixnum::build_with(nb as i64)) + fixnum_as_cell!(Fixnum::build_with(nb)) } else { let err = self.machine_st.type_error(ValidType::InByte, addr); return Err(self.machine_st.error_form(err, stub_gen())); @@ -3467,8 +3485,7 @@ impl Machine { match stream.read(&mut b) { Ok(1) => { - self.machine_st - .unify_fixnum(Fixnum::build_with(b[0] as i64), addr); + self.machine_st.unify_fixnum(Fixnum::build_with(b[0]), addr); } _ => { stream.set_past_end_of_stream(true); @@ -3693,7 +3710,7 @@ impl Machine { let n = std::char::from_u32(n); if let Some(n) = n { - fixnum_as_cell!(Fixnum::build_with(n as i64)) + fixnum_as_cell!(Fixnum::build_with(u32::from(n))) } else { let err = self .machine_st @@ -3737,7 +3754,7 @@ impl Machine { match result { Some(Ok(c)) => { self.machine_st - .unify_fixnum(Fixnum::build_with(c as i64), addr); + .unify_fixnum(Fixnum::build_with(u32::from(c)), addr); break; } _ => { @@ -3916,7 +3933,8 @@ impl Machine { #[inline(always)] pub(crate) fn copy_to_lifted_heap(&mut self) { - let lh_offset = cell_as_fixnum!(self.deref_register(1)).get_num() as usize; + let lh_offset = + unsafe { self.deref_register(1).to_fixnum_or_cut_point_unchecked() }.get_num() as usize; let copy_target = self.machine_st.registers[2]; let FindallCopyInfo { offset: old_threshold, @@ -3935,11 +3953,14 @@ impl Machine { self.machine_st.lifted_heap[idx] -= self.machine_st.heap.cell_len() + lh_offset; } - self.machine_st.lifted_heap[old_threshold + 1] = - fixnum_as_cell!(Fixnum::build_with(pstr_threshold as i64)); - self.machine_st.lifted_heap[old_threshold + 2] = fixnum_as_cell!(Fixnum::build_with( - self.machine_st.lifted_heap.cell_len() as i64 - )); + self.machine_st.lifted_heap[old_threshold + 1] = fixnum_as_cell!( + /* FIXME this is not safe */ + unsafe { Fixnum::build_with_unchecked(pstr_threshold as i64) } + ); + self.machine_st.lifted_heap[old_threshold + 2] = + fixnum_as_cell!(/* FIXME this is not safe */ unsafe { + Fixnum::build_with_unchecked(self.machine_st.lifted_heap.cell_len() as i64) + }); let mut pstr_threshold = heap_index!(pstr_threshold); @@ -3958,7 +3979,8 @@ impl Machine { pub(crate) fn lookup_db_ref(&mut self) { let module_name = self.deref_register(1); let name = cell_as_atom!(self.deref_register(2)); - let arity = cell_as_fixnum!(self.deref_register(3)).get_num() as usize; + let arity = + unsafe { self.deref_register(3).to_fixnum_or_cut_point_unchecked() }.get_num() as usize; let module_name = read_heap_cell!(module_name, (HeapCellValueTag::Atom, (module_name, _arity)) => { @@ -4285,7 +4307,12 @@ impl Machine { return; } let value = self.rng.gen_range(lower..upper); - Number::Fixnum(Fixnum::build_with(value)) + // Safety: + // - lower and uper bounds are Fixnum values + // - value is inbetween lower and upper + // - fixnums value range has no gaps + // so value is also a valid Fixnum value + Number::Fixnum(unsafe { Fixnum::build_with_unchecked(value) }) } (Ok(Number::Fixnum(lower)), Ok(Number::Integer(upper))) => { let lower = Integer::from(lower); @@ -4463,7 +4490,7 @@ impl Machine { // status code let status = resp.status().as_u16(); self.machine_st - .unify_fixnum(Fixnum::build_with(status as i64), address_status); + .unify_fixnum(Fixnum::build_with(status), address_status); // headers let mut headers: Vec = vec![]; @@ -5010,9 +5037,12 @@ impl Machine { { Ok(result) => { match result { - Value::Int(n) => self - .machine_st - .unify_fixnum(Fixnum::build_with(n), return_value), + Value::Int(n) => self.machine_st.unify_fixnum( + Fixnum::build_with_checked(n).unwrap_or_else(|_| { + todo!("handle integer values that don't fit in fixnum") + }), + return_value, + ), Value::Float(n) => { let n = float_alloc!(n, self.machine_st.arena); self.machine_st.unify_f64(n, return_value) @@ -5060,7 +5090,16 @@ impl Machine { for val in args { expanded_args.push(match val { - Value::Int(n) => fixnum_as_cell!(Fixnum::build_with(n)), + Value::Int(n) => { + if let Ok(fixnum) = Fixnum::build_with_checked(n) { + fixnum_as_cell!(fixnum) + } else { + integer_as_cell!(Number::Integer(arena_alloc!( + Integer::from(n), + &mut self.machine_st.arena + ))) + } + } Value::Float(n) => HeapCellValue::from(float_alloc!(n, self.machine_st.arena)), Value::CString(cstr) => atom_as_cell!(AtomTable::build_with( &self.machine_st.atom_tbl, @@ -5413,7 +5452,11 @@ impl Machine { #[inline(always)] pub(crate) fn get_attr_var_queue_delimiter(&mut self) { let addr = self.deref_register(1); - let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64); + + /* FIXME this is not safe */ + let value = unsafe { + Fixnum::build_with_unchecked(self.machine_st.attr_var_init.attr_var_queue.len() as i64) + }; self.machine_st.unify_fixnum(value, addr); } @@ -5682,7 +5725,7 @@ impl Machine { #[inline(always)] pub(crate) fn get_continuation_chunk(&mut self) { let e = self.deref_register(1); - let e = cell_as_fixnum!(e).get_num() as usize; + let e = unsafe { e.to_fixnum_or_cut_point_unchecked() }.get_num() as usize; let h = self.machine_st.heap.cell_len(); let p_functor_cell = self.deref_register(2); @@ -5736,8 +5779,12 @@ impl Machine { #[inline(always)] pub(crate) fn get_lifted_heap_from_offset_diff(&mut self) { let lh_offset = self.machine_st.registers[1]; - let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))) - .get_num() as usize; + let lh_offset = unsafe { + self.machine_st + .store(self.machine_st.deref(lh_offset)) + .to_fixnum_or_cut_point_unchecked() + } + .get_num() as usize; if lh_offset >= self.machine_st.lifted_heap.cell_len() { let solutions = self.machine_st.registers[2]; @@ -5765,8 +5812,12 @@ impl Machine { #[inline(always)] pub(crate) fn get_lifted_heap_from_offset(&mut self) { let lh_offset = self.machine_st.registers[1]; - let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))) - .get_num() as usize; + let lh_offset = unsafe { + self.machine_st + .store(self.machine_st.deref(lh_offset)) + .to_fixnum_or_cut_point_unchecked() + } + .get_num() as usize; if lh_offset >= self.machine_st.lifted_heap.cell_len() { let solutions = self.machine_st.registers[2]; @@ -5888,7 +5939,7 @@ impl Machine { } }; - let bp = cell_as_fixnum!(a1).get_num() as usize; + let bp = unsafe { a1.to_fixnum_or_cut_point_unchecked() }.get_num() as usize; let a3 = self.deref_register(3); let count = self.machine_st.cwil.add_limit(n, bp).clone(); @@ -5899,9 +5950,11 @@ impl Machine { #[inline(always)] pub(crate) fn inference_count(&mut self, count_var: HeapCellValue, count: Integer) { - if let Ok(value) = <&Integer as TryInto>::try_into(&count) { - self.machine_st - .unify_fixnum(Fixnum::build_with(value), count_var); + if let Some(value) = <&Integer as TryInto>::try_into(&count) + .ok() + .and_then(|i| Fixnum::build_with_checked(i).ok()) + { + self.machine_st.unify_fixnum(value, count_var); } else { let count = arena_alloc!(count, &mut self.machine_st.arena); self.machine_st.unify_big_int(count, count_var); @@ -6028,7 +6081,8 @@ impl Machine { #[inline(always)] pub(crate) fn remove_call_policy_check(&mut self) { - let bp = cell_as_fixnum!(self.deref_register(1)).get_num() as usize; + let bp = + unsafe { self.deref_register(1).to_fixnum_or_cut_point_unchecked() }.get_num() as usize; if bp == self.machine_st.b && self.machine_st.cwil.is_empty() { self.machine_st.cwil.reset(); @@ -6040,12 +6094,10 @@ impl Machine { let a1 = self.deref_register(1); let a2 = self.deref_register(2); - let block = cell_as_fixnum!(a1).get_num() as usize; + let block = unsafe { a1.to_fixnum_or_cut_point_unchecked() }.get_num() as usize; let count = self.machine_st.cwil.remove_limit(block).clone(); - let result = count.clone().try_into(); - - if let Ok(value) = result { - self.machine_st.unify_fixnum(Fixnum::build_with(value), a2); + if let Ok(value) = Fixnum::build_with_checked(&count) { + self.machine_st.unify_fixnum(value, a2); } else { let count = arena_alloc!(count.clone(), &mut self.machine_st.arena); self.machine_st.unify_big_int(count, a2); @@ -6063,18 +6115,23 @@ impl Machine { self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)]; } - self.machine_st.b0 = cell_as_fixnum!( + self.machine_st.b0 = unsafe { self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 2)] - ) + .to_fixnum_or_cut_point_unchecked() + } .get_num() as usize; - self.machine_st.num_of_args = cell_as_fixnum!( + self.machine_st.num_of_args = unsafe { self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)] - ) + .to_fixnum_or_cut_point_unchecked() + } .get_num() as usize; - let p = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]).get_num() - as usize; + let p = unsafe { + self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)] + .to_fixnum_or_cut_point_unchecked() + } + .get_num() as usize; self.machine_st.deallocate(); self.machine_st.p = p; @@ -6191,7 +6248,7 @@ impl Machine { let a1 = self.deref_register(1); let a2 = self.deref_register(2); - let bp = cell_as_fixnum!(a2).get_num() as usize; + let bp = unsafe { a2.to_fixnum_or_cut_point_unchecked() }.get_num() as usize; let prev_b = self .machine_st .stack @@ -6214,7 +6271,7 @@ impl Machine { #[inline(always)] pub(crate) fn clean_up_block(&mut self) { let nb = self.deref_register(1); - let nb = cell_as_fixnum!(nb).get_num() as usize; + let nb = unsafe { nb.to_fixnum_or_cut_point_unchecked() }.get_num() as usize; let b = self.machine_st.b; @@ -6270,7 +6327,9 @@ impl Machine { #[inline(always)] pub(crate) fn get_current_block(&mut self) { let addr = self.machine_st.registers[1]; - let block = Fixnum::build_with(self.machine_st.block as i64); + + /* FIXME this is not safe */ + let block = unsafe { Fixnum::build_with_unchecked(self.machine_st.block as i64) }; self.machine_st.unify_fixnum(block, addr); } @@ -6278,21 +6337,27 @@ impl Machine { #[inline(always)] pub(crate) fn get_current_scc_block(&mut self) { let addr = self.machine_st.registers[1]; - let block = Fixnum::build_with(self.machine_st.scc_block as i64); + + /* FIXME this is not safe */ + let block = unsafe { Fixnum::build_with_unchecked(self.machine_st.scc_block as i64) }; self.machine_st.unify_fixnum(block, addr); } #[inline(always)] pub(crate) fn get_b_value(&mut self) { - let n = Fixnum::as_cutpoint(i64::try_from(self.machine_st.b).unwrap()); + /* FIXME this is not safe */ + let n = unsafe { Fixnum::build_with_unchecked(i64::try_from(self.machine_st.b).unwrap()) } + .as_cutpoint(); self.machine_st .unify_fixnum(n, self.machine_st.registers[1]); } #[inline(always)] pub(crate) fn get_cut_point(&mut self) { - let n = Fixnum::as_cutpoint(i64::try_from(self.machine_st.b0).unwrap()); + /* FIXME this is not safe */ + let n = unsafe { Fixnum::build_with_unchecked(i64::try_from(self.machine_st.b0).unwrap()) } + .as_cutpoint(); self.machine_st .unify_fixnum(n, self.machine_st.registers[1]); } @@ -6314,7 +6379,7 @@ impl Machine { let cp = and_frame.prelude.cp - 1; let e = and_frame.prelude.e; - let e = Fixnum::build_with(i64::try_from(e).unwrap()); + let e = Fixnum::build_with_checked(e).unwrap(); machine_st.unify_fixnum(e, machine_st.registers[2]); @@ -6363,7 +6428,7 @@ impl Machine { writer(&mut self.machine_st.heap) ); - let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap()); + let e = Fixnum::build_with_checked(and_frame.prelude.e).unwrap(); self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); if !self.machine_st.fail { @@ -6787,10 +6852,7 @@ impl Machine { let port = tcp_listener.local_addr().map(|addr| addr.port()).ok(); if let Some(port) = port { - ( - arena_alloc!(tcp_listener, &mut self.machine_st.arena), - port as usize, - ) + (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port) } else { self.machine_st.fail = true; return Ok(()); @@ -6817,7 +6879,7 @@ impl Machine { if had_zero_port { self.machine_st - .unify_fixnum(Fixnum::build_with(port as i64), self.deref_register(2)); + .unify_fixnum(Fixnum::build_with(port), self.deref_register(2)); } Ok(()) @@ -7266,7 +7328,8 @@ impl Machine { #[inline(always)] pub(crate) fn term_variables_under_max_depth(&mut self) { // Term, MaxDepth, VarList - let max_depth = cell_as_fixnum!(self.deref_register(2)).get_num() as usize; + let max_depth = + unsafe { self.deref_register(2).to_fixnum_or_cut_point_unchecked() }.get_num() as usize; self.machine_st.term_variables_under_max_depth( self.machine_st.registers[1], @@ -7278,7 +7341,7 @@ impl Machine { #[inline(always)] pub(crate) fn truncate_lifted_heap_to(&mut self) { let a1 = self.deref_register(1); - let lh_offset = cell_as_fixnum!(a1).get_num() as usize; + let lh_offset = unsafe { a1.to_fixnum_or_cut_point_unchecked() }.get_num() as usize; self.machine_st.lifted_heap.truncate(lh_offset); } @@ -7561,7 +7624,7 @@ impl Machine { } } - let byte = Fixnum::build_with(bytes[0] as i64); + let byte = Fixnum::build_with(bytes[0]); self.machine_st.unify_fixnum(byte, arg); } @@ -7587,7 +7650,7 @@ impl Machine { context_len, finalized_context .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ) } @@ -7604,7 +7667,7 @@ impl Machine { context_len, finalized_context .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ) } @@ -7621,7 +7684,7 @@ impl Machine { context_len, finalized_context .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ) } @@ -7638,7 +7701,7 @@ impl Machine { context_len, finalized_context .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))), ) ) } @@ -7655,7 +7718,7 @@ impl Machine { context_len, finalized_context .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))), ) ) } @@ -7672,7 +7735,7 @@ impl Machine { context_len, finalized_context .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))), ) ) } @@ -7689,7 +7752,7 @@ impl Machine { context_len, finalized_context .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ) } @@ -7714,7 +7777,7 @@ impl Machine { ints.as_ref().len(), ints.as_ref() .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ) } @@ -7754,7 +7817,7 @@ impl Machine { tag.as_ref().len(), tag.as_ref() .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ); @@ -7825,7 +7888,7 @@ impl Machine { bytes.len(), bytes .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ) }; @@ -7881,7 +7944,7 @@ impl Machine { bytes.len(), bytes .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ) }; @@ -7928,7 +7991,7 @@ impl Machine { tag.as_ref().len(), tag.as_ref() .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ); @@ -8068,7 +8131,7 @@ impl Machine { sig.as_ref().len(), sig.as_ref() .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b))) ) ); @@ -8482,7 +8545,7 @@ impl Machine { let number = self.deref_register(1); let pop_count = integer_as_cell!(match Number::try_from(number) { Ok(Number::Fixnum(n)) => { - Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64)) + Number::Fixnum(Fixnum::build_with(n.get_num().count_ones())) } Ok(Number::Integer(n)) => { let value: usize = if n.sign() == Sign::Positive { diff --git a/src/macros.rs b/src/macros.rs index 5347af3c..29e3369f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -14,12 +14,6 @@ macro_rules! fixnum_as_cell { }; } -macro_rules! cell_as_fixnum { - ($cell:expr) => { - Fixnum::from_bytes($cell.into_bytes()) - }; -} - macro_rules! integer_as_cell { ($n: expr) => {{ match $n { diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 9f1d7382..d67d97ce 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -11,7 +11,10 @@ use std::cell::{Cell, Ref, RefCell, RefMut}; use std::fmt; use std::hash::Hash; use std::hash::Hasher; +use std::i64; use std::io::{Error as IOError, ErrorKind}; +use std::ops::Not; +use std::ops::RangeInclusive; use std::ops::{Deref, Neg}; use std::rc::Rc; use std::sync::Arc; @@ -550,9 +553,90 @@ pub struct Fixnum { tag: B6, } +mod private { + use dashu::Integer; + + pub(crate) trait FitsInFixnumSeal {} + pub(crate) trait MightNotFitInFixnumSeal {} + + macro_rules! impl_fits_in_fixnum { + ($t:ty) => { + impl $crate::parser::ast::private::FitsInFixnumSeal for $t {} + + impl $crate::parser::ast::FitsInFixnum for $t { + fn into_i56(self) -> i64 { + self.into() + } + } + }; + } + + impl_fits_in_fixnum!(u8); + impl_fits_in_fixnum!(i8); + impl_fits_in_fixnum!(u16); + impl_fits_in_fixnum!(i16); + impl_fits_in_fixnum!(u32); + impl_fits_in_fixnum!(i32); + + impl FitsInFixnumSeal for char {} + impl super::FitsInFixnum for char { + fn into_i56(self) -> i64 { + u32::from(self) as i64 + } + } + + impl MightNotFitInFixnumSeal for i64 {} + impl MightNotFitInFixnumSeal for &Integer {} + impl MightNotFitInFixnumSeal for Integer {} + impl MightNotFitInFixnumSeal for usize {} +} + +#[allow(private_bounds)] +pub trait FitsInFixnum: private::FitsInFixnumSeal { + fn into_i56(self) -> i64; +} + +#[allow(private_bounds)] +pub trait MightNotFitInFixnum: private::MightNotFitInFixnumSeal { + fn try_into_i56(self) -> Option; +} + +impl MightNotFitInFixnum for T +where + T: private::MightNotFitInFixnumSeal + TryInto, +{ + fn try_into_i56(self) -> Option { + let val = self.try_into().ok()?; + if Fixnum::RANGE.contains(&val) { + Some(val) + } else { + None + } + } +} + impl Fixnum { + pub(crate) const MIN: i64 = -(1 << 55); + pub(crate) const MAX: i64 = (1 << 55) - 1; + const RANGE: RangeInclusive = Self::MIN..=Self::MAX; + + // if you have a type that is not guaranteed to fit use `Fixnum::build_with_checked` or `Fixnum::build_with_unchecked` instead #[inline] - pub fn build_with(num: i64) -> Self { + pub fn build_with(num: impl FitsInFixnum) -> Self { + // Safety: FitsInFixnum is only implemented by types that only have valid values + // and FitsInFixnumSeal ensures no one outside this crate can violate that + unsafe { Self::build_with_unchecked(num.into_i56()) } + } + + #[inline] + pub unsafe fn build_with_unchecked(num: i64) -> Self { + debug_assert!( + Self::RANGE.contains(&num), + "{num} should be in the range {}..={}", + Self::MIN, + Self::MAX + ); + Fixnum::new() .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)) .with_tag(HeapCellValueTag::Fixnum as u8) @@ -561,12 +645,8 @@ impl Fixnum { } #[inline] - pub fn as_cutpoint(num: i64) -> Self { - Fixnum::new() - .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)) - .with_tag(HeapCellValueTag::CutPoint as u8) - .with_m(false) - .with_f(false) + pub fn as_cutpoint(self) -> Self { + self.with_tag(HeapCellValueTag::CutPoint as u8) } #[inline] @@ -575,20 +655,14 @@ impl Fixnum { HeapCellValueTag::from_bytes(self.tag()).unwrap() } + // if you have a type that is guaranteed to fit use `Fixnum::build_with` instead #[inline] - pub fn build_with_checked(num: i64) -> Result { - const UPPER_BOUND: i64 = (1 << 55) - 1; - const LOWER_BOUND: i64 = -(1 << 55); - - if (LOWER_BOUND..=UPPER_BOUND).contains(&num) { - Ok(Fixnum::new() - .with_m(false) - .with_f(false) - .with_tag(HeapCellValueTag::Fixnum as u8) - .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))) - } else { - Err(OutOfBounds {}) - } + pub fn build_with_checked(num: impl MightNotFitInFixnum) -> Result { + Ok(unsafe { + // Safety: all MightNotFitInFixnum impls return None when the value is out-of-bounds + // and MightNotFitInFixnumSeal ensures no one outside this crate can violate that + Self::build_with_unchecked(num.try_into_i56().ok_or(OutOfBounds {})?) + }) } #[inline] @@ -598,6 +672,10 @@ impl Fixnum { debug_assert!(!overflowed); n } + + pub fn checked_abs(self) -> Option { + Self::build_with_checked(self.get_num().abs()).ok() + } } impl Neg for Fixnum { @@ -605,7 +683,18 @@ impl Neg for Fixnum { #[inline] fn neg(self) -> Self::Output { - Fixnum::build_with(-self.get_num()) + // Safety: the truncating behaviour is correct + unsafe { Self::build_with_unchecked(-self.get_num()) } + } +} + +impl Not for Fixnum { + type Output = Self; + + #[inline] + fn not(self) -> Self::Output { + // Safety: the truncating behaviour is correct + unsafe { Self::build_with_unchecked(!self.get_num()) } } } diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 95162196..a1b8cb4a 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -1,9 +1,7 @@ -use crate::arena::F64Ptr; -use crate::arena::TypedArenaPtr; - use crate::arena::*; use crate::atom_table::*; pub use crate::machine::machine_state::*; +use crate::offset_table::F64Ptr; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::dashu::Integer; @@ -662,15 +660,15 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } - fn vacate_with_float(&mut self, mut token: String) -> Result { + fn vacate_with_float(&mut self, mut token: String) -> Result { self.return_char(token.pop().unwrap()); let n = parse_float_lossy(&token)?; - Ok(Token::Literal(Literal::from(float_alloc!( + Ok(Number::Float(float_alloc!( n, self.machine_st.arena - )))) + ))) } fn skip_underscore_in_number(&mut self) -> Result { @@ -797,7 +795,8 @@ impl<'a, R: CharRead> Lexer<'a, R> { } let n = parse_float_lossy(&token)?; - Ok(Token::Literal(Literal::from(float_alloc!( + + Ok(NumberToken::Number(Number::Float(float_alloc!( n, self.machine_st.arena )))) @@ -806,7 +805,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } else { let n = parse_float_lossy(&token)?; - Ok(Token::Literal(Literal::from(float_alloc!( + Ok(NumberToken::Number(Number::Float(float_alloc!( n, self.machine_st.arena )))) @@ -859,7 +858,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { } self.get_single_quoted_char() - .map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c as i64)))) + .map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c)))) .or_else(|err| { match err { ParserError::UnexpectedChar('\'', ..) => {} diff --git a/src/parser/parser.rs b/src/parser/parser.rs index b39fc557..10702109 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -389,7 +389,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Cell::default(), Box::new(Term::Literal( Cell::default(), - Literal::Fixnum(Fixnum::build_with(c as i64)), + Literal::Fixnum(Fixnum::build_with(c)), )), Box::new(list), ); @@ -963,12 +963,12 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::Literal(Literal::Rational(n)) => { self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r)) } - Token::Literal(Literal::Float(n)) if n.as_ptr().is_infinite() => { + Token::Literal(Literal::Float(n)) if n.as_ptr().is_infinite() => { return Err(ParserError::InfiniteFloat( self.lexer.line_num, self.lexer.col_num, )); - } + } Token::Literal(Literal::Float(n)) => self.negate_number( **n.as_ptr(), |n, _| -n, diff --git a/src/types.rs b/src/types.rs index e6dda7d9..b4765930 100644 --- a/src/types.rs +++ b/src/types.rs @@ -588,6 +588,16 @@ impl HeapCellValue { } } + // FIXME: someone that knows this better should check if this can be split into `to_fixnum_unchecked` and `to_cut_point_unchecked` assuming thats always unambigusly knowable + #[inline] + pub unsafe fn to_fixnum_or_cut_point_unchecked(self) -> Fixnum { + debug_assert!(matches!( + self.get_tag(), + HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint + )); + Fixnum::from_bytes(self.into_bytes()) + } + #[inline] pub fn from_ptr_addr(ptr_bytes: usize) -> Self { HeapCellValue::from_bytes((ptr_bytes as u64).to_ne_bytes()) From 725def07cdc5f597cdc9901550683bc4e1094a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Fri, 9 May 2025 23:45:03 +0200 Subject: [PATCH 054/122] fix crash when loading html --- src/lib/sgml.pl | 12 +++--- src/machine/system_calls.rs | 85 +++++++++++++++++++++++++++++++------ tests-pl/issue2949.pl | 11 +++++ tests/scryer/issues.rs | 6 +++ 4 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 tests-pl/issue2949.pl diff --git a/src/lib/sgml.pl b/src/lib/sgml.pl index bccba1f3..b7933c9f 100644 --- a/src/lib/sgml.pl +++ b/src/lib/sgml.pl @@ -96,14 +96,14 @@ is_sgml_source([]). is_sgml_source([C|Cs]) :- must_be(chars, [C|Cs]). load_structure_([], [], _, _). -load_structure_([C|Cs], [E], Options, What) :- - load_(What, [C|Cs], E, Options). -load_structure_(file(Fs), [E], Options, What) :- +load_structure_([C|Cs], [E|Es], Options, What) :- + load_(What, [C|Cs], [E|Es], Options). +load_structure_(file(Fs), [E|Es], Options, What) :- once(phrase_from_file(seq(Cs), Fs)), - load_(What, Cs, E, Options). -load_structure_(stream(Stream), [E], Options, What) :- + load_(What, Cs, [E|Es], Options). +load_structure_(stream(Stream), [E|Es], Options, What) :- get_n_chars(Stream, _, Cs), - load_(What, Cs, E, Options). + load_(What, Cs, [E|Es], Options). load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options). load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 3bee79d4..dc07cb78 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8202,9 +8202,21 @@ impl Machine { .value_to_str_like(self.machine_st.registers[1]) { let document = scraper::Html::parse_document(&string.as_str()); - let result = self.html_node_to_term(document.tree.root().first_child().unwrap())?; - unify!(self.machine_st, self.machine_st.registers[2], result); + let root_nodes = document + .tree + .root() + .children() + .map(|child| self.html_node_to_term(child)) + .collect::, _>>()?; + + let nodes = sized_iter_to_heap_list( + &mut self.machine_st.heap, + root_nodes.len(), + root_nodes.into_iter(), + )?; + + unify!(self.machine_st, self.machine_st.registers[2], nodes); } else { self.machine_st.fail = true; } @@ -8651,12 +8663,39 @@ impl Machine { &mut self, node: ego_tree::NodeRef<'_, scraper::Node>, ) -> Result { - match node.value().as_element() { - None => self - .machine_st - .heap - .allocate_cstr(&node.value().as_text().unwrap().text), - Some(element) => { + match node.value() { + scraper::Node::Document | scraper::Node::Fragment => { + unreachable!("we never iterate the root itself only its children") + } + scraper::Node::Doctype(doctype) => { + // what about public and system id? + let name = self.machine_st.heap.allocate_cstr(&doctype.name)?; + + let result = str_loc_as_cell!(self.machine_st.heap.cell_len()); + let mut writer = self.machine_st.heap.reserve(2)?; + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("doctype"), 1)); + section.push_cell(name); + }); + + Ok(result) + } + scraper::Node::Comment(comment) => { + let comment = self.machine_st.heap.allocate_cstr(&comment)?; + + let result = str_loc_as_cell!(self.machine_st.heap.cell_len()); + let mut writer = self.machine_st.heap.reserve(2)?; + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("comment"), 1)); + section.push_cell(comment); + }); + + Ok(result) + } + scraper::Node::Text(text) => self.machine_st.heap.allocate_cstr(&text.text), + scraper::Node::Element(element) => { let mut avec = Vec::new(); for attr in element.attrs() { @@ -8680,11 +8719,10 @@ impl Machine { avec.into_iter(), )?; - let mut cvec = Vec::new(); - - for child in node.children() { - cvec.push(self.html_node_to_term(child)?); - } + let cvec = node + .children() + .map(|child| self.html_node_to_term(child)) + .collect::, _>>()?; let children = sized_iter_to_heap_list( &mut self.machine_st.heap, @@ -8703,6 +8741,27 @@ impl Machine { section.push_cell(children); }); + Ok(result) + } + scraper::Node::ProcessingInstruction(processing_instruction) => { + let target = self + .machine_st + .heap + .allocate_cstr(&processing_instruction.target)?; + let data = self + .machine_st + .heap + .allocate_cstr(&processing_instruction.data)?; + + let result = str_loc_as_cell!(self.machine_st.heap.cell_len()); + let mut writer = self.machine_st.heap.reserve(3)?; + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("processing_instruction"), 2)); + section.push_cell(target); + section.push_cell(data); + }); + Ok(result) } } diff --git a/tests-pl/issue2949.pl b/tests-pl/issue2949.pl new file mode 100644 index 00000000..901bf031 --- /dev/null +++ b/tests-pl/issue2949.pl @@ -0,0 +1,11 @@ +:- use_module(library(sgml)). + +test :- + load_html("Hello!", Es, []), + write(Es), + load_html("Hello!", Es2, []), + write(Es2), + load_html(" Date: Thu, 22 May 2025 23:49:57 -0700 Subject: [PATCH 055/122] use OffsetTableImpl without synchronization by default --- build/instructions_template.rs | 2 +- src/arena.rs | 26 +- src/arithmetic.rs | 30 +- src/codegen.rs | 25 +- src/forms.rs | 3 +- src/heap_print.rs | 105 ++++-- src/machine/arithmetic_ops.rs | 5 +- src/machine/compile.rs | 96 +++--- src/machine/disjuncts.rs | 2 +- src/machine/dispatch.rs | 80 +++-- src/machine/heap.rs | 30 +- src/machine/lib_machine/mod.rs | 44 +-- src/machine/load_state.rs | 163 +++++---- src/machine/loader.rs | 50 ++- src/machine/machine_indices.rs | 68 ++-- src/machine/machine_state.rs | 3 +- src/machine/machine_state_impl.rs | 199 ++--------- src/machine/mock_wam.rs | 1 + src/machine/mod.rs | 89 +++-- src/machine/preprocessor.rs | 16 +- src/machine/system_calls.rs | 182 +++++----- src/machine/unify.rs | 28 +- src/macros.rs | 41 +-- src/offset_table.rs | 541 ++++++++++++++++-------------- src/parser/ast.rs | 17 +- src/parser/lexer.rs | 12 +- src/parser/parser.rs | 19 +- src/types.rs | 118 +++---- 28 files changed, 1005 insertions(+), 990 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index baa59626..dc2ed9f7 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -2698,7 +2698,7 @@ pub fn generate_instructions_rs() -> TokenStream { if ident == "Named" { clause_type_from_name_and_arity_arms.push(quote! { - (name, arity) => ClauseType::Named(arity, name, CodeIndex::default(arena)) + (name, arity) => ClauseType::Named(arity, name, CodeIndex::default(&mut arena.code_index_tbl)) }); clause_type_to_instr_arms.push(quote! { diff --git a/src/arena.rs b/src/arena.rs index a6ccb921..2be3a9f9 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -21,7 +21,6 @@ use std::ops::{Deref, DerefMut}; use std::ptr; use std::ptr::addr_of_mut; use std::ptr::NonNull; -use std::sync::Arc; macro_rules! arena_alloc { ($e:expr, $arena:expr) => {{ @@ -32,8 +31,7 @@ macro_rules! arena_alloc { macro_rules! float_alloc { ($e:expr, $arena:expr) => {{ - let result = $e; - unsafe { $arena.f64_tbl.build_with(OrderedFloat(result)).as_ptr() } + $arena.f64_tbl.build_with(OrderedFloat($e)) }}; } @@ -458,8 +456,8 @@ impl Drop for UntypedArenaSlab { #[derive(Debug)] pub struct Arena { base: Option, - pub f64_tbl: Arc, - pub code_index_tbl: Arc, + pub f64_tbl: F64Table, + pub code_index_tbl: CodeIndexTable, } unsafe impl Send for Arena {} @@ -584,23 +582,27 @@ mod tests { #[test] fn float_ptr_cast() { - let wam = MockWAM::new(); + let mut wam = MockWAM::new(); let f = 0f64; let fp = float_alloc!(f, wam.machine_st.arena); - let mut cell = HeapCellValue::from(fp.clone()); + let mut cell = HeapCellValue::from(fp); - assert_eq!(cell.get_tag(), HeapCellValueTag::F64); + assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset); assert!(!cell.get_mark_bit()); - assert_eq!(fp.deref(), &OrderedFloat(f)); + assert_eq!( + wam.machine_st.arena.f64_tbl.lookup(fp).deref(), + &OrderedFloat(f) + ); cell.set_mark_bit(true); assert!(cell.get_mark_bit()); read_heap_cell!(cell, - (HeapCellValueTag::F64, ptr) => { - assert_eq!(OrderedFloat(*ptr), OrderedFloat(f)) + (HeapCellValueTag::F64Offset, offset) => { + let fp = wam.machine_st.arena.f64_tbl.lookup(offset.into()); + assert_eq!(*fp, OrderedFloat(0f64)) } _ => { unreachable!() } ); @@ -825,7 +827,7 @@ mod tests { let float_ptr = float_alloc!(float, wam.machine_st.arena); let cell = HeapCellValue::from(float_ptr); - assert_eq!(cell.get_tag(), HeapCellValueTag::F64); + assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset); // char diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 2f0df28d..a4aad3f8 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -138,6 +138,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { #[derive(Debug)] pub(crate) struct ArithmeticEvaluator<'a> { marker: &'a mut DebrayAllocator, + f64_tbl: &'a F64Table, interm: Vec, interm_c: usize, } @@ -156,11 +157,18 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term { } } -fn push_literal(interm: &mut Vec, c: &Literal) -> Result<(), ArithmeticError> { +fn push_literal( + f64_tbl: &F64Table, + 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::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))), + &Literal::F64Offset(offset) => { + let n = *f64_tbl.lookup(offset); + interm.push(ArithmeticTerm::Number(Number::Float(n))); + } 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)), @@ -178,9 +186,14 @@ fn push_literal(interm: &mut Vec, c: &Literal) -> Result<(), Ari } impl<'a> ArithmeticEvaluator<'a> { - pub(crate) fn new(marker: &'a mut DebrayAllocator, target_int: usize) -> Self { + pub(crate) fn new( + marker: &'a mut DebrayAllocator, + f64_tbl: &'a F64Table, + target_int: usize, + ) -> Self { ArithmeticEvaluator { marker, + f64_tbl, interm: Vec::new(), interm_c: target_int, } @@ -318,7 +331,7 @@ impl<'a> ArithmeticEvaluator<'a> { for term_ref in src.iter()? { match term_ref? { - ArithTermRef::Literal(c) => push_literal(&mut self.interm, &c)?, + ArithTermRef::Literal(c) => push_literal(self.f64_tbl, &mut self.interm, &c)?, ArithTermRef::Var(lvl, cell, name) => { let var_num = name.to_var_num().unwrap(); @@ -652,11 +665,11 @@ impl Ord for Number { } } -impl TryFrom for Number { +impl TryFrom<(HeapCellValue, &'_ F64Table)> for Number { type Error = (); #[inline] - fn try_from(value: HeapCellValue) -> Result { + fn try_from((value, f64_tbl): (HeapCellValue, &F64Table)) -> Result { read_heap_cell!(value, (HeapCellValueTag::Cons, c) => { match_untyped_arena_ptr!(c, @@ -671,8 +684,9 @@ impl TryFrom for Number { } ) } - (HeapCellValueTag::F64, n) => { - Ok(Number::Float(*n)) + (HeapCellValueTag::F64Offset, offset) => { + let n = *f64_tbl.lookup(offset.into()); + Ok(Number::Float(n)) } (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => { Ok(Number::Fixnum(n)) diff --git a/src/codegen.rs b/src/codegen.rs index 41458653..afde0ab7 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -6,6 +6,7 @@ use crate::forms::*; use crate::indexing::*; use crate::instructions::*; use crate::iterators::*; +use crate::offset_table::F64Table; use crate::parser::ast::*; use crate::targets::*; use crate::types::*; @@ -269,9 +270,10 @@ impl CodeGenSettings { } #[derive(Debug)] -pub(crate) struct CodeGenerator { +pub(crate) struct CodeGenerator<'f64_tbl> { marker: DebrayAllocator, settings: CodeGenSettings, + f64_tbl: &'f64_tbl F64Table, pub(crate) skeleton: PredicateSkeleton, } @@ -323,7 +325,7 @@ trait AddToFreeList<'a, Target: CompilationTarget<'a>> { fn add_subterm_to_free_list(&mut self, term: &Term); } -impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator { +impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator<'_> { fn add_term_to_free_list(&mut self, r: RegType) { self.marker.add_reg_to_free_list(r); } @@ -331,7 +333,7 @@ impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator { fn add_subterm_to_free_list(&mut self, _term: &Term) {} } -impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator { +impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'_> { #[inline(always)] fn add_term_to_free_list(&mut self, _r: RegType) {} @@ -353,11 +355,12 @@ fn structure_cell(term: &Term) -> Option<&Cell> { } } -impl CodeGenerator { - pub(crate) fn new(settings: CodeGenSettings) -> Self { +impl<'f64_tbl> CodeGenerator<'f64_tbl> { + pub(crate) fn new(f64_tbl: &'f64_tbl F64Table, settings: CodeGenSettings) -> Self { CodeGenerator { marker: DebrayAllocator::new(), settings, + f64_tbl, skeleton: PredicateSkeleton::new(), } } @@ -427,7 +430,7 @@ impl CodeGenerator { where Target: crate::targets::CompilationTarget<'a>, Iter: Iterator>, - CodeGenerator: AddToFreeList<'a, Target>, + CodeGenerator<'f64_tbl>: AddToFreeList<'a, Target>, { let mut target = CodeDeque::new(); @@ -443,7 +446,7 @@ impl CodeGenerator { } TermRef::Clause(lvl, cell, name, terms) => { let terms_range = - if let Some(subterm @ Term::Literal(_, Literal::CodeIndex(_))) = + if let Some(subterm @ Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() { self.subterm_to_instr::(subterm, context, &mut target); @@ -666,7 +669,7 @@ impl CodeGenerator { } }, InlinedClauseType::IsFloat(..) => match terms[0] { - Term::Literal(_, Literal::Float(_)) => { + Term::Literal(_, Literal::F64Offset(_)) => { instr!("$succeed") } Term::Var(ref vr, ref name) => { @@ -687,7 +690,7 @@ impl CodeGenerator { } }, InlinedClauseType::IsNumber(..) => match terms[0] { - Term::Literal(_, Literal::Float(_)) + Term::Literal(_, Literal::F64Offset(_)) | Term::Literal(_, Literal::Rational(_)) | Term::Literal(_, Literal::Integer(_)) | Term::Literal(_, Literal::Fixnum(_)) => { @@ -791,7 +794,7 @@ impl CodeGenerator { term_loc: GenContext, arg: usize, ) -> Result { - let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int); + let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, self.f64_tbl, target_int); evaluator.compile_is(term, term_loc, arg) } @@ -861,7 +864,7 @@ impl CodeGenerator { Term::Literal( _, c @ Literal::Integer(_) - | c @ Literal::Float(_) + | c @ Literal::F64Offset(_) | c @ Literal::Rational(_) | c @ Literal::Fixnum(_), ) => { diff --git a/src/forms.rs b/src/forms.rs index 0779d5b8..1418b570 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -6,6 +6,7 @@ use crate::machine::disjuncts::VarData; use crate::machine::loader::PredicateQueue; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; +use crate::offset_table::OffsetTable; use crate::parser::ast::*; use crate::parser::dashu::{Integer, Rational}; use crate::parser::parser::CompositeOpDesc; @@ -742,7 +743,7 @@ impl ArenaFrom for HeapCellValue { match value { Number::Fixnum(n) => fixnum_as_cell!(n), Number::Integer(n) => typed_arena_ptr_as_cell!(n), - Number::Float(OrderedFloat(n)) => HeapCellValue::from(float_alloc!(n, arena)), + Number::Float(n) => HeapCellValue::from(arena.f64_tbl.build_with(n)), Number::Rational(n) => typed_arena_ptr_as_cell!(n), } } diff --git a/src/heap_print.rs b/src/heap_print.rs index c23344bf..d45e45a9 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -8,7 +8,6 @@ use crate::parser::dashu::{ibig, Integer, Rational}; use crate::forms::*; use crate::heap_iter::*; use crate::machine::heap::*; -use crate::machine::machine_indices::*; use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::streams::*; @@ -389,17 +388,20 @@ fn is_numbered_var(name: Atom, arity: usize) -> bool { #[inline] fn negated_op_needs_bracketing( iter: &StackfulPreOrderHeapIter, + f64_tbl: &F64Table, op_dir: &OpDir, op: &Option, ) -> bool { if let Some(ref op) = op { op.is_negative_sign() - && iter.leftmost_leaf_has_property(op_dir, |addr| match Number::try_from(addr) { - Ok(Number::Fixnum(n)) => n.get_num() > 0, - Ok(Number::Float(OrderedFloat(f))) => f > 0f64, - Ok(Number::Integer(n)) => n.is_positive(), - Ok(Number::Rational(n)) => n.is_positive(), - _ => false, + && iter.leftmost_leaf_has_property(op_dir, |addr| { + match Number::try_from((addr, f64_tbl)) { + Ok(Number::Fixnum(n)) => n.get_num() > 0, + Ok(Number::Float(OrderedFloat(f))) => f > 0f64, + Ok(Number::Integer(n)) => n.is_positive(), + Ok(Number::Rational(n)) => n.is_positive(), + _ => false, + } }) } else { false @@ -473,6 +475,7 @@ pub fn fmt_float(mut fl: f64) -> String { pub struct HCPrinter<'a, Outputter> { outputter: Outputter, iter: StackfulPreOrderHeapIter<'a, ListElider>, + arena: &'a Arena, op_dir: &'a OpDir, state_stack: Vec, toplevel_spec: Option, @@ -530,19 +533,39 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option } } - match Number::try_from(addr) { - Ok(Number::Fixnum(n)) if n.get_num() >= 0 => { - Some(numbervar(offset + Integer::from(n.get_num()))) + read_heap_cell!(addr, + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::Integer, n) => { + if !n.is_negative() { + Some(numbervar(Integer::from(offset + &*n))) + } else { + None + } + } + _ => { + None + } + ) } - Ok(Number::Integer(n)) if !n.is_negative() => Some(numbervar(Integer::from(offset + &*n))), - _ => None, - } + (HeapCellValueTag::Fixnum, n) => { + if n.get_num() >= 0 { + Some(numbervar(offset + Integer::from(n.get_num()))) + } else { + None + } + } + _ => { + None + } + ) } impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { pub fn new( heap: &'a mut Heap, stack: &'a mut Stack, + arena: &'a Arena, op_dir: &'a OpDir, output: Outputter, term_loc: usize, @@ -550,6 +573,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { HCPrinter { outputter: output, iter: stackful_preorder_iter(heap, stack, term_loc), + arena, op_dir, state_stack: vec![], toplevel_spec: None, @@ -1280,11 +1304,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let at_cdr = self.outputter.ends_with("|"); - if self.double_quotes && !self.ignore_ops && !is_cyclic { - if end_cell.is_string_terminator(self.iter.heap) { - self.remove_list_children(focus.value() as usize); - return self.print_proper_string(focus.value() as usize, max_depth); - } + if self.double_quotes + && !self.ignore_ops + && !is_cyclic + && end_cell.is_string_terminator(self.iter.heap) + { + self.remove_list_children(focus.value() as usize); + return self.print_proper_string(focus.value() as usize, max_depth); } if self.ignore_ops { @@ -1426,7 +1452,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { || if let Some(ref op) = op { if self.numbervars && arity == 1 && name == atom!("$VAR") { !self.iter.immediate_leaf_has_property(|addr| { - match Number::try_from(addr) { + match Number::try_from((addr, &self.arena.f64_tbl)) { Ok(Number::Integer(n)) => (*n).sign() == Sign::Positive, Ok(Number::Fixnum(n)) => n.get_num() >= 0, Ok(Number::Float(f)) => f >= OrderedFloat(0f64), @@ -1511,28 +1537,29 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - fn print_index_ptr(&mut self, idx: CodeIndex, max_depth: usize) { + fn print_index_ptr(&mut self, idx: CodeIndexOffset, max_depth: usize) { if self.format_struct(max_depth, 1, atom!("$index_ptr")) { let atom = self.state_stack.pop().unwrap(); self.state_stack.pop(); self.state_stack.pop(); - let idx_ptr = idx.as_ptr(); + let idx_ptr = self.arena.code_index_tbl.lookup(idx); let offset = if idx_ptr.is_undefined() || idx_ptr.is_dynamic_undefined() { TokenOrRedirect::Atom(atom!("undefined")) } else { let idx_ptr_p = idx_ptr.p() as i64; - TokenOrRedirect::NumberFocus( - max_depth, - NumberFocus::Unfocused(Number::Fixnum( - /* FIXME this is not safe */ - unsafe { Fixnum::build_with_unchecked(idx_ptr_p) }, - )), - None, - ) + if let Ok(n) = Fixnum::build_with_checked(idx_ptr_p) { + TokenOrRedirect::NumberFocus( + max_depth, + NumberFocus::Unfocused(Number::Fixnum(n)), + None, + ) + } else { + TokenOrRedirect::Atom(atom!("out_of_bounds_idx_ptr")) + } }; self.state_stack.push(offset); @@ -1612,7 +1639,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { is_functor_redirect: bool, mut max_depth: usize, ) { - let negated_operand = negated_op_needs_bracketing(&self.iter, self.op_dir, &op); + let negated_operand = + negated_op_needs_bracketing(&self.iter, &self.arena.f64_tbl, self.op_dir, &op); let addr = match self.check_for_seen(&mut max_depth) { Some(addr) => addr, @@ -1714,14 +1742,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }); } } - (HeapCellValueTag::CodeIndex, idx) => { + (HeapCellValueTag::CodeIndexOffset, idx) => { self.print_index_ptr(idx, self.max_depth); } (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => { self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op); } - (HeapCellValueTag::F64, f) => { - self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(*f)), &op); + (HeapCellValueTag::F64Offset, offset) => { + let f = *self.arena.f64_tbl.lookup(offset.into()); + self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(f)), &op); } (HeapCellValueTag::PStrLoc) => { self.print_list_like(max_depth); @@ -1885,6 +1914,7 @@ mod tests { let printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 3, @@ -1917,6 +1947,7 @@ mod tests { let printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 5, @@ -1944,6 +1975,7 @@ mod tests { let printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 0, @@ -1956,6 +1988,7 @@ mod tests { let mut printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 0, @@ -1999,6 +2032,7 @@ mod tests { let printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 0, @@ -2017,6 +2051,7 @@ mod tests { let printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 0, @@ -2033,6 +2068,7 @@ mod tests { let mut printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 0, @@ -2069,6 +2105,7 @@ mod tests { let mut printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 0, @@ -2094,6 +2131,7 @@ mod tests { let printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 2, @@ -2123,6 +2161,7 @@ mod tests { let mut printer = HCPrinter::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, + &wam.machine_st.arena, &wam.op_dir, PrinterOutputter::new(), 2, diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index d1667795..8e4c0552 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1124,7 +1124,7 @@ impl MachineState { &ArithmeticTerm::Reg(r) => { let value = self.store(self.deref(self[r])); - match Number::try_from(value) { + match Number::try_from((value, &self.arena.f64_tbl)) { Ok(n) => Ok(n), Err(_) => { self.heap[0] = value; @@ -1388,7 +1388,8 @@ impl MachineState { (HeapCellValueTag::Fixnum, n) => { self.interms.push(Number::Fixnum(n)); } - (HeapCellValueTag::F64, fl) => { + (HeapCellValueTag::F64Offset, offset) => { + let fl = self.arena.f64_tbl.lookup(offset); self.interms.push(Number::Float(*fl)); } (HeapCellValueTag::Cons, ptr) => { diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 1b2f6bff..0ce7b5b8 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -700,31 +700,25 @@ fn remove_non_leading_clause( } } -fn finalize_retract( +fn finalize_retract<'a, LS: LoadState<'a>>( + payload: &mut >::LoaderFieldType, key: PredicateKey, compilation_target: CompilationTarget, skeleton: &mut PredicateSkeleton, code_index: CodeIndex, target_pos: usize, index_ptr_opt: Option, - retraction_info: &mut RetractionInfo, ) -> usize { let clause_clause_loc = delete_from_skeleton( compilation_target, key, skeleton, target_pos, - retraction_info, + &mut payload.retraction_info, ); if let Some(index_ptr) = index_ptr_opt { - set_code_index( - retraction_info, - &compilation_target, - key, - code_index, - index_ptr, - ); + set_code_index::(payload, &compilation_target, key, code_index, index_ptr); } clause_clause_loc @@ -1239,7 +1233,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let mut preprocessor = Preprocessor::new(settings); let clause = preprocessor.try_term_to_tl(self, term)?; - let mut cg = CodeGenerator::new(settings); + let f64_tbl = &LS::machine_st(&mut self.payload).arena.f64_tbl; + + let mut cg = CodeGenerator::new(f64_tbl, settings); let clause_code = cg.compile_predicate(vec![clause])?; Ok(StandaloneCompileResult { @@ -1254,7 +1250,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { mut predicates: PredicateQueue, settings: CodeGenSettings, ) -> Result { - let code_index = self.get_or_insert_code_index(key, predicates.compilation_target); + let code_idx = self.get_or_insert_code_index(key, predicates.compilation_target); LS::err_on_builtin_overwrite(self, key)?; @@ -1268,7 +1264,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { clauses.push(preprocessor.try_term_to_tl(self, term)?); } - let mut cg = CodeGenerator::new(settings); + let f64_tbl = &LS::machine_st(&mut self.payload).arena.f64_tbl; + + let mut cg = CodeGenerator::new(f64_tbl, settings); let mut code = cg.compile_predicate(clauses)?; if settings.is_extensible { @@ -1327,9 +1325,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ); } + let index_ptr = LS::machine_st(&mut self.payload) + .arena + .code_index_tbl + .lookup(code_idx.into()); + print_overwrite_warning( &predicates.compilation_target, - code_index.get(), + *index_ptr, key, settings.is_dynamic(), ); @@ -1340,16 +1343,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { IndexPtr::index(code_ptr) }; - set_code_index( - &mut self.payload.retraction_info, + set_code_index::( + &mut self.payload, &predicates.compilation_target, key, - code_index, + code_idx, index_ptr, ); self.wam_prelude.code.extend(code); - Ok(code_index) + Ok(code_idx) } fn extend_local_predicate_skeleton( @@ -1551,19 +1554,19 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { self.push_back_to_local_predicate_skeleton(&compilation_target, &key, code_len); - let code_index = self.get_or_insert_code_index(key, compilation_target); + let code_idx = self.get_or_insert_code_index(key, compilation_target); if let Some(new_code_ptr) = result { - set_code_index( - &mut self.payload.retraction_info, + set_code_index::( + &mut self.payload, &compilation_target, key, - code_index, + code_idx, new_code_ptr, ); } - Ok(code_index) + Ok(code_idx) } AppendOrPrepend::Prepend => { let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap(); @@ -1593,17 +1596,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { self.push_front_to_local_predicate_skeleton(&compilation_target, &key, code_len); - let code_index = self.get_or_insert_code_index(key, compilation_target); + let code_idx = self.get_or_insert_code_index(key, compilation_target); - set_code_index( - &mut self.payload.retraction_info, + set_code_index::( + &mut self.payload, &compilation_target, key, - code_index, + code_idx, new_code_ptr, ); - Ok(code_index) + Ok(code_idx) } } } @@ -1651,7 +1654,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize { let payload_compilation_target = self.payload.compilation_target; - let code_index = self.get_or_insert_code_index(key, payload_compilation_target); + let code_idx_offset = self.get_or_insert_code_index(key, payload_compilation_target); let skeleton = self .wam_prelude @@ -1729,14 +1732,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { None }; - return finalize_retract( + return finalize_retract::( + &mut self.payload, key, payload_compilation_target, skeleton, - code_index, + code_idx_offset, target_pos, index_ptr_opt, - &mut self.payload.retraction_info, ); } None => { @@ -1758,14 +1761,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ) }; - return finalize_retract( + return finalize_retract::( + &mut self.payload, key, payload_compilation_target, skeleton, - code_index, + code_idx_offset, target_pos, index_ptr_opt, - &mut self.payload.retraction_info, ); } } @@ -1988,14 +1991,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } }; - finalize_retract( + finalize_retract::( + &mut self.payload, key, payload_compilation_target, skeleton, - code_index, + code_idx_offset, target_pos, index_ptr_opt, - &mut self.payload.retraction_info, ) } } @@ -2222,18 +2225,23 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { }; let predicates = self.payload.predicates.take(); - let code_index = self.compile(key, predicates, settings)?; + let offset = self.compile(key, predicates, settings)?; if let Some(filename) = self.listing_src_file_name() { if let Some(ref mut module) = self.wam_prelude.indices.modules.get_mut(&filename) { - let index_ptr = code_index.get(); - let code_index = *module.code_dir.entry(key).or_insert(code_index); + let code_idx = LS::machine_st(&mut self.payload) + .arena + .code_index_tbl + .lookup_mut(offset.into()); - set_code_index( - &mut self.payload.retraction_info, + let index_ptr = *code_idx; + let offset = *module.code_dir.entry(key).or_insert(offset); + + set_code_index::( + &mut self.payload, &CompilationTarget::Module(filename), key, - code_index, + offset, index_ptr, ); } diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index 2187e7b8..4ecac7bc 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -579,7 +579,7 @@ impl VariableClassifier { mut terms, ) if terms.len() == 3 => { if let Some(last_arg) = terms.last() { - if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { + if let Term::Literal(_, Literal::CodeIndexOffset(_)) = last_arg { terms.pop(); state_stack.push(TraversalState::Term(Term::Clause( Cell::default(), diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 20dfd8ee..20d60c94 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -232,13 +232,11 @@ impl MachineState { } (HeapCellValueTag::PStrLoc | HeapCellValueTag::Lis) => { - // HeapCellValueTag::CStr) => { l } (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint | - // HeapCellValueTag::Char | - HeapCellValueTag::F64) => { + HeapCellValueTag::F64Offset) => { c } (HeapCellValueTag::Atom, (_name, arity)) => { @@ -548,19 +546,33 @@ impl Machine { let p = self.machine_st.p; // Find the boundaries of the current predicate - self.indices.code_dir.sort_by(|_, a, _, b| a.cmp(b)); + self.indices.code_dir.sort_by(|_, a, _, b| { + let a = *self.machine_st.arena.code_index_tbl.lookup((*a).into()); + let b = *self.machine_st.arena.code_index_tbl.lookup((*b).into()); + + a.cmp(&b) + }); let predicate_idx = self .indices .code_dir - .binary_search_by_key(&p, |_, x| x.get().p() as usize) + .binary_search_by_key(&p, |_, x| -> usize { + self.machine_st.arena.code_index_tbl.lookup((*x).into()).p() + as usize + }) .unwrap_or_else(|x| x - 1); let current_pred_start = self .indices .code_dir .get_index(predicate_idx) - .map(|x| x.1.as_ptr().p() as usize) + .map(|idx| { + self.machine_st + .arena + .code_index_tbl + .lookup((*idx.1).into()) + .p() as usize + }) .unwrap(); debug_assert!(current_pred_start <= p); @@ -569,7 +581,13 @@ impl Machine { .indices .code_dir .get_index(predicate_idx + 1) - .map(|x| x.1.as_ptr().p() as usize) + .map(|idx| { + self.machine_st + .arena + .code_index_tbl + .lookup((*idx.1).into()) + .p() as usize + }) .unwrap_or(self.code.len()); debug_assert!(current_pred_end >= p); @@ -2343,7 +2361,7 @@ impl Machine { .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, - (HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + (HeapCellValueTag::Fixnum | HeapCellValueTag::F64Offset | HeapCellValueTag::Cons) => { self.machine_st.p += 1; } @@ -2375,7 +2393,7 @@ impl Machine { .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, - (HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + (HeapCellValueTag::Fixnum | HeapCellValueTag::F64Offset | HeapCellValueTag::Cons) => { self.machine_st.p = self.machine_st.cp; } @@ -2472,7 +2490,7 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st[r])); - match Number::try_from(d) { + match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(_) | Number::Integer(_)) => { self.machine_st.p += 1; } @@ -2493,7 +2511,7 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st[r])); - match Number::try_from(d) { + match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(_) | Number::Integer(_)) => { self.machine_st.p = self.machine_st.cp; } @@ -2514,7 +2532,7 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st[r])); - match Number::try_from(d) { + match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(_) => { self.machine_st.p += 1; } @@ -2528,7 +2546,7 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st[r])); - match Number::try_from(d) { + match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(_) => { self.machine_st.p = self.machine_st.cp; } @@ -2590,7 +2608,7 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st[r])); - match Number::try_from(d) { + match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(Number::Float(_)) => { self.machine_st.p += 1; } @@ -2604,7 +2622,7 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st[r])); - match Number::try_from(d) { + match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(Number::Float(_)) => { self.machine_st.p = self.machine_st.cp; } @@ -2677,10 +2695,10 @@ impl Machine { } } } - &Instruction::CallNamed(arity, name, ref idx) => { - let idx = idx.get(); + &Instruction::CallNamed(arity, name, idx) => { + let idx = self.machine_st.arena.code_index_tbl.lookup(idx.into()); - try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); + try_or_throw!(self.machine_st, self.try_call(name, arity, *idx)); if self.machine_st.fail { self.machine_st.backtrack(); @@ -2688,10 +2706,10 @@ impl Machine { increment_call_count!(self.machine_st); } } - &Instruction::ExecuteNamed(arity, name, ref idx) => { - let idx = idx.get(); + &Instruction::ExecuteNamed(arity, name, idx) => { + let idx = self.machine_st.arena.code_index_tbl.lookup(idx.into()); - try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); + try_or_throw!(self.machine_st, self.try_execute(name, arity, *idx)); if self.machine_st.fail { self.machine_st.backtrack(); @@ -2699,19 +2717,19 @@ impl Machine { increment_call_count!(self.machine_st); } } - &Instruction::DefaultCallNamed(arity, name, ref idx) => { - let idx = idx.get(); + &Instruction::DefaultCallNamed(arity, name, idx) => { + let idx = self.machine_st.arena.code_index_tbl.lookup(idx.into()); - try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); + try_or_throw!(self.machine_st, self.try_call(name, arity, *idx)); if self.machine_st.fail { self.machine_st.backtrack(); } } - &Instruction::DefaultExecuteNamed(arity, name, ref idx) => { - let idx = idx.get(); + &Instruction::DefaultExecuteNamed(arity, name, idx) => { + let idx = self.machine_st.arena.code_index_tbl.lookup(idx.into()); - try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); + try_or_throw!(self.machine_st, self.try_execute(name, arity, *idx)); if self.machine_st.fail { self.machine_st.backtrack(); @@ -5251,7 +5269,7 @@ impl Machine { let l = self.machine_st.registers[3]; let l = self.machine_st.store(self.machine_st.deref(l)); - let l = match Number::try_from(l) { + let l = match Number::try_from((l, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(l)) => l.get_num() as usize, _ => unreachable!(), }; @@ -5259,7 +5277,7 @@ impl Machine { let p = self.machine_st.registers[4]; let p = self.machine_st.store(self.machine_st.deref(p)); - let p = match Number::try_from(p) { + let p = match Number::try_from((p, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(p)) => p.get_num() as usize, _ => unreachable!(), }; @@ -5297,7 +5315,7 @@ impl Machine { let l = self.machine_st.registers[3]; let l = self.machine_st.store(self.machine_st.deref(l)); - let l = match Number::try_from(l) { + let l = match Number::try_from((l, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(l)) => l.get_num() as usize, _ => unreachable!(), }; @@ -5305,7 +5323,7 @@ impl Machine { let p = self.machine_st.registers[4]; let p = self.machine_st.store(self.machine_st.deref(p)); - let p = match Number::try_from(p) { + let p = match Number::try_from((p, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(p)) => p.get_num() as usize, _ => unreachable!(), }; diff --git a/src/machine/heap.rs b/src/machine/heap.rs index dc4d2ce0..fdf24047 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1,6 +1,6 @@ use crate::atom_table::*; -use crate::forms::*; use crate::functor_macro::*; +use crate::machine::{ArenaHeaderTag, Fixnum, Integer}; use crate::types::*; use std::alloc; @@ -717,7 +717,7 @@ impl Heap { pub(crate) fn slice_to_str(&self, slice_loc: usize, slice_len: usize) -> &str { unsafe { let slice = std::slice::from_raw_parts(self.inner.ptr.add(slice_loc), slice_len); - std::str::from_utf8_unchecked(&slice) + std::str::from_utf8_unchecked(slice) } } @@ -824,7 +824,7 @@ impl Heap { let s = unsafe { let char_ptr = self.inner.ptr.add(byte_idx); let slice = std::slice::from_raw_parts(char_ptr, size_of::()); - std::str::from_utf8_unchecked(&slice) + std::str::from_utf8_unchecked(slice) }; s.chars().next().unwrap() @@ -1158,14 +1158,24 @@ pub fn sized_iter_to_heap_list>( pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option { let extract_integer = |s: usize| -> Option { - match Number::try_from(heap[s]) { - Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), - Ok(Number::Integer(n)) => { - let value: usize = (&*n).try_into().unwrap(); - Some(value) + read_heap_cell!(heap[s], + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::Integer, n) => { + (&*n).try_into().ok() + } + _ => { + None + } + ) } - _ => None, - } + (HeapCellValueTag::Fixnum, n) => { + usize::try_from(n.get_num()).ok() + } + _ => { + None + } + ) }; read_heap_cell!(addr, diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index 7e87dc00..dbaac207 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -277,14 +277,15 @@ impl Term { }, } } - (HeapCellValueTag::F64, f) => { - term_stack.push(Term::Float((*f).into())); + (HeapCellValueTag::F64Offset, offset) => { + let f = *machine.machine_st.arena.f64_tbl.lookup(offset); + term_stack.push(Term::Float(f.into())); } (HeapCellValueTag::Fixnum, n) => { term_stack.push(Term::Integer(n.into())); } (HeapCellValueTag::Cons, ptr) => { - if let Ok(n) = Number::try_from(addr) { + if let Ok(n) = Number::try_from((addr, &machine.machine_st.arena.f64_tbl)) { match n { Number::Integer(i) => term_stack.push(Term::Integer((*i).clone())), Number::Rational(r) => term_stack.push(Term::Rational((*r).clone())), @@ -312,31 +313,6 @@ impl Term { } } (HeapCellValueTag::Atom, (name, arity)) => { - //let h = iter.focus().value() as usize; - //let mut arity = arity; - - // Not sure why/if this is needed. - // Might find out with better testing later. - /* - 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 { let atom_name = name.as_str().to_string(); if atom_name == "[]" { @@ -621,9 +597,15 @@ impl Machine { .indices .code_dir .get(&(atom!("call"), 1)) - .expect("couldn't get code index") - .local() - .unwrap(); + .cloned() + .map(|offset| { + self.machine_st + .arena + .code_index_tbl + .lookup(offset.into()) + .p() as usize + }) + .expect("couldn't get code index"); self.machine_st.execute_at_index(1, call_index_p); diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 0a712c1a..123c7be5 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -15,35 +15,40 @@ use std::mem; pub(super) type ModuleOpExports = Vec<(OpDecl, Option)>; -pub(super) fn set_code_index( - retraction_info: &mut RetractionInfo, +pub(super) fn set_code_index<'a, LS: LoadState<'a>>( + payload: &mut >::LoaderFieldType, compilation_target: &CompilationTarget, key: PredicateKey, - mut code_index: CodeIndex, + code_idx: CodeIndex, code_ptr: IndexPtr, ) { + let mut code_idx_ptr = LS::machine_st(payload) + .arena + .code_index_tbl + .lookup_mut(code_idx.into()); + let record = match compilation_target { CompilationTarget::User => { - if IndexPtrTag::Undefined == code_index.get().tag() { - code_index.set(code_ptr); + if IndexPtrTag::Undefined == code_idx_ptr.tag() { + code_idx_ptr.set(code_ptr); RetractionRecord::AddedUserPredicate(key) } else { - let replaced = code_index.replace(code_ptr); + let replaced = code_idx_ptr.replace(code_ptr); RetractionRecord::ReplacedUserPredicate(key, replaced) } } CompilationTarget::Module(ref module_name) => { - if IndexPtrTag::Undefined == code_index.get().tag() { - code_index.set(code_ptr); + if IndexPtrTag::Undefined == code_idx_ptr.tag() { + code_idx_ptr.set(code_ptr); RetractionRecord::AddedModulePredicate(*module_name, key) } else { - let replaced = code_index.replace(code_ptr); + let replaced = code_idx_ptr.replace(code_ptr); RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced) } } }; - retraction_info.push_record(record); + payload.retraction_info.push_record(record); } fn add_op_decl_as_module_export<'a, LS: LoadState<'a>>( @@ -133,21 +138,28 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>( } if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() { - let arena = &mut LS::machine_st(payload).arena; + let code_idx_tbl = &mut LS::machine_st(payload).arena.code_index_tbl; let target_code_index = *code_dir .entry(key) - .or_insert_with(|| CodeIndex::default(arena)); + .or_insert_with(|| CodeIndex::default(code_idx_tbl)); - set_code_index( - &mut payload.retraction_info, + let src_code_index_ptr = *code_idx_tbl.lookup(src_code_index.into()); + + set_code_index::( + payload, compilation_target, key, target_code_index, - src_code_index.get(), + src_code_index_ptr, ); - if src_code_index.as_ptr().is_dynamic_undefined() { + if LS::machine_st(payload) + .arena + .code_index_tbl + .lookup(src_code_index.into()) + .is_dynamic_undefined() + { code_dir.insert(key, src_code_index); } } else { @@ -189,19 +201,20 @@ fn import_module_exports_into_module<'a, LS: LoadState<'a>>( meta_predicates.insert(key, meta_specs.clone()); } - if let Some(src_code_index) = imported_module.code_dir.get(&key) { - let arena = &mut LS::machine_st(payload).arena; + if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() { + let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl; + let src_code_ptr = *code_index_tbl.lookup(src_code_index.into()); let target_code_index = *code_dir .entry(key) - .or_insert_with(|| CodeIndex::default(arena)); + .or_insert_with(|| CodeIndex::default(code_index_tbl)); - set_code_index( - &mut payload.retraction_info, + set_code_index::( + payload, compilation_target, key, target_code_index, - src_code_index.get(), + src_code_ptr, ); } else { return Err(SessionError::ModuleDoesNotContainExport( @@ -242,21 +255,21 @@ fn import_qualified_module_exports<'a, LS: LoadState<'a>>( .insert(key, meta_specs.clone()); } - if let Some(src_code_index) = imported_module.code_dir.get(&key) { - let arena = &mut LS::machine_st(payload).arena; + if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() { + let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl; - let target_code_index = *wam_prelude - .indices - .code_dir - .entry(key) - .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)); + let src_code_ptr = *code_index_tbl.lookup(src_code_index.into()); + let target_code_index = + *wam_prelude.indices.code_dir.entry(key).or_insert_with(|| { + CodeIndex::new(IndexPtr::undefined(), code_index_tbl) + }); - set_code_index( - &mut payload.retraction_info, + set_code_index::( + payload, compilation_target, key, target_code_index, - src_code_index.get(), + src_code_ptr, ); } else { return Err(SessionError::ModuleDoesNotContainExport( @@ -303,19 +316,20 @@ fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>( meta_predicates.insert(key, meta_specs.clone()); } - if let Some(src_code_index) = imported_module.code_dir.get(&key) { - let arena = &mut LS::machine_st(payload).arena; + if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() { + let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl; + let src_code_ptr = *code_index_tbl.lookup(src_code_index.into()); let target_code_index = *code_dir .entry(key) - .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)); + .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl)); - set_code_index( - &mut payload.retraction_info, + set_code_index::( + payload, &payload_compilation_target, key, target_code_index, - src_code_index.get(), + src_code_ptr, ); } else { return Err(SessionError::ModuleDoesNotContainExport( @@ -468,11 +482,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .indices .get_predicate_skeleton(local_compilation_target, key) { - let old_index_ptr = code_index.replace(if global_skeleton.core.is_dynamic { - IndexPtr::dynamic_undefined() - } else { - IndexPtr::undefined() - }); + let old_index_ptr = code_index.replace( + &mut LS::machine_st(&mut self.payload).arena.code_index_tbl, + if global_skeleton.core.is_dynamic { + IndexPtr::dynamic_undefined() + } else { + IndexPtr::undefined() + }, + ); self.payload.retraction_info.push_record( RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr), @@ -486,8 +503,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { continue; } - if !code_index.as_ptr().is_undefined() && !code_index.as_ptr().is_dynamic_undefined() { - let old_index_ptr = code_index.replace(IndexPtr::undefined()); + let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl; + let code_ptr = code_index_tbl.lookup((*code_index).into()); + + if !code_ptr.is_undefined() && !code_ptr.is_dynamic_undefined() { + let old_index_ptr = code_index.replace(code_index_tbl, IndexPtr::undefined()); self.payload.retraction_info.push_record( RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr), @@ -517,25 +537,34 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { None => return, }; - fn remove_module_exports( + fn remove_module_exports<'b, LS: LoadState<'b>>( + payload: &mut >::LoaderFieldType, removed_module: &Module, code_dir: &mut CodeDir, op_dir: &mut OpDir, - retraction_info: &mut RetractionInfo, predicate_retractor: impl Fn(PredicateKey, IndexPtr) -> RetractionRecord, op_retractor: impl Fn(OpDecl, OpDesc) -> RetractionRecord, ) { for export in removed_module.module_decl.exports.iter() { match export { ModuleExport::PredicateKey(ref key) => { - match (removed_module.code_dir.get(key), code_dir.get_mut(key)) { - (Some(module_code_index), Some(target_code_index)) - if module_code_index.get() == target_code_index.get() => - { - let old_index_ptr = - target_code_index.replace(IndexPtr::undefined()); - retraction_info - .push_record(predicate_retractor(*key, old_index_ptr)); + match ( + removed_module.code_dir.get(key).cloned(), + code_dir.get_mut(key).cloned(), + ) { + (Some(module_code_idx), Some(target_code_idx)) => { + let code_index_tbl = + &mut LS::machine_st(payload).arena.code_index_tbl; + let module_code_ptr = code_index_tbl.lookup(module_code_idx.into()); + let target_code_ptr = code_index_tbl.lookup(target_code_idx.into()); + + if module_code_ptr == target_code_ptr { + let old_index_ptr = target_code_idx + .replace(code_index_tbl, IndexPtr::undefined()); + payload + .retraction_info + .push_record(predicate_retractor(*key, old_index_ptr)); + } } _ => {} } @@ -545,7 +574,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .swap_remove(&(op_decl.name, op_decl.op_desc.get_spec().fixity())); if let Some(op_desc) = op_dir_value_opt { - retraction_info.push_record(op_retractor(*op_decl, op_desc)); + payload + .retraction_info + .push_record(op_retractor(*op_decl, op_desc)); } } } @@ -554,11 +585,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { match self.payload.compilation_target { CompilationTarget::User => { - remove_module_exports( + remove_module_exports::( + &mut self.payload, &removed_module, &mut self.wam_prelude.indices.code_dir, &mut self.wam_prelude.indices.op_dir, - &mut self.payload.retraction_info, RetractionRecord::ReplacedUserPredicate, RetractionRecord::ReplacedUserOp, ); @@ -578,11 +609,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .modules .get_mut(&target_module_name) { - remove_module_exports( + remove_module_exports::( + &mut self.payload, &removed_module, &mut module.code_dir, &mut module.op_dir, - &mut self.payload.retraction_info, predicate_retractor, op_retractor, ); @@ -608,7 +639,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| { CodeIndex::new( IndexPtr::undefined(), - &mut LS::machine_st(&mut self.payload).arena, + &mut LS::machine_st(&mut self.payload).arena.code_index_tbl, ) }), None => { @@ -618,7 +649,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| { CodeIndex::new( IndexPtr::undefined(), - &mut LS::machine_st(&mut self.payload).arena, + &mut LS::machine_st(&mut self.payload).arena.code_index_tbl, ) }), None => { @@ -634,7 +665,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { key: PredicateKey, compilation_target: CompilationTarget, ) -> CodeIndex { - let arena = &mut LS::machine_st(&mut self.payload).arena; + let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl; match compilation_target { CompilationTarget::User => *self @@ -642,7 +673,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .indices .code_dir .entry(key) - .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)), + .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl)), CompilationTarget::Module(module_name) => { self.get_or_insert_local_code_index(module_name, key) } @@ -654,7 +685,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { module_name: Atom, key: PredicateKey, ) -> CodeIndex { - let arena = &mut LS::machine_st(&mut self.payload).arena; + let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl; if module_name == atom!("user") { return *self @@ -662,7 +693,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .indices .code_dir .entry(key) - .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)); + .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl)); } else { self.get_or_insert_local_code_index(module_name, key) } diff --git a/src/machine/loader.rs b/src/machine/loader.rs index c18eceda..cfec0bf6 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -720,7 +720,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { self.wam_prelude.indices.modules.get_mut(&module_name) { if let Some(code_idx) = module.code_dir.get_mut(&key) { - code_idx.set(old_code_idx) + let code_index_tbl = + &mut LS::machine_st(&mut self.payload).arena.code_index_tbl; + code_idx.set(code_index_tbl, old_code_idx); } } } @@ -741,7 +743,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => { if let Some(code_idx) = self.wam_prelude.indices.code_dir.get_mut(&key) { - code_idx.set(old_code_idx) + let code_index_tbl = + &mut LS::machine_st(&mut self.payload).arena.code_index_tbl; + code_idx.set(code_index_tbl, old_code_idx) } } RetractionRecord::AddedIndex(index_key, clause_loc) => { @@ -1217,14 +1221,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { * but to multifile and discontiguous predicates as well. */ - let code_index = self.get_or_insert_code_index(key, compilation_target); + let offset = self.get_or_insert_code_index(key, compilation_target); + let code_idx_ptr = LS::machine_st(&mut self.payload) + .arena + .code_index_tbl + .lookup_mut(offset.into()); - if code_index.as_ptr().is_undefined() { - set_code_index( - &mut self.payload.retraction_info, + if code_idx_ptr.is_undefined() { + set_code_index::( + &mut self.payload, &compilation_target, key, - code_index, + offset, IndexPtr::dynamic_undefined(), ); } @@ -1395,7 +1403,7 @@ impl MachineState { Err(cons_term) => term_stack.push(cons_term), } } - (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64) => { + (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64Offset) => { term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap())); } (HeapCellValueTag::StackVar, h) => { @@ -1410,7 +1418,7 @@ impl MachineState { let value = iter.heap[h.saturating_sub(1)]; if let Some(idx) = get_structure_index(value) { - term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx))); + term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndexOffset(idx.into()))); arity += 1; } @@ -1588,7 +1596,7 @@ impl Machine { let predicate_name = cell_as_atom!(self.deref_register(2)); let arity = self.deref_register(3); - let arity = match Number::try_from(arity) { + let arity = match Number::try_from((arity, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) if *n >= Integer::ZERO && *n <= Integer::from(MAX_ARITY) => { let value: usize = (&*n).try_into().unwrap(); Ok(value) @@ -1999,7 +2007,15 @@ impl Machine { .wam_prelude .indices .get_predicate_code_index(name, arity, module_name) - .map(|code_idx| code_idx.get_tag()) + .map(|offset| { + loader + .payload + .machine_st + .arena + .code_index_tbl + .lookup(offset.into()) + .tag() + }) .unwrap_or(IndexPtrTag::DynamicUndefined); if idx_tag == IndexPtrTag::Index { @@ -2142,9 +2158,15 @@ impl Machine { .indices .remove_predicate_skeleton(&compilation_target, &key); - let mut code_index = loader.get_or_insert_code_index(key, compilation_target); + let offset = loader.get_or_insert_code_index(key, compilation_target); + let mut code_idx = loader + .payload + .machine_st + .arena + .code_index_tbl + .lookup_mut(offset.into()); - code_index.set(IndexPtr::undefined()); + code_idx.set(IndexPtr::undefined()); loader.payload.compilation_target = clause_clause_compilation_target; @@ -2174,7 +2196,7 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st[temp_v!(3)])); - let target_pos = match Number::try_from(target_pos) { + let target_pos = match Number::try_from((target_pos, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) => { let value: usize = (&*n).try_into().unwrap(); value diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 8dc5291f..66caba46 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -2,7 +2,6 @@ use crate::parser::ast::*; -use crate::arena::*; use crate::atom_table::*; use crate::forms::*; use crate::machine::loader::*; @@ -19,7 +18,6 @@ use scryer_modular_bitfield::{bitfield, BitfieldSpecifier}; use std::cmp::Ordering; use std::collections::BTreeSet; -use std::ops::Deref; use crate::types::*; @@ -127,9 +125,18 @@ impl IndexPtr { pub(crate) fn is_dynamic_undefined(&self) -> bool { matches!(self.tag(), IndexPtrTag::DynamicUndefined) } + + #[inline] + pub(crate) fn local(&self) -> Option { + match self.tag() { + IndexPtrTag::Index => Some(self.p() as usize), + IndexPtrTag::DynamicIndex => Some(self.p() as usize), + _ => None, + } + } } -#[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)] +#[derive(Debug, Clone, Copy)] // , Ord, Hash, PartialOrd, Eq, PartialEq)] pub struct CodeIndex(CodeIndexOffset); #[cfg(target_pointer_width = "32")] @@ -141,7 +148,7 @@ const_assert!(std::mem::align_of::() == 8); impl From for HeapCellValue { #[inline(always)] fn from(idx: CodeIndex) -> HeapCellValue { - HeapCellValue::from(idx.as_ptr()) + HeapCellValue::from(idx.0) } } @@ -152,48 +159,39 @@ impl From for CodeIndex { } } +impl Into for CodeIndex { + #[inline(always)] + fn into(self) -> CodeIndexOffset { + self.0 + } +} + +impl Into for &'_ CodeIndex { + #[inline(always)] + fn into(self) -> CodeIndexOffset { + self.0 + } +} + impl CodeIndex { #[inline] - pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self { - unsafe { CodeIndex(arena.code_index_tbl.build_with(ptr)) } + pub(crate) fn new(ptr: IndexPtr, code_index_tbl: &mut CodeIndexTable) -> Self { + CodeIndex(code_index_tbl.build_with(ptr)) } #[inline(always)] - pub(crate) fn default(arena: &mut Arena) -> Self { - CodeIndex::new(IndexPtr::undefined(), arena) - } - - pub(crate) fn local(&self) -> Option { - match self.0.as_ptr().tag() { - IndexPtrTag::Index => Some(self.get().p() as usize), - IndexPtrTag::DynamicIndex => Some(self.get().p() as usize), - _ => None, - } + pub(crate) fn default(code_index_tbl: &mut CodeIndexTable) -> Self { + CodeIndex::new(IndexPtr::undefined(), code_index_tbl) } #[inline(always)] - pub(crate) fn get(&self) -> IndexPtr { - *self.as_ptr().deref() + pub(crate) fn set(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) { + code_index_tbl.lookup_mut(self.0).set(value); } #[inline(always)] - pub(crate) fn set(&mut self, value: IndexPtr) { - self.as_ptr().set(value); - } - - #[inline(always)] - pub(crate) fn get_tag(self) -> IndexPtrTag { - self.get().tag() - } - - #[inline(always)] - pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr { - self.as_ptr().replace(value) - } - - #[inline(always)] - pub(crate) fn as_ptr(&self) -> CodeIndexPtr { - self.0.as_ptr() + pub(crate) fn replace(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) -> IndexPtr { + code_index_tbl.lookup_mut(self.0).replace(value) } } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index e3236483..fac5d7b6 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -952,6 +952,7 @@ impl MachineState { let mut printer = HCPrinter::new( &mut self.heap, &mut self.stack, + &self.arena, op_dir, PrinterOutputter::new(), 0, @@ -962,7 +963,7 @@ impl MachineState { printer.quoted = quoted; printer.double_quotes = double_quotes; - match Number::try_from(max_depth) { + match Number::try_from((max_depth, &self.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => { if let Ok(n) = usize::try_from(n.get_num()) { printer.max_depth = n; diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index b72b18d2..385d9a4e 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -288,7 +288,7 @@ impl MachineState { unifier.unify_big_rational(n1, value); } - pub fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) { + pub fn unify_f64(&mut self, f1: F64Offset, value: HeapCellValue) { let mut unifier = DefaultUnifier::from(self); unifier.unify_f64(f1, value); } @@ -409,8 +409,11 @@ impl MachineState { } } Some(TermOrderCategory::FloatingPoint) => { - let v1 = cell_as_f64_ptr!(v1); - let v2 = cell_as_f64_ptr!(v2); + let v1 = cell_as_f64_offset!(v1); + let v2 = cell_as_f64_offset!(v2); + + let v1 = self.arena.f64_tbl.lookup(v1); + let v2 = self.arena.f64_tbl.lookup(v2); if v1 != v2 { self.pdl.clear(); @@ -418,8 +421,8 @@ impl MachineState { } } Some(TermOrderCategory::Integer) => { - let v1 = Number::try_from(v1).unwrap(); - let v2 = Number::try_from(v2).unwrap(); + let v1 = Number::try_from((v1, &self.arena.f64_tbl)).unwrap(); + let v2 = Number::try_from((v2, &self.arena.f64_tbl)).unwrap(); if v1 != v2 { self.pdl.clear(); @@ -436,22 +439,6 @@ impl MachineState { return Some(n1.cmp(&n2)); } } - /* - (HeapCellValueTag::Char, c2) => { - if let Some(c1) = n1.as_char() { - if c1 != c2 { - self.pdl.clear(); - return Some(c1.cmp(&c2)); - } - } else { - self.pdl.clear(); - return Some( - n1.as_str().chars().next().cmp(&Some(c2)) - .then(Ordering::Greater) - ); - } - } - */ (HeapCellValueTag::Str, s) => { let n2 = cell_as_atom_cell!(self.heap[s]) .get_name(); @@ -466,52 +453,6 @@ impl MachineState { } ) } - /* - (HeapCellValueTag::Char, c1) => { - read_heap_cell!(v2, - (HeapCellValueTag::Atom, (n2, _a2)) => { - if let Some(c2) = n2.as_char() { - if c1 != c2 { - self.pdl.clear(); - return Some(c1.cmp(&c2)); - } - } else { - self.pdl.clear(); - return Some( - Some(c1).cmp(&n2.as_str().chars().next()) - .then(Ordering::Less) - ); - } - } - (HeapCellValueTag::Char, c2) => { - if c1 != c2 { - self.pdl.clear(); - return Some(c1.cmp(&c2)); - } - } - (HeapCellValueTag::Str, s) => { - let n2 = cell_as_atom_cell!(self.heap[s]) - .get_name(); - - if let Some(c2) = n2.as_char() { - if c1 != c2 { - self.pdl.clear(); - return Some(c1.cmp(&c2)); - } - } else { - self.pdl.clear(); - return Some( - Some(c1).cmp(&n2.as_str().chars().next()) - .then(Ordering::Less) - ); - } - } - _ => { - unreachable!() - } - ) - } - */ (HeapCellValueTag::Str, s) => { let n1 = cell_as_atom_cell!(self.heap[s]) .get_name(); @@ -523,22 +464,6 @@ impl MachineState { return Some(n1.cmp(&n2)); } } - /* - (HeapCellValueTag::Char, c2) => { - if let Some(c1) = n1.as_char() { - if c1 != c2 { - self.pdl.clear(); - return Some(c1.cmp(&c2)); - } - } else { - self.pdl.clear(); - return Some( - n1.as_str().chars().next().cmp(&Some(c2)) - .then(Ordering::Greater) - ); - } - } - */ (HeapCellValueTag::Str, s) => { let n2 = cell_as_atom_cell!(self.heap[s]) .get_name(); @@ -865,7 +790,7 @@ impl MachineState { return Err(self.error_form(err, stub_gen())); } _ => { - let n = match Number::try_from(n) { + let n = match Number::try_from((n, &self.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => Number::Fixnum(n), Ok(Number::Integer(n)) => Number::Integer(n), _ => { @@ -917,46 +842,18 @@ impl MachineState { (HeapCellValueTag::PStrLoc, pstr_loc) => { if n == 1 || n == 2 { let a3 = self.registers[3]; - // let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc); let mut char_iter = self.heap.char_iter(pstr_loc); - // let pstr = cell_as_string!(self.heap[h]); - // let offset = offset.get_num() as usize; - - if let Some(c) = char_iter.next() { // pstr.as_str_from(offset).chars().next() { + if let Some(c) = char_iter.next() { if n == 1 { self.unify_char(c, a3); } else { - // let offset = (offset + c.len_utf8()) as i64; - // let h_len = self.heap.len(); - // let pstr_atom: Atom = pstr.into(); if char_iter.next().is_some() { unify_fn!(*self, pstr_loc_as_cell!(pstr_loc + c.len_utf8()), a3); } else { let tail_idx = Heap::pstr_tail_idx(pstr_loc + c.len_utf8()); unify_fn!(*self, self.heap[tail_idx], a3); } - - /* - if pstr_atom.len() > offset as usize { - self.heap.push(pstr_offset_as_cell!(h)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with_unchecked(offset as i64))); - - unify_fn!(*self, pstr_loc_as_cell!(h_len), a3); - } else { - match self.heap[h].get_tag() { - HeapCellValueTag::CStr => { - self.unify_atom(atom!("[]"), self.store(self.deref(a3))); - } - HeapCellValueTag::PStr => { - unify_fn!(*self, self.heap[h+1], a3); - } - _ => { - unreachable!(); - } - } - } - */ } } else { unreachable!() @@ -965,34 +862,6 @@ impl MachineState { self.fail = true; } } - /* - (HeapCellValueTag::CStr, cstr_atom) => { - let cstr = PartialString::from(cstr_atom); - - if let Some(c) = cstr.as_str_from(0).chars().next() { - if n == 1 { - self.unify_char(c, self.store(self.deref(self.registers[3]))); - } else if n == 2 { - let offset = c.len_utf8(); - let h_len = self.heap.len(); - - if cstr_atom.len() > offset{ - self.heap.push(atom_as_cstr_cell!(cstr_atom)); - self.heap.push(pstr_offset_as_cell!(h_len)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with_unchecked(offset as i64))); - - unify_fn!(*self, pstr_loc_as_cell!(h_len+1), self.registers[3]); - } else { - self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[3]))); - } - } else { - self.fail = true; - } - } else { - unreachable!() - } - } - */ _ => { // 8.5.2.3 d) let err = self.type_error(ValidType::Compound, term); @@ -1077,7 +946,7 @@ impl MachineState { read_heap_cell!(a1, (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // | HeapCellValueTag::Char - HeapCellValueTag::F64) => { + HeapCellValueTag::F64Offset) => { self.try_functor_unify_components(a1, 0); } (HeapCellValueTag::Atom, (_name, arity)) => { @@ -1103,17 +972,17 @@ impl MachineState { return Err(self.error_form(err, stub_gen())); } - let mut type_error = |arity| { - let err = self.type_error(ValidType::Integer, arity); - Err(self.error_form(err, stub_gen())) + let type_error = |machine_st: &mut Self, arity| { + let err = machine_st.type_error(ValidType::Integer, arity); + Err(machine_st.error_form(err, stub_gen())) }; - let arity = match Number::try_from(arity) { + let arity = match Number::try_from((arity, &self.arena.f64_tbl)) { Ok(Number::Float(_)) => { - return type_error(arity); + return type_error(self, arity); } Ok(Number::Rational(n)) if !n.denominator().is_one() => { - return type_error(arity); + return type_error(self, arity); } Ok(n) if n > MAX_ARITY => { // 8.5.1.3 f) @@ -1135,15 +1004,15 @@ impl MachineState { value }, Err(_) => { - return type_error(arity); + return type_error(self, arity); } }; read_heap_cell!(store_name, - (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // HeapCellValueTag::Char | - HeapCellValueTag::F64) if arity == 0 => { - self.bind(a1.as_var().unwrap(), deref_name); - } + (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64Offset) + if arity == 0 => { + self.bind(a1.as_var().unwrap(), deref_name); + } (HeapCellValueTag::Atom, (name, atom_arity)) => { debug_assert_eq!(atom_arity, 0); resource_error_call_result!( @@ -1173,22 +1042,8 @@ impl MachineState { return Err(self.error_form(err, stub_gen())); } } - /* - (HeapCellValueTag::Char, c) => { - let c = AtomTable::build_with(&self.atom_tbl, &c.to_string()); - - resource_error_call_result!( - self, - self.try_functor_fabricate_struct( - c, - arity as usize, - a1.as_var().unwrap(), - ) - ); - } - */ (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | - HeapCellValueTag::F64) if arity != 0 => { + HeapCellValueTag::F64Offset) if arity != 0 => { let err = self.type_error(ValidType::Atom, store_name); return Err(self.error_form(err, stub_gen())); // 8.5.1.3 e) } @@ -1243,12 +1098,6 @@ impl MachineState { Err(self.error_form(err, stub_gen())) } } - /* - (HeapCellValueTag::CStr, cstr_atom) => { - let cstr = cstr_atom.as_str(); - Ok(cstr.chars().map(|c| char_as_cell!(c)).collect()) - } - */ _ => { let err = self.type_error(ValidType::List, value); Err(self.error_form(err, stub_gen())) @@ -1372,7 +1221,7 @@ impl MachineState { for addr in addrs { let addr = self.store(self.deref(addr)); - match Number::try_from(addr) { + match Number::try_from((addr, &self.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => { if let Ok(b) = u8::try_from(n.get_num()) { bytes.push(b) diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index a372e0af..b7201b71 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -56,6 +56,7 @@ impl MockWAM { let mut printer = HCPrinter::new( &mut self.machine_st.heap, &mut self.machine_st.stack, + &mut self.machine_st.arena, &self.op_dir, PrinterOutputter::new(), term_write_result.heap_loc, diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 4c987373..fb336248 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -208,8 +208,8 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) { #[inline] pub(crate) fn get_structure_index(value: HeapCellValue) -> Option { read_heap_cell!(value, - (HeapCellValueTag::CodeIndex, ip) => { - return Some(ip); + (HeapCellValueTag::CodeIndexOffset, offset) => { + return Some(CodeIndex::from(offset)); } _ => { } @@ -242,7 +242,7 @@ impl Machine { } /// Runs the predicate `key` in `module_name` until completion. - /// Siltently ignores failure, thrown errors and choice points. + /// Silently ignores failure, thrown errors and choice points. /// /// Consider using [`Machine::run_query`] if you wish to handle /// predicates that may fail, leave a choice point or throw. @@ -252,8 +252,10 @@ impl Machine { key: PredicateKey, ) -> std::process::ExitCode { if let Some(module) = self.indices.modules.get(&module_name) { - if let Some(code_index) = module.code_dir.get(&key) { - let p = code_index.local().unwrap(); + if let Some(code_idx) = module.code_dir.get(&key) { + let index_ptr = self.machine_st.arena.code_index_tbl.lookup(code_idx.into()); + let p = index_ptr.local().unwrap(); + // Leave a halting choice point to backtrack to in case the predicate fails or throws. self.allocate_stub_choice_point(); @@ -324,8 +326,9 @@ impl Machine { self.load_file(path_buf.to_str().unwrap(), stream); if let Some(module) = self.indices.modules.get(&atom!("$atts")) { - if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) { - self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap(); + if let Some(code_idx) = module.code_dir.get(&(atom!("driver"), 2)) { + let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(code_idx.into()); + self.machine_st.attr_var_init.verify_attrs_loc = index_ptr.local().unwrap(); } } } @@ -339,13 +342,16 @@ impl Machine { for arity in 1..66 { let key = (atom!("call"), arity); - match loader.code_dir.get(&key) { + match loader.code_dir.get(&key).cloned() { Some(src_code_index) => { - let target_code_index = target_code_dir - .entry(key) - .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)); + let code_index_tbl = &mut arena.code_index_tbl; - target_code_index.set(src_code_index.get()); + let target_code_index = target_code_dir.entry(key).or_insert_with(|| { + CodeIndex::new(IndexPtr::undefined(), code_index_tbl) + }); + + let src_code_ptr = *code_index_tbl.lookup(src_code_index.into()); + target_code_index.set(code_index_tbl, src_code_ptr); } None => { unreachable!(); @@ -454,7 +460,7 @@ impl Machine { key, CodeIndex::new( IndexPtr::index(p + impls_offset), - &mut self.machine_st.arena, + &mut self.machine_st.arena.code_index_tbl, ), ); } @@ -535,37 +541,8 @@ impl Machine { if cell.is_var() { offset += 1; - /* - } else if lit.get_tag() == HeapCellValueTag::CStr { - read_heap_cell!(cell, - (HeapCellValueTag::CStr) => { - if cell == lit { - offset += 1; - } else { - return false; - } - } - (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { - offset += 1; - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) - .get_name_and_arity(); - - if name == atom!(".") && arity == 2 { - offset += 1; - } else { - return false; - } - } - _ => { - return false; - } - ); - */ } else { unify!(self.machine_st, cell, lit); - // self.machine_st.write_literal_to_var(cell, lit); if self.machine_st.fail { self.machine_st.fail = false; @@ -1068,13 +1045,15 @@ impl Machine { if module_name == atom!("user") { if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { - self.try_call(name, arity, idx.get()) + let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + self.try_call(name, arity, index_ptr) } else { Err(self.machine_st.throw_undefined_error(name, arity)) } } else if let Some(module) = self.indices.modules.get(&module_name) { if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() { - self.try_call(name, arity, idx.get()) + let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + self.try_call(name, arity, index_ptr) } else { self.undefined_procedure(name, arity) } @@ -1098,13 +1077,15 @@ impl Machine { if module_name == atom!("user") { if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { - self.try_execute(name, arity, idx.get()) + let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + self.try_execute(name, arity, index_ptr) } else { self.undefined_procedure(name, arity) } } else if let Some(module) = self.indices.modules.get(&module_name) { if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() { - self.try_execute(name, arity, idx.get()) + let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + self.try_execute(name, arity, index_ptr) } else { self.undefined_procedure(name, arity) } @@ -1146,12 +1127,24 @@ impl Machine { let r_c_w_h = self .indices .get_predicate_code_index(r_c_w_h_atom, 0, iso_ext) - .and_then(|item| item.local()) + .and_then(|code_idx| { + self.machine_st + .arena + .code_index_tbl + .lookup(code_idx.into()) + .local() + }) .unwrap(); let r_c_wo_h = self .indices .get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext) - .and_then(|item| item.local()) + .and_then(|code_idx| { + self.machine_st + .arena + .code_index_tbl + .lookup(code_idx.into()) + .local() + }) .unwrap(); (r_c_w_h, r_c_wo_h) }); diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index 9ee332ed..3a043402 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -424,7 +424,7 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( let term = match term { Term::Clause(cell, name, mut terms) => { - if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { + if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() { arg_terms .push(process_term(module_name, Term::Clause(cell, name, terms))); @@ -433,7 +433,10 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( let idx = loader.get_or_insert_qualified_code_index(module_name, key); - terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx))); + terms.push(Term::Literal( + Cell::default(), + Literal::CodeIndexOffset(idx.into()), + )); process_term(module_name, Term::Clause(cell, name, terms)) } Term::Literal(cell, Literal::Atom(name)) => { @@ -444,7 +447,10 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( Term::Clause( cell, name, - vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))], + vec![Term::Literal( + Cell::default(), + Literal::CodeIndexOffset(idx.into()), + )], ), ) } @@ -469,7 +475,7 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( mut terms: Vec, call_policy: CallPolicy, ) -> QueryTerm { - if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { + if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() { // supplementary code vector indices are unnecessary for // root-level clauses. terms.pop(); @@ -504,7 +510,7 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( mut terms: Vec, call_policy: CallPolicy, ) -> QueryTerm { - if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { + if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() { // supplementary code vector indices are unnecessary for // root-level clauses. terms.pop(); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index dc07cb78..94728dce 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -25,6 +25,7 @@ use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::streams::*; use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC}; +use crate::offset_table::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::dashu::Integer; @@ -821,7 +822,7 @@ impl MachineState { let mut max_old = -1i64; if !max_steps.is_var() { - let max_steps = Number::try_from(max_steps); + let max_steps = Number::try_from((max_steps, &self.arena.f64_tbl)); let max_steps_n = match max_steps { Ok(Number::Fixnum(n)) => Some(n.get_num()), @@ -1132,7 +1133,7 @@ impl MachineState { for addr in addrs { let addr = self.store(self.deref(addr)); - match Number::try_from(addr) { + match Number::try_from((addr, &self.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => { if let Ok(n) = u32::try_from(n.get_num()) { if let Some(c) = std::char::from_u32(n) { @@ -1241,7 +1242,13 @@ impl Machine { let mut bp = self .indices .get_predicate_code_index(atom!("$clause"), 2, module_name) - .and_then(|idx| idx.local()) + .and_then(|idx| { + self.machine_st + .arena + .code_index_tbl + .lookup(idx.into()) + .local() + }) .unwrap(); macro_rules! extract_ptr { @@ -1431,7 +1438,7 @@ impl Machine { self.machine_st.error_form(err, stub) })?; - let index_cell = if index_cell_opt.is_some() { + let index_cell_opt = if index_cell_opt.is_some() { index_cell_opt } else { let is_internal_call = name == atom!("$call") && goal_arity > 0; @@ -1469,11 +1476,13 @@ impl Machine { } }; - if let Some(code_index) = index_cell { - if !code_index.as_ptr().is_undefined() { + if let Some(code_idx) = index_cell_opt { + let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(code_idx.into()); + + if !index_ptr.is_undefined() { load_registers(&mut self.machine_st, goal, goal_arity); self.machine_st.neck_cut(); - return call_at_index(self, name, arity, code_index.get()); + return call_at_index(self, name, arity, index_ptr); } } @@ -1653,7 +1662,7 @@ impl Machine { let idx = CodeIndex::new( IndexPtr::index(helper_clause_loc), - &mut self.machine_st.arena, + &mut self.machine_st.arena.code_index_tbl, ); writer.write_with(|section| { @@ -1694,7 +1703,7 @@ impl Machine { let idx_cell = self.machine_st.heap[s.saturating_sub(1)]; - if HeapCellValueTag::CodeIndex == idx_cell.get_tag() { + if HeapCellValueTag::CodeIndexOffset == idx_cell.get_tag() { return true; } } @@ -1846,7 +1855,7 @@ impl Machine { #[inline(always)] pub(crate) fn bind_from_register(&mut self) { let reg = self.deref_register(2); - let n = match Number::try_from(reg) { + let n = match Number::try_from((reg, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), Ok(Number::Integer(n)) => { let value: usize = (&*n).try_into().unwrap(); @@ -2608,7 +2617,7 @@ impl Machine { let addr = match addr { addr if addr.is_var() => addr, - addr => match Number::try_from(addr) { + addr => match Number::try_from((addr, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) => { let result: Result = (&*n).try_into(); if let Ok(value) = result { @@ -2797,7 +2806,7 @@ impl Machine { a2 } _ => { - match Number::try_from(a2) { + match Number::try_from((a2, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) => { let n: u32 = (&*n).try_into().unwrap(); @@ -2864,7 +2873,7 @@ impl Machine { let n = self.deref_register(1); let chs = self.deref_register(2); - let string = match Number::try_from(n) { + let string = match Number::try_from((n, &self.machine_st.arena.f64_tbl)) { Ok(Number::Float(OrderedFloat(n))) => fmt_float(n), Ok(Number::Fixnum(n)) => n.get_num().to_string(), Ok(Number::Integer(n)) => n.to_string(), @@ -2892,7 +2901,7 @@ impl Machine { let n = self.deref_register(1); let chs = self.machine_st.registers[2]; - let string = match Number::try_from(n) { + let string = match Number::try_from((n, &self.machine_st.arena.f64_tbl)) { Ok(Number::Float(OrderedFloat(n))) => { format!("{0:<20?}", n) } @@ -2979,13 +2988,8 @@ impl Machine { debug_assert_eq!(arity, 0); name.as_char().unwrap() } - /* - (HeapCellValueTag::Char, c) => { - c - } - */ _ => { - match Number::try_from(a2) { + match Number::try_from((a2, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) => { let n: u32 = (&*n).try_into().unwrap(); let n = std::char::from_u32(n); @@ -3223,7 +3227,7 @@ impl Machine { let err = self.machine_st.instantiation_error(); Err(self.machine_st.error_form(err, stub_gen())) } else { - match Number::try_from(addr) { + match Number::try_from((addr, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) => { let n: u32 = (&*n).try_into().unwrap(); let n = char::try_from(n); @@ -3370,7 +3374,7 @@ impl Machine { let err = self.machine_st.instantiation_error(); return Err(self.machine_st.error_form(err, stub_gen())); } else { - match Number::try_from(addr) { + match Number::try_from((addr, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) => { let n: u8 = (&*n).try_into().unwrap(); @@ -3449,7 +3453,7 @@ impl Machine { let addr = if addr.is_var() { addr } else { - match Number::try_from(addr) { + match Number::try_from((addr, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(ref n)) if (**n).num_eq(&1_i64) => { fixnum_as_cell!(Fixnum::build_with(-1)) } @@ -3603,7 +3607,7 @@ impl Machine { 3, )?; - let num = match Number::try_from(self.deref_register(2)) { + let num = match Number::try_from((self.deref_register(2), &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match (&*n).try_into() as Result { Ok(u) => u, @@ -3704,7 +3708,7 @@ impl Machine { let addr = if addr.is_var() { addr } else { - match Number::try_from(addr) { + match Number::try_from((addr, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) => { let n: u32 = (&*n).try_into().unwrap(); let n = std::char::from_u32(n); @@ -4040,7 +4044,7 @@ impl Machine { } else { arity_match = |arity_1, arity_2| arity_1 == arity_2; - let arity = match Number::try_from(arity) { + let arity = match Number::try_from((arity, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => Some(n.get_num() as usize), Ok(Number::Integer(n)) => { let value: usize = (&*n).try_into().unwrap(); @@ -4299,7 +4303,10 @@ impl Machine { pub(crate) fn random_integer(&mut self) { let a1 = self.deref_register(1); let a2 = self.deref_register(2); - let value = match (Number::try_from(a1), Number::try_from(a2)) { + let value = match ( + Number::try_from((a1, &self.machine_st.arena.f64_tbl)), + Number::try_from((a2, &self.machine_st.arena.f64_tbl)), + ) { (Ok(Number::Fixnum(lower)), Ok(Number::Fixnum(upper))) => { let (lower, upper) = (lower.get_num(), upper.get_num()); if lower >= upper { @@ -4390,7 +4397,7 @@ impl Machine { let stub_gen = || functor_stub(atom!("length"), 2); let len = self.deref_register(2); - let n = match Number::try_from(len) { + let n = match Number::try_from((len, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => n.get_num() as usize, Ok(Number::Integer(n)) => match (&*n).try_into() as Result { Ok(n) => n, @@ -4581,23 +4588,24 @@ impl Machine { let tls_cert = self.deref_register(4); let content_length_limit = self.deref_register(5); const CONTENT_LENGTH_LIMIT_DEFAULT: u64 = 32768; - let content_length_limit = match Number::try_from(content_length_limit) { - Ok(Number::Fixnum(n)) => { - if n.get_num() >= 0 { - n.get_num() as u64 - } else { - CONTENT_LENGTH_LIMIT_DEFAULT + let content_length_limit = + match Number::try_from((content_length_limit, &self.machine_st.arena.f64_tbl)) { + Ok(Number::Fixnum(n)) => { + if n.get_num() >= 0 { + n.get_num() as u64 + } else { + CONTENT_LENGTH_LIMIT_DEFAULT + } } - } - Ok(Number::Integer(n)) => { - let n: Result = (&*n).try_into(); - match n { - Ok(u) => u, - Err(_) => CONTENT_LENGTH_LIMIT_DEFAULT, + Ok(Number::Integer(n)) => { + let n: Result = (&*n).try_into(); + match n { + Ok(u) => u, + Err(_) => CONTENT_LENGTH_LIMIT_DEFAULT, + } } - } - _ => CONTENT_LENGTH_LIMIT_DEFAULT, - }; + _ => CONTENT_LENGTH_LIMIT_DEFAULT, + }; let ssl_server: Option<(String, String)> = { match self.machine_st.value_to_str_like(tls_key) { @@ -4864,7 +4872,8 @@ impl Machine { pub(crate) fn http_answer(&mut self) -> CallResult { let culprit = self.deref_register(1); let status_code = self.deref_register(2); - let status_code: u16 = match Number::try_from(status_code) { + let status_code: u16 = match Number::try_from((status_code, &self.machine_st.arena.f64_tbl)) + { Ok(Number::Fixnum(n)) => n.get_num() as u16, Ok(Number::Integer(n)) => { let n: Result = (&*n).try_into(); @@ -4994,7 +5003,7 @@ impl Machine { if let Some(function_name) = self.machine_st.value_to_str_like(function_name) { let stub_gen = || functor_stub(atom!("foreign_call"), 3); fn map_arg(machine_st: &mut MachineState, source: HeapCellValue) -> crate::ffi::Value { - match Number::try_from(source) { + match Number::try_from((source, &machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => Value::Int(n.get_num()), Ok(Number::Float(n)) => Value::Float(n.into_inner()), _ => { @@ -5297,7 +5306,7 @@ impl Machine { let priority = self.deref_register(1); let specifier = cell_as_atom_cell!(self.deref_register(2)).get_name(); - let priority = match Number::try_from(priority) { + let priority = match Number::try_from((priority, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) => { let n: u16 = (&*n).try_into().unwrap(); n @@ -5465,7 +5474,7 @@ impl Machine { pub(crate) fn get_attr_var_queue_beyond(&mut self) { let addr = self.deref_register(1); - let b = match Number::try_from(addr) { + let b = match Number::try_from((addr, &self.machine_st.arena.f64_tbl)) { Ok(Number::Integer(n)) => { let value: usize = (&*n).try_into().unwrap(); Some(value) @@ -5892,7 +5901,7 @@ impl Machine { pub(crate) fn halt(&mut self) -> std::process::ExitCode { let code = self.deref_register(1); - let code = match Number::try_from(code) { + let code = match Number::try_from((code, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => u8::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => { let n: u8 = (&*n).try_into().unwrap(); @@ -5929,7 +5938,7 @@ impl Machine { let a1 = self.deref_register(1); let a2 = self.deref_register(2); - let n = match Number::try_from(a2) { + let n = match Number::try_from((a2, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(bp)) => Integer::from(bp.get_num() as usize), Ok(Number::Integer(n)) => (*n).clone(), _ => { @@ -5974,7 +5983,7 @@ impl Machine { let name = cell_as_atom!(self.deref_register(2)); let a3 = self.deref_register(3); - let arity = match Number::try_from(a3) { + let arity = match Number::try_from((a3, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => n.get_num() as usize, Ok(Number::Integer(n)) => { let result = (&*n).try_into(); @@ -5992,7 +6001,14 @@ impl Machine { self.indices .get_predicate_code_index(name, arity, module_name) - .map(|index| index.local().is_some()) + .map(|idx| { + self.machine_st + .arena + .code_index_tbl + .lookup(idx.into()) + .local() + .is_some() + }) .unwrap_or(false) } @@ -6014,7 +6030,10 @@ impl Machine { arity, module_name, ) - .map(|index| index.get()) + .map(|idx| *self.machine_st + .arena + .code_index_tbl + .lookup(idx.into())) .unwrap_or(IndexPtr::dynamic_undefined()); !matches!(index.tag(), IndexPtrTag::DynamicUndefined | IndexPtrTag::Undefined) @@ -6031,7 +6050,10 @@ impl Machine { 0, module_name, ) - .map(|index| index.get()) + .map(|idx| *self.machine_st + .arena + .code_index_tbl + .lookup(idx.into())) .unwrap_or(IndexPtr::dynamic_undefined()); !matches!(index.tag(), IndexPtrTag::DynamicUndefined) @@ -6667,7 +6689,7 @@ impl Machine { pub(crate) fn set_seed(&mut self) { let seed = self.deref_register(1); - match Number::try_from(seed) { + match Number::try_from((seed, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => { let n: u64 = Integer::from(n).try_into().unwrap(); let rng: StdRng = SeedableRng::seed_from_u64(n); @@ -6695,7 +6717,7 @@ impl Machine { pub(crate) fn sleep(&mut self) { let time = self.deref_register(1); - let time = match Number::try_from(time) { + let time = match Number::try_from((time, &self.machine_st.arena.f64_tbl)) { Ok(Number::Float(n)) => n.into_inner(), Ok(Number::Fixnum(n)) => n.get_num() as f64, Ok(Number::Integer(n)) => n.to_f64().value(), @@ -6730,7 +6752,7 @@ impl Machine { name } _ => { - AtomTable::build_with(&self.machine_st.atom_tbl, &match Number::try_from(port) { + AtomTable::build_with(&self.machine_st.atom_tbl, &match Number::try_from((port, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => n.get_num().to_string(), Ok(Number::Integer(n)) => n.to_string(), _ => { @@ -6829,7 +6851,7 @@ impl Machine { let port = if port.is_var() { String::from("0") } else { - match Number::try_from(port) { + match Number::try_from((port, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => n.get_num().to_string(), Ok(Number::Integer(n)) => n.to_string(), _ => { @@ -7107,7 +7129,7 @@ impl Machine { let position = self.deref_register(2); - let position = match Number::try_from(position) { + let position = match Number::try_from((position, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => n.get_num() as u64, Ok(Number::Integer(n)) => { let n: Result = (&*n).try_into(); @@ -7426,7 +7448,7 @@ impl Machine { let name = cell_as_atom!(self.deref_register(2)); let arity = self.deref_register(3); - let arity = match Number::try_from(arity) { + let arity = match Number::try_from((arity, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => n.get_num() as usize, Ok(Number::Integer(n)) => { let value: usize = (&*n).try_into().unwrap(); @@ -7454,22 +7476,23 @@ impl Machine { }, }; - let first_idx = match first_idx { - Some(idx) if idx.local().is_some() => { - if let Some(idx) = idx.local() { - idx - } else { - unreachable!() - } - } - _ => { - let stub = functor_stub(name, arity); - let err = self - .machine_st - .existence_error(ExistenceError::Procedure(name, arity)); + let first_idx = first_idx.and_then(|first_idx| { + self.machine_st + .arena + .code_index_tbl + .lookup(first_idx.into()) + .local() + }); - return Err(self.machine_st.error_form(err, stub)); - } + let first_idx = if let Some(idx) = first_idx { + idx + } else { + let stub = functor_stub(name, arity); + let err = self + .machine_st + .existence_error(ExistenceError::Procedure(name, arity)); + + return Err(self.machine_st.error_form(err, stub)); }; let listing = @@ -7484,7 +7507,7 @@ impl Machine { #[inline(always)] pub(crate) fn inlined_instructions(&mut self) { let index_ptr = self.deref_register(1); - let index_ptr = match Number::try_from(index_ptr) { + let index_ptr = match Number::try_from((index_ptr, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => n.get_num() as usize, Ok(Number::Integer(n)) => { let value: usize = (&*n).try_into().unwrap(); @@ -7843,7 +7866,7 @@ impl Machine { let length = self.deref_register(6); - let length = match Number::try_from(length) { + let length = match Number::try_from((length, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match (&*n).try_into() as Result { Ok(u) => u, @@ -7909,7 +7932,7 @@ impl Machine { let iterations = self.deref_register(3); - let iterations = match Number::try_from(iterations) { + let iterations = match Number::try_from((iterations, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => { let n: Result = (&*n).try_into(); @@ -8555,7 +8578,10 @@ impl Machine { #[inline(always)] pub(crate) fn pop_count(&mut self) { let number = self.deref_register(1); - let pop_count = integer_as_cell!(match Number::try_from(number) { + let pop_count = integer_as_cell!(match Number::try_from(( + number, + &self.machine_st.arena.f64_tbl + )) { Ok(Number::Fixnum(n)) => { Number::Fixnum(Fixnum::build_with(n.get_num().count_ones())) } diff --git a/src/machine/unify.rs b/src/machine/unify.rs index fdc996a0..6d3bc3ad 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -216,7 +216,9 @@ pub(crate) trait Unifier: DerefMut { return; } - match Number::try_from(value) { + let machine_st = self.deref(); + + match Number::try_from((value, &machine_st.arena.f64_tbl)) { Ok(n2) => match n2 { Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {} Number::Integer(n2) if (*n2).num_eq(&n1.get_num()) => {} @@ -237,7 +239,9 @@ pub(crate) trait Unifier: DerefMut { return; } - match Number::try_from(value) { + let machine_st = self.deref(); + + match Number::try_from((value, &machine_st.arena.f64_tbl)) { Ok(n2) => match n2 { Number::Fixnum(n2) if (*n1).num_eq(&n2.get_num()) => {} Number::Integer(n2) if (*n1).num_eq(&*n2) => {} @@ -258,7 +262,9 @@ pub(crate) trait Unifier: DerefMut { return; } - match Number::try_from(value) { + let machine_st = self.deref_mut(); + + match Number::try_from((value, &machine_st.arena.f64_tbl)) { Ok(n2) => match n2 { Number::Fixnum(n2) if (*n1).num_eq(&Integer::from(n2.get_num())) => {} Number::Integer(n2) if (*n1).num_eq(&*n2) => {} @@ -273,14 +279,19 @@ pub(crate) trait Unifier: DerefMut { } } - fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) { + fn unify_f64(&mut self, f1: F64Offset, value: HeapCellValue) { if let Some(r) = value.as_var() { Self::bind(self, r, HeapCellValue::from(f1)); return; } read_heap_cell!(value, - (HeapCellValueTag::F64, f2) => { + (HeapCellValueTag::F64Offset, f2) => { + let machine_st = self.deref_mut(); + + let f1 = machine_st.arena.f64_tbl.lookup(f1); + let f2 = machine_st.arena.f64_tbl.lookup(f2.into()); + self.fail = **f1 != **f2; } _ => { @@ -414,17 +425,12 @@ pub(crate) trait Unifier: DerefMut { tabu_list.insert((d1, d2)); } } - (HeapCellValueTag::F64, f1) => { + (HeapCellValueTag::F64Offset, f1) => { Self::unify_f64(self, f1, d2); } (HeapCellValueTag::Fixnum, n1) => { Self::unify_fixnum(self, n1, d2); } - /* - (HeapCellValueTag::Char, c1) => { - Self::unify_char(self, c1, d2); - } - */ (HeapCellValueTag::Cons, ptr_1) => { Self::unify_constant(self, ptr_1, d2); } diff --git a/src/macros.rs b/src/macros.rs index 29e3369f..e301832b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -53,17 +53,17 @@ macro_rules! cell_as_atom_cell { }; } -macro_rules! cell_as_f64_ptr { +macro_rules! cell_as_f64_offset { ($cell:expr) => {{ let offset = $cell.get_value() as usize; - F64Ptr::from_offset(F64Offset::from(offset)) + F64Offset::from(offset) }}; } -macro_rules! cell_as_code_index { +macro_rules! cell_as_code_index_offset { ($cell:expr) => {{ let offset = $cell.get_value() as usize; - CodeIndex::from(CodeIndexOffset::from(offset)) + CodeIndexOffset::from(offset) }}; } @@ -266,13 +266,13 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; - ($cell:ident, F64, $n:ident, $code:expr) => {{ - let $n = cell_as_f64_ptr!($cell); + ($cell:ident, F64Offset, $n:ident, $code:expr) => {{ + let $n = cell_as_f64_offset!($cell); #[allow(unused_braces)] $code }}; - ($cell:ident, CodeIndex, $n:ident, $code:expr) => {{ - let $n = cell_as_code_index!($cell); + ($cell:ident, CodeIndexOffset, $n:ident, $code:expr) => {{ + let $n = cell_as_code_index_offset!($cell); #[allow(unused_braces)] $code }}; @@ -281,26 +281,6 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; - ($cell:ident, PStr, $atom:ident, $code:expr) => {{ - let $atom = cell_as_atom!($cell); - #[allow(unused_braces)] - $code - }}; - ($cell:ident, CStr, $atom:ident, $code:expr) => {{ - let $atom = cell_as_atom!($cell); - #[allow(unused_braces)] - $code - }}; - ($cell:ident, CStr | PStr, $atom:ident, $code:expr) => {{ - let $atom = cell_as_atom!($cell); - #[allow(unused_braces)] - $code - }}; - ($cell:ident, PStr | CStr, $atom:ident, $code:expr) => {{ - let $atom = cell_as_atom!($cell); - #[allow(unused_braces)] - $code - }}; ($cell:ident, Fixnum, $value:ident, $code:expr) => {{ let $value = Fixnum::from_bytes($cell.into_bytes()); #[allow(unused_braces)] @@ -321,11 +301,6 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; - ($cell:ident, Char, $value:ident, $code:expr) => {{ - let $value = unsafe { char::from_u32_unchecked($cell.get_value() as u32) }; - #[allow(unused_braces)] - $code - }}; ($cell:ident, $($tags:tt)|+, $value:ident, $code:expr) => {{ let $value = $cell.get_value() as usize; #[allow(unused_braces)] diff --git a/src/offset_table.rs b/src/offset_table.rs index 7b47b96f..a384cb84 100644 --- a/src/offset_table.rs +++ b/src/offset_table.rs @@ -1,8 +1,6 @@ use std::cell::UnsafeCell; use std::hash::{Hash, Hasher}; use std::ops::{Deref, DerefMut}; -use std::sync::RwLock; -use std::sync::Weak; use std::sync::{Arc, Mutex}; use std::{fmt, mem, ptr}; @@ -23,19 +21,7 @@ const F64_TABLE_ALIGN: usize = 8; const CODE_INDEX_TABLE_INIT_SIZE: usize = 1 << 16; const CODE_INDEX_TABLE_ALIGN: usize = 8; -#[derive(Debug)] -pub struct OffsetTableImpl -where - OffsetTableImpl: RawBlockTraits, -{ - block: Arcu>, GlobalEpochCounterPool>, - update: Mutex<()>, -} - -pub type F64Table = OffsetTableImpl>; -pub type CodeIndexTable = OffsetTableImpl; - -impl RawBlockTraits for F64Table { +impl RawBlockTraits for OrderedFloat { #[inline] fn init_size() -> usize { F64_TABLE_INIT_SIZE @@ -47,7 +33,7 @@ impl RawBlockTraits for F64Table { } } -impl RawBlockTraits for CodeIndexTable { +impl RawBlockTraits for IndexPtr { #[inline] fn init_size() -> usize { CODE_INDEX_TABLE_INIT_SIZE @@ -59,72 +45,159 @@ impl RawBlockTraits for CodeIndexTable { } } -pub trait OffsetTable: RawBlockTraits { - type Offset: Copy + From + Into; - type Stored; - - fn global_table() -> &'static RwLock>; -} - -impl OffsetTable for F64Table { - type Offset = F64Offset; - type Stored = OrderedFloat; +#[derive(Debug)] +pub struct OffsetTableImpl(InnerOffsetTableImpl); +impl OffsetTableImpl { #[inline(always)] - fn global_table() -> &'static RwLock> { - static GLOBAL_ATOM_TABLE: RwLock> = RwLock::new(Weak::new()); - &GLOBAL_ATOM_TABLE + pub fn new() -> Self { + Self(InnerOffsetTableImpl::Serial(SerialOffsetTable::new())) } } -impl OffsetTable for CodeIndexTable { - type Offset = CodeIndexOffset; - type Stored = IndexPtr; - - #[inline(always)] - fn global_table() -> &'static RwLock> { - static GLOBAL_CODE_INDEX_TABLE: RwLock> = RwLock::new(Weak::new()); - &GLOBAL_CODE_INDEX_TABLE +impl Default for OffsetTableImpl { + fn default() -> Self { + Self::new() } } -impl OffsetTableImpl -where - OffsetTableImpl: OffsetTable, -{ - #[inline] - pub fn new() -> Arc { - let upgraded = Self::global_table().read().unwrap().upgrade(); - // don't inline upgraded, otherwise temporary will be dropped too late in case of None - if let Some(atom_table) = upgraded { - atom_table - } else { - let mut guard = Self::global_table().write().unwrap(); - // try to upgrade again in case we lost the race on the write lock - if let Some(atom_table) = guard.upgrade() { - atom_table - } else { - let table = Arc::new(Self { - block: Arcu::new(RawBlock::new(), GlobalEpochCounterPool), - update: Mutex::new(()), - }); - *guard = Arc::downgrade(&table); - table - } +#[derive(Debug)] +enum InnerOffsetTableImpl { + Serial(SerialOffsetTable), + #[allow(dead_code)] + Concurrent(Arc>), +} + +impl InnerOffsetTableImpl { + #[inline(always)] + fn build_with(&mut self, value: T) -> usize { + match self { + Self::Concurrent(concurrent_tbl) => unsafe { concurrent_tbl.build_with(value) }, + Self::Serial(serial_tbl) => unsafe { serial_tbl.build_with(value) }, } } + #[inline(always)] + fn lookup<'a>(&'a self, offset: usize) -> TablePtr<'a, T> { + match self { + Self::Concurrent(concurrent_tbl) => { + TablePtr(InnerTablePtr::Concurrent(concurrent_tbl.lookup(offset))) + } + Self::Serial(serial_tbl) => unsafe { + TablePtr(InnerTablePtr::Serial(serial_tbl.lookup(offset))) + }, + } + } + + #[inline(always)] + fn lookup_mut<'a>(&'a mut self, offset: usize) -> TablePtrMut<'a, T> { + match self { + Self::Concurrent(concurrent_tbl) => TablePtrMut(InnerTablePtrMut::Concurrent( + concurrent_tbl.lookup_mut(offset), + )), + Self::Serial(serial_tbl) => unsafe { + TablePtrMut(InnerTablePtrMut::Serial(serial_tbl.lookup_mut(offset))) + }, + } + } +} + +pub trait OffsetTable { + type Offset: Copy + Into; + + fn build_with(&mut self, value: T) -> Self::Offset; + fn lookup<'a>(&'a self, offset: Self::Offset) -> TablePtr<'a, T>; + fn lookup_mut<'a>(&'a mut self, offset: Self::Offset) -> TablePtrMut<'a, T>; +} + +impl OffsetTable> for OffsetTableImpl> { + type Offset = F64Offset; + + fn build_with(&mut self, value: OrderedFloat) -> F64Offset { + F64Offset(self.0.build_with(value)) + } + + fn lookup<'a>(&'a self, offset: F64Offset) -> TablePtr<'a, OrderedFloat> { + self.0.lookup(offset.into()) + } + + fn lookup_mut<'a>(&'a mut self, offset: F64Offset) -> TablePtrMut<'a, OrderedFloat> { + self.0.lookup_mut(offset.into()) + } +} + +impl OffsetTable for OffsetTableImpl { + type Offset = CodeIndexOffset; + + fn build_with(&mut self, value: IndexPtr) -> CodeIndexOffset { + CodeIndexOffset(self.0.build_with(value)) + } + + fn lookup<'a>(&'a self, offset: CodeIndexOffset) -> TablePtr<'a, IndexPtr> { + self.0.lookup(offset.into()) + } + + fn lookup_mut<'a>(&'a mut self, offset: CodeIndexOffset) -> TablePtrMut<'a, IndexPtr> { + self.0.lookup_mut(offset.into()) + } +} + +#[derive(Debug)] +struct SerialOffsetTable { + block: RawBlock, +} + +impl SerialOffsetTable { + #[inline] + fn new() -> Self { + Self { + block: RawBlock::new(), + } + } + + unsafe fn build_with(&mut self, value: T) -> usize { + let mut ptr; + + loop { + ptr = self.block.alloc(size_of::()); + + if ptr.is_null() { + let new_block = self.block.grow_new().unwrap(); + self.block = new_block; + } else { + break; + } + } + + ptr::write(ptr as *mut T, value); + ptr.addr() - self.block.base.addr() + } + + #[inline] + unsafe fn lookup(&self, offset: usize) -> &T { + &*self.block.base.add(offset).cast::() + } + + #[inline] + unsafe fn lookup_mut(&mut self, offset: usize) -> &mut T { + &mut *self.block.base.add(offset).cast::().cast_mut() + } +} + +#[derive(Debug)] +pub struct ConcurrentOffsetTable { + block: Arcu, GlobalEpochCounterPool>, + update: Mutex<()>, +} + +impl ConcurrentOffsetTable { #[allow(clippy::missing_safety_doc)] - pub unsafe fn build_with( - &self, - value: as OffsetTable>::Stored, - ) -> as OffsetTable>::Offset { + unsafe fn build_with(&self, value: T) -> usize { let update_guard = self.update.lock(); // we don't have an index table for lookups as AtomTable does so // just get the epoch after we take the upgrade lock let mut block_epoch = self.block.read(); - let mut ptr; loop { @@ -141,8 +214,7 @@ where ptr::write(ptr as *mut T, value); - let value = - as OffsetTable>::Offset::from(ptr.addr() - block_epoch.base.addr()); + let value = ptr.addr() - block_epoch.base.addr(); // AtomTable would have to update the index table at this point // explicit drop to ensure we don't accidentally drop it early @@ -151,17 +223,20 @@ where value } - pub fn lookup(offset: ::Offset) -> RcuRef, UnsafeCell> { - let table = Self::global_table() - .read() - .unwrap() - .upgrade() - .expect("We should only be looking up entries when there is a table"); + #[inline] + fn lookup(&self, offset: usize) -> RcuRef, T> { + RcuRef::try_map(self.block.read(), |raw_block| unsafe { + raw_block.base.add(offset).cast::().as_ref() + }) + .expect("The offset should result in a non-null pointer") + } - RcuRef::try_map(table.block.read(), |raw_block| unsafe { + #[inline] + fn lookup_mut(&self, offset: usize) -> RcuRef, UnsafeCell> { + RcuRef::try_map(self.block.read(), |raw_block| unsafe { raw_block .base - .add(offset.into()) + .add(offset) .cast_mut() .cast::>() .as_ref() @@ -170,109 +245,8 @@ where } } -#[derive(Debug)] -pub struct TablePtr(RcuRef>, UnsafeCell>) -where - OffsetTableImpl: RawBlockTraits; - -pub type CodeIndexPtr = TablePtr; -pub type F64Ptr = TablePtr>; - -impl Clone for TablePtr -where - OffsetTableImpl: RawBlockTraits, -{ - fn clone(&self) -> Self { - Self(RcuRef::clone(&self.0)) - } -} - -impl PartialEq for TablePtr -where - OffsetTableImpl: RawBlockTraits, -{ - fn eq(&self, other: &TablePtr) -> bool { - RcuRef::ptr_eq(&self.0, &other.0) || self.deref() == other.deref() - } -} - -impl Eq for TablePtr where OffsetTableImpl: RawBlockTraits {} - -impl PartialOrd for TablePtr -where - OffsetTableImpl: RawBlockTraits, -{ - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for TablePtr -where - OffsetTableImpl: RawBlockTraits, -{ - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - (**self).cmp(&**other) - } -} - -impl Hash for TablePtr -where - OffsetTableImpl: RawBlockTraits, -{ - #[inline(always)] - fn hash(&self, hasher: &mut H) { - (self as &T).hash(hasher) - } -} - -impl fmt::Display for TablePtr -where - OffsetTableImpl: RawBlockTraits, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self as &T) - } -} - -impl Deref for TablePtr -where - OffsetTableImpl: RawBlockTraits, -{ - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - unsafe { self.0.get().as_ref().unwrap() } - } -} - -impl DerefMut for TablePtr -where - OffsetTableImpl: RawBlockTraits, -{ - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.0.get().as_mut().unwrap() } - } -} - -impl TablePtr -where - OffsetTableImpl: OffsetTable, -{ - #[inline(always)] - pub fn from_offset(offset: as OffsetTable>::Offset) -> Self { - Self(OffsetTableImpl::::lookup(offset)) - } - - #[inline(always)] - pub fn as_offset(&self) -> as OffsetTable>::Offset { - as OffsetTable>::Offset::from( - self.0.get().addr() - RcuRef::get_root(&self.0).base.addr(), - ) - } -} +pub type F64Table = OffsetTableImpl>; +pub type CodeIndexTable = OffsetTableImpl; #[derive(Clone, Copy, Debug)] pub struct F64Offset(usize); @@ -284,10 +258,9 @@ impl From for F64Offset { } } -impl Into for F64Offset { - #[inline(always)] - fn into(self: Self) -> usize { - self.0 +impl From for usize { + fn from(val: F64Offset) -> Self { + val.0 } } @@ -301,57 +274,71 @@ impl From for CodeIndexOffset { } } -impl Into for CodeIndexOffset { +impl From for usize { #[inline(always)] - fn into(self: Self) -> usize { - self.0 + fn from(val: CodeIndexOffset) -> Self { + val.0 } } impl CodeIndexOffset { - #[inline(always)] - pub fn from_ptr(ptr: CodeIndexPtr) -> Self { - ptr.as_offset() - } - - #[inline(always)] - pub fn as_ptr(self) -> CodeIndexPtr { - CodeIndexPtr::from_offset(self) - } - #[inline(always)] pub fn to_u64(self) -> u64 { self.0 as u64 } } -impl PartialEq for CodeIndexOffset { - #[inline(always)] - fn eq(&self, other: &CodeIndexOffset) -> bool { - self.as_ptr() == other.as_ptr() +#[derive(Debug)] +pub struct TablePtr<'a, T: RawBlockTraits>(InnerTablePtr<'a, T>); + +#[derive(Debug)] +enum InnerTablePtr<'a, T: RawBlockTraits> { + Concurrent(RcuRef, T>), + Serial(&'a T), +} + +impl PartialEq for TablePtr<'_, T> { + fn eq(&self, other: &TablePtr<'_, T>) -> bool { + self.deref() == other.deref() } } -impl Eq for CodeIndexOffset {} +impl Eq for TablePtr<'_, T> {} -impl PartialOrd for CodeIndexOffset { - #[inline(always)] +impl PartialOrd for TablePtr<'_, T> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for CodeIndexOffset { - #[inline(always)] +impl Ord for TablePtr<'_, T> { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.as_ptr().cmp(&other.as_ptr()) + (**self).cmp(&**other) } } -impl Hash for CodeIndexOffset { +impl Hash for TablePtr<'_, T> { #[inline(always)] fn hash(&self, hasher: &mut H) { - self.as_ptr().hash(hasher) + (self as &T).hash(hasher) + } +} + +impl fmt::Display for TablePtr<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self as &T) + } +} + +impl Deref for TablePtr<'_, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + match &self.0 { + InnerTablePtr::Concurrent(rcu_ref) => rcu_ref, + InnerTablePtr::Serial(ref_mut) => ref_mut, + } } } @@ -361,67 +348,103 @@ impl fmt::Display for CodeIndexOffset { } } -impl CodeIndexPtr { - #[inline] - pub fn set(&self, val: IndexPtr) { - unsafe { *self.0.get() = val }; - } - - #[inline] - pub fn replace(&self, val: IndexPtr) -> IndexPtr { - unsafe { self.0.get().replace(val) } - } -} - impl F64Offset { - #[inline(always)] - pub fn from_ptr(ptr: F64Ptr) -> Self { - ptr.as_offset() - } - - #[inline(always)] - pub fn as_ptr(self) -> F64Ptr { - F64Ptr::from_offset(self) - } - #[inline(always)] pub fn to_u64(self) -> u64 { self.0 as u64 } } -impl PartialEq for F64Offset { - #[inline(always)] - fn eq(&self, other: &F64Offset) -> bool { - self.as_ptr() == other.as_ptr() - } -} - -impl Eq for F64Offset {} - -impl PartialOrd for F64Offset { - #[inline(always)] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for F64Offset { - #[inline(always)] - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.as_ptr().cmp(&other.as_ptr()) - } -} - -impl Hash for F64Offset { - #[inline(always)] - fn hash(&self, hasher: &mut H) { - self.as_ptr().hash(hasher) - } -} - impl fmt::Display for F64Offset { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "F64Offset({})", self.0) } } + +#[derive(Debug)] +pub struct TablePtrMut<'a, T: RawBlockTraits>(InnerTablePtrMut<'a, T>); + +#[derive(Debug)] +enum InnerTablePtrMut<'a, T: RawBlockTraits> { + Concurrent(RcuRef, UnsafeCell>), + Serial(&'a mut T), +} + +impl PartialEq for TablePtrMut<'_, T> { + fn eq(&self, other: &TablePtrMut<'_, T>) -> bool { + self.deref() == other.deref() + } +} + +impl Eq for TablePtrMut<'_, T> {} + +impl PartialOrd for TablePtrMut<'_, T> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for TablePtrMut<'_, T> { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + (**self).cmp(&**other) + } +} + +impl Hash for TablePtrMut<'_, T> { + #[inline(always)] + fn hash(&self, hasher: &mut H) { + (self as &T).hash(hasher) + } +} + +impl fmt::Display for TablePtrMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self as &T) + } +} + +impl Deref for TablePtrMut<'_, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + match &self.0 { + InnerTablePtrMut::Concurrent(rcu_ref) => unsafe { rcu_ref.get().as_ref().unwrap() }, + InnerTablePtrMut::Serial(ref_mut) => ref_mut, + } + } +} + +impl DerefMut for TablePtrMut<'_, T> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + match &mut self.0 { + InnerTablePtrMut::Concurrent(rcu_ref) => unsafe { + &mut *rcu_ref.get().as_mut().unwrap() + }, + InnerTablePtrMut::Serial(ref_mut) => ref_mut, + } + } +} + +impl TablePtrMut<'_, IndexPtr> { + #[inline] + pub fn set(&mut self, val: IndexPtr) { + match &mut self.0 { + InnerTablePtrMut::Concurrent(rcu_ref) => unsafe { + *rcu_ref.get() = val; + }, + InnerTablePtrMut::Serial(ref_mut) => { + **ref_mut = val; + } + } + } + + #[inline] + pub fn replace(&mut self, val: IndexPtr) -> IndexPtr { + match &mut self.0 { + InnerTablePtrMut::Concurrent(rcu_ref) => unsafe { rcu_ref.get().replace(val) }, + InnerTablePtrMut::Serial(ref_mut) => mem::replace(*ref_mut, val), + } + } +} diff --git a/src/parser/ast.rs b/src/parser/ast.rs index d67d97ce..4fc10e05 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -2,7 +2,6 @@ use crate::arena::*; use crate::atom_table::*; -use crate::machine::machine_indices::CodeIndex; use crate::offset_table::*; use crate::parser::char_reader::*; use crate::types::HeapCellValueTag; @@ -698,17 +697,18 @@ impl Not for Fixnum { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone)] pub enum Literal { Atom(Atom), - CodeIndex(CodeIndex), + CodeIndexOffset(CodeIndexOffset), Fixnum(Fixnum), Integer(TypedArenaPtr), Rational(TypedArenaPtr), - Float(F64Offset), + F64Offset(F64Offset), } -impl From for Literal { +/* +impl From> for Literal { #[inline(always)] fn from(ptr: F64Ptr) -> Literal { Literal::Float(ptr.as_offset()) @@ -721,14 +721,15 @@ impl fmt::Display for Literal { Literal::Atom(ref atom) => { write!(f, "{}", atom.flat_index()) } - Literal::CodeIndex(i) => write!(f, "{:?}", *i.as_ptr()), + Literal::CodeIndexOffset(i) => write!(f, "{}", *i), Literal::Fixnum(n) => write!(f, "{}", n.get_num()), Literal::Integer(ref n) => write!(f, "{}", n), Literal::Rational(ref n) => write!(f, "{}", n), - Literal::Float(ref n) => write!(f, "{}", *n), + Literal::FloatOffset(ref n) => write!(f, "{}", *n), } } } +*/ impl Literal { pub fn as_atom(&self, atom_tbl: &Arc) -> Option { @@ -874,7 +875,7 @@ impl Term { pub(crate) fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> { if let Term::Clause(_, ref name, ref mut subterms) = term { - if let Some(Term::Literal(_, Literal::CodeIndex(_))) = subterms.last() { + if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = subterms.last() { subterms.pop(); } diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index a1b8cb4a..6584dd32 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -1,7 +1,7 @@ use crate::arena::*; use crate::atom_table::*; pub use crate::machine::machine_state::*; -use crate::offset_table::F64Ptr; +use crate::offset_table::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::dashu::Integer; @@ -30,7 +30,7 @@ struct LayoutInfo { more: bool, } -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub enum Token { Literal(Literal), Var(String), @@ -58,7 +58,7 @@ impl Token { enum Number { BigInt(TypedArenaPtr), Fixnum(Fixnum), - Float(F64Ptr), + Float(F64Offset), } impl Number { @@ -67,7 +67,7 @@ impl Number { match self { Number::BigInt(ibig) => Literal::Integer(ibig), Number::Fixnum(fixnum) => Literal::Fixnum(fixnum), - Number::Float(f) => Literal::Float(f.as_offset()), + Number::Float(f) => Literal::F64Offset(f), } } } @@ -944,8 +944,8 @@ impl<'a, R: CharRead> Lexer<'a, R> { Ok(n) => Ok(Token::Literal(n.to_literal())), Err(_) => { let n = parse_float_lossy(&token_string)?; - Ok(Token::Literal(Literal::Float( - float_alloc!(n, self.machine_st.arena).as_offset(), + Ok(Token::Literal(Literal::F64Offset( + float_alloc!(n, self.machine_st.arena), ))) } }, diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 10702109..b989738d 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -3,12 +3,11 @@ use dashu::Rational; use crate::arena::*; use crate::atom_table::*; +use crate::offset_table::OffsetTable; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::lexer::*; -use ordered_float::OrderedFloat; - use std::cell::Cell; use std::mem; use std::ops::Neg; @@ -963,17 +962,21 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::Literal(Literal::Rational(n)) => { self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r)) } - Token::Literal(Literal::Float(n)) if n.as_ptr().is_infinite() => { + Token::Literal(Literal::F64Offset(n)) if self.lexer.machine_st.arena.f64_tbl.lookup(n).is_infinite() => { return Err(ParserError::InfiniteFloat( self.lexer.line_num, self.lexer.col_num, )); } - Token::Literal(Literal::Float(n)) => self.negate_number( - **n.as_ptr(), - |n, _| -n, - |n, arena| Literal::from(float_alloc!(n, arena)), - ), + Token::Literal(Literal::F64Offset(n)) => { + let n = *self.lexer.machine_st.arena.f64_tbl.lookup(n); + + self.negate_number( + n, + |n, _| -n, + |n, arena| Literal::F64Offset(arena.f64_tbl.build_with(n)), + ) + } Token::Literal(Literal::Fixnum(n)) => { self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n)) } diff --git a/src/types.rs b/src/types.rs index b4765930..60b3b132 100644 --- a/src/types.rs +++ b/src/types.rs @@ -30,9 +30,9 @@ pub enum HeapCellValueTag { PStrLoc = 0b010011, // constants. Cons = 0b0, - F64 = 0b010101, + F64Offset = 0b010101, Fixnum = 0b011001, - CodeIndex = 0b011011, + CodeIndexOffset = 0b011011, Atom = 0b011111, CutPoint = 0b011101, // trail elements. @@ -57,9 +57,9 @@ pub enum HeapCellValueView { PStrLoc = 0b010011, // constants. Cons = 0b0, - F64 = 0b010101, + F64Offset = 0b010101, Fixnum = 0b011001, - CodeIndex = 0b011011, + CodeIndexOffset = 0b011011, Atom = 0b011111, CutPoint = 0b011101, // trail elements. @@ -261,9 +261,9 @@ pub struct HeapCellValue { impl fmt::Debug for HeapCellValue { fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result { match self.get_tag() { - HeapCellValueTag::F64 => f + HeapCellValueTag::F64Offset => f .debug_struct("HeapCellValue") - .field("tag", &HeapCellValueTag::F64) + .field("tag", &HeapCellValueTag::F64Offset) .field("offset", &self.get_value()) .field("m", &self.m()) .field("f", &self.f()) @@ -289,18 +289,6 @@ impl fmt::Debug for HeapCellValue { .field("f", &self.f()) .finish() } - /* - HeapCellValueTag::PStr => { - let (name, _) = cell_as_atom_cell!(self).get_name_and_arity(); - - f.debug_struct("HeapCellValue") - .field("tag", &HeapCellValueTag::PStr) - .field("contents", &name.as_str()) - .field("m", &self.m()) - .field("f", &self.f()) - .finish() - } - */ tag => f .debug_struct("HeapCellValue") .field("tag", &tag) @@ -317,7 +305,7 @@ impl From for HeapCellValue { fn from(literal: Literal) -> Self { match literal { Literal::Atom(name) => atom_as_cell!(name), - Literal::CodeIndex(idx) => HeapCellValue::from(idx), + Literal::CodeIndexOffset(idx) => HeapCellValue::from(idx), Literal::Fixnum(n) => fixnum_as_cell!(n), Literal::Integer(bigint_ptr) => { typed_arena_ptr_as_cell!(bigint_ptr) @@ -325,7 +313,7 @@ impl From for HeapCellValue { Literal::Rational(bigint_ptr) => { typed_arena_ptr_as_cell!(bigint_ptr) } - Literal::Float(f) => HeapCellValue::from(f.as_ptr()), + Literal::F64Offset(f) => HeapCellValue::from(f), } } } @@ -345,11 +333,11 @@ impl TryFrom for Literal { (HeapCellValueTag::Fixnum, n) => { Ok(Literal::Fixnum(n)) } - (HeapCellValueTag::F64, f) => { - Ok(Literal::Float(f.as_offset())) + (HeapCellValueTag::F64Offset, f) => { + Ok(Literal::F64Offset(f)) } - (HeapCellValueTag::CodeIndex, idx) => { - Ok(Literal::CodeIndex(idx)) + (HeapCellValueTag::CodeIndexOffset, idx) => { + Ok(Literal::CodeIndexOffset(idx)) } (HeapCellValueTag::Cons, cons_ptr) => { match_untyped_arena_ptr!(cons_ptr, @@ -381,19 +369,19 @@ where } } -impl From for HeapCellValue { +impl From for HeapCellValue { #[inline] - fn from(f64_ptr: F64Ptr) -> HeapCellValue { - HeapCellValue::build_with(HeapCellValueTag::F64, f64_ptr.as_offset().to_u64()) + fn from(f64_offset: F64Offset) -> HeapCellValue { + HeapCellValue::build_with(HeapCellValueTag::F64Offset, f64_offset.to_u64()) } } -impl From for HeapCellValue { +impl From for HeapCellValue { #[inline] - fn from(code_index_ptr: CodeIndexPtr) -> HeapCellValue { + fn from(code_index_offset: CodeIndexOffset) -> HeapCellValue { HeapCellValue::build_with( - HeapCellValueTag::CodeIndex, - code_index_ptr.as_offset().to_u64(), + HeapCellValueTag::CodeIndexOffset, + code_index_offset.to_u64(), ) } } @@ -472,7 +460,7 @@ impl HeapCellValue { | HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar - | HeapCellValueTag::PStrLoc // | HeapCellValueTag::PStrOffset + | HeapCellValueTag::PStrLoc ) } @@ -496,7 +484,7 @@ impl HeapCellValue { pub fn is_constant(self) -> bool { match self.get_tag() { HeapCellValueTag::Cons - | HeapCellValueTag::F64 + | HeapCellValueTag::F64Offset | HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint => true, HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0, @@ -661,38 +649,52 @@ impl HeapCellValue { } pub fn order_category(self, heap: &Heap) -> Option { - match Number::try_from(self).ok() { - Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => { + read_heap_cell!(self, + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::Integer, _n) => { + Some(TermOrderCategory::Integer) + } + (ArenaHeaderTag::Rational, _n) => { + Some(TermOrderCategory::Integer) + } + _ => { + None + } + ) + } + (HeapCellValueTag::F64Offset) => { + Some(TermOrderCategory::FloatingPoint) + } + (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint) => { Some(TermOrderCategory::Integer) } - Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint), - None => match self.get_tag() { - HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => { - Some(TermOrderCategory::Variable) - } - // HeapCellValueTag::Char => Some(TermOrderCategory::Atom), - HeapCellValueTag::Atom => Some(if cell_as_atom_cell!(self).get_arity() > 0 { + (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { + Some(TermOrderCategory::Variable) + } + (HeapCellValueTag::Atom, (_name, arity)) => { + Some(if arity > 0 { TermOrderCategory::Compound } else { TermOrderCategory::Atom - }), - HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => { - // | HeapCellValueTag::CStr => { + }) + } + (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { + Some(TermOrderCategory::Compound) + } + (HeapCellValueTag::Str, s) => { + let arity = cell_as_atom_cell!(heap[s]).get_arity(); + + if arity == 0 { + Some(TermOrderCategory::Atom) + } else { Some(TermOrderCategory::Compound) } - HeapCellValueTag::Str => { - let value = heap[self.get_value() as usize]; - let arity = cell_as_atom_cell!(value).get_arity(); - - if arity == 0 { - Some(TermOrderCategory::Atom) - } else { - Some(TermOrderCategory::Compound) - } - } - _ => None, - }, - } + } + _ => { + None + } + ) } #[inline(always)] From 2844b5a9582958e782d6c89a1abd1073b116806b Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 20 Jun 2025 23:19:32 -0700 Subject: [PATCH 056/122] synchronize offset table growth with the borrowing of offset pointers --- src/machine/compile.rs | 5 +- src/machine/dispatch.rs | 16 ++-- src/machine/load_state.rs | 5 ++ src/machine/loader.rs | 5 ++ src/machine/mod.rs | 2 +- src/machine/unify.rs | 6 +- src/offset_table.rs | 150 +++++++++++++++++++++++++++++--------- src/raw_block.rs | 2 +- 8 files changed, 141 insertions(+), 50 deletions(-) diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 0ce7b5b8..fcd2364f 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1337,6 +1337,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { settings.is_dynamic(), ); + drop(index_ptr); + let index_ptr = if settings.is_dynamic() { IndexPtr::dynamic_index(code_ptr) } else { @@ -2229,12 +2231,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { if let Some(filename) = self.listing_src_file_name() { if let Some(ref mut module) = self.wam_prelude.indices.modules.get_mut(&filename) { - let code_idx = LS::machine_st(&mut self.payload) + let index_ptr = *LS::machine_st(&mut self.payload) .arena .code_index_tbl .lookup_mut(offset.into()); - let index_ptr = *code_idx; let offset = *module.code_dir.entry(key).or_insert(offset); set_code_index::( diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 20d60c94..59816f17 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -2696,9 +2696,9 @@ impl Machine { } } &Instruction::CallNamed(arity, name, idx) => { - let idx = self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); - try_or_throw!(self.machine_st, self.try_call(name, arity, *idx)); + try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); if self.machine_st.fail { self.machine_st.backtrack(); @@ -2707,9 +2707,9 @@ impl Machine { } } &Instruction::ExecuteNamed(arity, name, idx) => { - let idx = self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); - try_or_throw!(self.machine_st, self.try_execute(name, arity, *idx)); + try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); if self.machine_st.fail { self.machine_st.backtrack(); @@ -2718,18 +2718,18 @@ impl Machine { } } &Instruction::DefaultCallNamed(arity, name, idx) => { - let idx = self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); - try_or_throw!(self.machine_st, self.try_call(name, arity, *idx)); + try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::DefaultExecuteNamed(arity, name, idx) => { - let idx = self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); - try_or_throw!(self.machine_st, self.try_execute(name, arity, *idx)); + try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); if self.machine_st.fail { self.machine_st.backtrack(); diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 123c7be5..931ee273 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -48,6 +48,7 @@ pub(super) fn set_code_index<'a, LS: LoadState<'a>>( } }; + drop(code_idx_ptr); payload.retraction_info.push_record(record); } @@ -507,6 +508,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let code_ptr = code_index_tbl.lookup((*code_index).into()); if !code_ptr.is_undefined() && !code_ptr.is_dynamic_undefined() { + drop(code_ptr); let old_index_ptr = code_index.replace(code_index_tbl, IndexPtr::undefined()); self.payload.retraction_info.push_record( @@ -559,6 +561,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let target_code_ptr = code_index_tbl.lookup(target_code_idx.into()); if module_code_ptr == target_code_ptr { + drop(module_code_ptr); + drop(target_code_ptr); + let old_index_ptr = target_code_idx .replace(code_index_tbl, IndexPtr::undefined()); payload diff --git a/src/machine/loader.rs b/src/machine/loader.rs index cfec0bf6..2a65a1f9 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1228,6 +1228,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .lookup_mut(offset.into()); if code_idx_ptr.is_undefined() { + drop(code_idx_ptr); + set_code_index::( &mut self.payload, &compilation_target, @@ -2159,6 +2161,7 @@ impl Machine { .remove_predicate_skeleton(&compilation_target, &key); let offset = loader.get_or_insert_code_index(key, compilation_target); + let mut code_idx = loader .payload .machine_st @@ -2168,6 +2171,8 @@ impl Machine { code_idx.set(IndexPtr::undefined()); + drop(code_idx); + loader.payload.compilation_target = clause_clause_compilation_target; while let Some(target_pos) = clause_clause_target_poses.pop() { diff --git a/src/machine/mod.rs b/src/machine/mod.rs index fb336248..e9e91f89 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -253,7 +253,7 @@ impl Machine { ) -> std::process::ExitCode { if let Some(module) = self.indices.modules.get(&module_name) { if let Some(code_idx) = module.code_dir.get(&key) { - let index_ptr = self.machine_st.arena.code_index_tbl.lookup(code_idx.into()); + let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(code_idx.into()); let p = index_ptr.local().unwrap(); // Leave a halting choice point to backtrack to in case the predicate fails or throws. diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 6d3bc3ad..252b0f48 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -289,10 +289,10 @@ pub(crate) trait Unifier: DerefMut { (HeapCellValueTag::F64Offset, f2) => { let machine_st = self.deref_mut(); - let f1 = machine_st.arena.f64_tbl.lookup(f1); - let f2 = machine_st.arena.f64_tbl.lookup(f2.into()); + let f1 = *machine_st.arena.f64_tbl.lookup(f1); + let f2 = *machine_st.arena.f64_tbl.lookup(f2.into()); - self.fail = **f1 != **f2; + self.fail = *f1 != *f2; } _ => { self.fail = true; diff --git a/src/offset_table.rs b/src/offset_table.rs index a384cb84..f7d9efdf 100644 --- a/src/offset_table.rs +++ b/src/offset_table.rs @@ -1,7 +1,7 @@ use std::cell::UnsafeCell; use std::hash::{Hash, Hasher}; use std::ops::{Deref, DerefMut}; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, RwLock, RwLockReadGuard}; use std::{fmt, mem, ptr}; use arcu::atomic::Arcu; @@ -48,11 +48,60 @@ impl RawBlockTraits for IndexPtr { #[derive(Debug)] pub struct OffsetTableImpl(InnerOffsetTableImpl); +impl From>> for OffsetTableImpl { + #[inline] + fn from(value: Arc>) -> Self { + OffsetTableImpl(InnerOffsetTableImpl::Concurrent(value)) + } +} + impl OffsetTableImpl { #[inline(always)] pub fn new() -> Self { Self(InnerOffsetTableImpl::Serial(SerialOffsetTable::new())) } + + #[must_use = "the returned concurrent table must be absorbed into the owned OffsetTable"] + pub fn single_to_concurrent(&mut self) -> Arc> { + match &mut self.0 { + InnerOffsetTableImpl::Serial(serial_tbl) => { + let empty_serial_tbl = SerialOffsetTable { + block: RawBlock::empty_block(), + }; + + let serial_tbl = mem::replace(serial_tbl, empty_serial_tbl); + let block = Arcu::new(serial_tbl.block, GlobalEpochCounterPool); + + let growth_lock = RwLock::new(()); + let concurrent_tbl = Arc::new(ConcurrentOffsetTable { block, growth_lock }); + + self.0 = InnerOffsetTableImpl::Concurrent(concurrent_tbl.clone()); + + concurrent_tbl + } + InnerOffsetTableImpl::Concurrent(concurrent_tbl) => concurrent_tbl.clone(), + } + } + + #[must_use = "the transition to a single-threaded offset table may fail if the concurrent table is held from multiple places"] + pub fn concurrent_to_single(&mut self) -> Result<(), ()> { + match &mut self.0 { + InnerOffsetTableImpl::Serial(_serial_tbl) => Ok(()), + InnerOffsetTableImpl::Concurrent(concurrent_tbl) => { + let lock_guard = concurrent_tbl.growth_lock.write().unwrap(); + let raw_block = concurrent_tbl.block.replace(RawBlock::empty_block()); + + match Arc::try_unwrap(raw_block) { + Ok(block) => { + drop(lock_guard); + self.0 = InnerOffsetTableImpl::Serial(SerialOffsetTable { block }); + Ok(()) + } + Err(_) => Err(()), + } + } + } + } } impl Default for OffsetTableImpl { @@ -61,6 +110,17 @@ impl Default for OffsetTableImpl { } } +#[derive(Debug)] +struct SerialOffsetTable { + block: RawBlock, +} + +#[derive(Debug)] +pub struct ConcurrentOffsetTable { + block: Arcu, GlobalEpochCounterPool>, + growth_lock: RwLock<()>, +} + #[derive(Debug)] enum InnerOffsetTableImpl { Serial(SerialOffsetTable), @@ -80,9 +140,13 @@ impl InnerOffsetTableImpl { #[inline(always)] fn lookup<'a>(&'a self, offset: usize) -> TablePtr<'a, T> { match self { - Self::Concurrent(concurrent_tbl) => { - TablePtr(InnerTablePtr::Concurrent(concurrent_tbl.lookup(offset))) - } + Self::Concurrent(concurrent_tbl) => TablePtr({ + let (rcu_ref, guard_lock) = concurrent_tbl.lookup(offset); + InnerTablePtr::Concurrent { + rcu_ref, + guard_lock, + } + }), Self::Serial(serial_tbl) => unsafe { TablePtr(InnerTablePtr::Serial(serial_tbl.lookup(offset))) }, @@ -92,12 +156,18 @@ impl InnerOffsetTableImpl { #[inline(always)] fn lookup_mut<'a>(&'a mut self, offset: usize) -> TablePtrMut<'a, T> { match self { - Self::Concurrent(concurrent_tbl) => TablePtrMut(InnerTablePtrMut::Concurrent( - concurrent_tbl.lookup_mut(offset), - )), - Self::Serial(serial_tbl) => unsafe { - TablePtrMut(InnerTablePtrMut::Serial(serial_tbl.lookup_mut(offset))) - }, + InnerOffsetTableImpl::Concurrent(concurrent_tbl) => TablePtrMut({ + let (rcu_ref, guard_lock) = concurrent_tbl.lookup_mut(offset); + InnerTablePtrMut::Concurrent { + rcu_ref, + guard_lock, + } + }), + InnerOffsetTableImpl::Serial(serial_tbl) => { + TablePtrMut(InnerTablePtrMut::Serial(unsafe { + serial_tbl.lookup_mut(offset) + })) + } } } } @@ -142,11 +212,6 @@ impl OffsetTable for OffsetTableImpl { } } -#[derive(Debug)] -struct SerialOffsetTable { - block: RawBlock, -} - impl SerialOffsetTable { #[inline] fn new() -> Self { @@ -184,16 +249,10 @@ impl SerialOffsetTable { } } -#[derive(Debug)] -pub struct ConcurrentOffsetTable { - block: Arcu, GlobalEpochCounterPool>, - update: Mutex<()>, -} - impl ConcurrentOffsetTable { #[allow(clippy::missing_safety_doc)] unsafe fn build_with(&self, value: T) -> usize { - let update_guard = self.update.lock(); + let update_guard = self.growth_lock.write().unwrap(); // we don't have an index table for lookups as AtomTable does so // just get the epoch after we take the upgrade lock @@ -224,16 +283,25 @@ impl ConcurrentOffsetTable { } #[inline] - fn lookup(&self, offset: usize) -> RcuRef, T> { - RcuRef::try_map(self.block.read(), |raw_block| unsafe { + fn lookup<'a>(&'a self, offset: usize) -> (RcuRef, T>, RwLockReadGuard<'a, ()>) { + let growth_lock_guard = self.growth_lock.read().unwrap(); + + let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe { raw_block.base.add(offset).cast::().as_ref() }) - .expect("The offset should result in a non-null pointer") + .expect("The offset should result in a non-null pointer"); + + (rcu_ref, growth_lock_guard) } #[inline] - fn lookup_mut(&self, offset: usize) -> RcuRef, UnsafeCell> { - RcuRef::try_map(self.block.read(), |raw_block| unsafe { + fn lookup_mut<'a>( + &'a self, + offset: usize, + ) -> (RcuRef, UnsafeCell>, RwLockReadGuard<'a, ()>) { + let growth_lock_guard = self.growth_lock.read().unwrap(); + + let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe { raw_block .base .add(offset) @@ -241,7 +309,9 @@ impl ConcurrentOffsetTable { .cast::>() .as_ref() }) - .expect("The offset should result in a non-null pointer") + .expect("The offset should result in a non-null pointer"); + + (rcu_ref, growth_lock_guard) } } @@ -293,7 +363,11 @@ pub struct TablePtr<'a, T: RawBlockTraits>(InnerTablePtr<'a, T>); #[derive(Debug)] enum InnerTablePtr<'a, T: RawBlockTraits> { - Concurrent(RcuRef, T>), + Concurrent { + rcu_ref: RcuRef, T>, + #[allow(dead_code)] + guard_lock: RwLockReadGuard<'a, ()>, + }, Serial(&'a T), } @@ -336,7 +410,7 @@ impl Deref for TablePtr<'_, T> { #[inline] fn deref(&self) -> &Self::Target { match &self.0 { - InnerTablePtr::Concurrent(rcu_ref) => rcu_ref, + InnerTablePtr::Concurrent { rcu_ref, .. } => rcu_ref, InnerTablePtr::Serial(ref_mut) => ref_mut, } } @@ -366,7 +440,11 @@ pub struct TablePtrMut<'a, T: RawBlockTraits>(InnerTablePtrMut<'a, T>); #[derive(Debug)] enum InnerTablePtrMut<'a, T: RawBlockTraits> { - Concurrent(RcuRef, UnsafeCell>), + Concurrent { + rcu_ref: RcuRef, UnsafeCell>, + #[allow(dead_code)] + guard_lock: RwLockReadGuard<'a, ()>, + }, Serial(&'a mut T), } @@ -409,7 +487,9 @@ impl Deref for TablePtrMut<'_, T> { #[inline] fn deref(&self) -> &Self::Target { match &self.0 { - InnerTablePtrMut::Concurrent(rcu_ref) => unsafe { rcu_ref.get().as_ref().unwrap() }, + InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe { + rcu_ref.get().as_ref().unwrap() + }, InnerTablePtrMut::Serial(ref_mut) => ref_mut, } } @@ -419,7 +499,7 @@ impl DerefMut for TablePtrMut<'_, T> { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { match &mut self.0 { - InnerTablePtrMut::Concurrent(rcu_ref) => unsafe { + InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe { &mut *rcu_ref.get().as_mut().unwrap() }, InnerTablePtrMut::Serial(ref_mut) => ref_mut, @@ -431,7 +511,7 @@ impl TablePtrMut<'_, IndexPtr> { #[inline] pub fn set(&mut self, val: IndexPtr) { match &mut self.0 { - InnerTablePtrMut::Concurrent(rcu_ref) => unsafe { + InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe { *rcu_ref.get() = val; }, InnerTablePtrMut::Serial(ref_mut) => { @@ -443,7 +523,7 @@ impl TablePtrMut<'_, IndexPtr> { #[inline] pub fn replace(&mut self, val: IndexPtr) -> IndexPtr { match &mut self.0 { - InnerTablePtrMut::Concurrent(rcu_ref) => unsafe { rcu_ref.get().replace(val) }, + InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe { rcu_ref.get().replace(val) }, InnerTablePtrMut::Serial(ref_mut) => mem::replace(*ref_mut, val), } } diff --git a/src/raw_block.rs b/src/raw_block.rs index 3c39c77d..02bea9f0 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 fn empty_block() -> Self { RawBlock { base: ptr::null(), top: ptr::null(), From 762b63e1f41dff5d6d19b154b528ab58bf1e2f6b Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 24 Jun 2025 21:58:40 -0700 Subject: [PATCH 057/122] use granular hierarchical locks in offset_table.rs --- Cargo.lock | 13 +- Cargo.toml | 1 + src/arena.rs | 11 +- src/arithmetic.rs | 4 +- src/heap_print.rs | 4 +- src/machine/arithmetic_ops.rs | 4 +- src/machine/compile.rs | 10 +- src/machine/dispatch.rs | 23 ++- src/machine/lib_machine/mod.rs | 4 +- src/machine/load_state.rs | 67 +++--- src/machine/loader.rs | 17 +- src/machine/machine_indices.rs | 4 +- src/machine/machine_state_impl.rs | 4 +- src/machine/mod.rs | 38 +++- src/machine/system_calls.rs | 20 +- src/machine/unify.rs | 6 +- src/offset_table.rs | 332 ++++++++++-------------------- src/parser/parser.rs | 4 +- 18 files changed, 233 insertions(+), 333 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 52a3a76a..0feaf573 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1673,9 +1673,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -2011,9 +2011,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -2021,9 +2021,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -2712,6 +2712,7 @@ dependencies = [ "num-order", "ordered-float", "ouroboros", + "parking_lot", "phf", "pprof", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 22609228..3087a3a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,7 @@ ego-tree = "0.10.0" serde_json = "1.0.122" serde = "1.0.204" +parking_lot = "0.12.4" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] crossterm = { version = "0.28.1", optional = true } diff --git a/src/arena.rs b/src/arena.rs index 2be3a9f9..2a3fc8b9 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -570,8 +570,6 @@ const_assert!(mem::size_of::>() == 8); #[cfg(test)] mod tests { - use std::ops::Deref; - use crate::arena::*; use crate::atom_table::*; use crate::machine::mock_wam::*; @@ -590,10 +588,7 @@ mod tests { assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset); assert!(!cell.get_mark_bit()); - assert_eq!( - wam.machine_st.arena.f64_tbl.lookup(fp).deref(), - &OrderedFloat(f) - ); + assert_eq!(wam.machine_st.arena.f64_tbl.get_entry(fp), OrderedFloat(f)); cell.set_mark_bit(true); @@ -601,8 +596,8 @@ mod tests { read_heap_cell!(cell, (HeapCellValueTag::F64Offset, offset) => { - let fp = wam.machine_st.arena.f64_tbl.lookup(offset.into()); - assert_eq!(*fp, OrderedFloat(0f64)) + let fp = wam.machine_st.arena.f64_tbl.get_entry(offset); + assert_eq!(fp, OrderedFloat(0f64)) } _ => { unreachable!() } ); diff --git a/src/arithmetic.rs b/src/arithmetic.rs index a4aad3f8..f7a86569 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -166,7 +166,7 @@ fn push_literal( Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))), Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))), &Literal::F64Offset(offset) => { - let n = *f64_tbl.lookup(offset); + let n = f64_tbl.get_entry(offset); interm.push(ArithmeticTerm::Number(Number::Float(n))); } Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))), @@ -685,7 +685,7 @@ impl TryFrom<(HeapCellValue, &'_ F64Table)> for Number { ) } (HeapCellValueTag::F64Offset, offset) => { - let n = *f64_tbl.lookup(offset.into()); + let n = f64_tbl.get_entry(offset); Ok(Number::Float(n)) } (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => { diff --git a/src/heap_print.rs b/src/heap_print.rs index d45e45a9..9cc3a2d0 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1544,7 +1544,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.pop(); self.state_stack.pop(); - let idx_ptr = self.arena.code_index_tbl.lookup(idx); + let idx_ptr = self.arena.code_index_tbl.get_entry(idx); let offset = if idx_ptr.is_undefined() || idx_ptr.is_dynamic_undefined() { TokenOrRedirect::Atom(atom!("undefined")) @@ -1749,7 +1749,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op); } (HeapCellValueTag::F64Offset, offset) => { - let f = *self.arena.f64_tbl.lookup(offset.into()); + let f = self.arena.f64_tbl.get_entry(offset); self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(f)), &op); } (HeapCellValueTag::PStrLoc) => { diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 8e4c0552..c0c3f2bb 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1389,8 +1389,8 @@ impl MachineState { self.interms.push(Number::Fixnum(n)); } (HeapCellValueTag::F64Offset, offset) => { - let fl = self.arena.f64_tbl.lookup(offset); - self.interms.push(Number::Float(*fl)); + let fl = self.arena.f64_tbl.get_entry(offset); + self.interms.push(Number::Float(fl)); } (HeapCellValueTag::Cons, ptr) => { match_untyped_arena_ptr!(ptr, diff --git a/src/machine/compile.rs b/src/machine/compile.rs index fcd2364f..7dcbee14 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1328,17 +1328,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let index_ptr = LS::machine_st(&mut self.payload) .arena .code_index_tbl - .lookup(code_idx.into()); + .get_entry(code_idx.into()); print_overwrite_warning( &predicates.compilation_target, - *index_ptr, + index_ptr, key, settings.is_dynamic(), ); - drop(index_ptr); - let index_ptr = if settings.is_dynamic() { IndexPtr::dynamic_index(code_ptr) } else { @@ -2231,10 +2229,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { if let Some(filename) = self.listing_src_file_name() { if let Some(ref mut module) = self.wam_prelude.indices.modules.get_mut(&filename) { - let index_ptr = *LS::machine_st(&mut self.payload) + let index_ptr = LS::machine_st(&mut self.payload) .arena .code_index_tbl - .lookup_mut(offset.into()); + .get_entry(offset.into()); let offset = *module.code_dir.entry(key).or_insert(offset); diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 59816f17..2428f7d2 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -547,8 +547,8 @@ impl Machine { // Find the boundaries of the current predicate self.indices.code_dir.sort_by(|_, a, _, b| { - let a = *self.machine_st.arena.code_index_tbl.lookup((*a).into()); - let b = *self.machine_st.arena.code_index_tbl.lookup((*b).into()); + let a = self.machine_st.arena.code_index_tbl.get_entry((*a).into()); + let b = self.machine_st.arena.code_index_tbl.get_entry((*b).into()); a.cmp(&b) }); @@ -557,8 +557,11 @@ impl Machine { .indices .code_dir .binary_search_by_key(&p, |_, x| -> usize { - self.machine_st.arena.code_index_tbl.lookup((*x).into()).p() - as usize + self.machine_st + .arena + .code_index_tbl + .get_entry((*x).into()) + .p() as usize }) .unwrap_or_else(|x| x - 1); @@ -570,7 +573,7 @@ impl Machine { self.machine_st .arena .code_index_tbl - .lookup((*idx.1).into()) + .get_entry((*idx.1).into()) .p() as usize }) .unwrap(); @@ -585,7 +588,7 @@ impl Machine { self.machine_st .arena .code_index_tbl - .lookup((*idx.1).into()) + .get_entry((*idx.1).into()) .p() as usize }) .unwrap_or(self.code.len()); @@ -2696,7 +2699,7 @@ impl Machine { } } &Instruction::CallNamed(arity, name, idx) => { - let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); @@ -2707,7 +2710,7 @@ impl Machine { } } &Instruction::ExecuteNamed(arity, name, idx) => { - let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); @@ -2718,7 +2721,7 @@ impl Machine { } } &Instruction::DefaultCallNamed(arity, name, idx) => { - let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); @@ -2727,7 +2730,7 @@ impl Machine { } } &Instruction::DefaultExecuteNamed(arity, name, idx) => { - let idx = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index dbaac207..a1ba3399 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -278,7 +278,7 @@ impl Term { } } (HeapCellValueTag::F64Offset, offset) => { - let f = *machine.machine_st.arena.f64_tbl.lookup(offset); + let f = machine.machine_st.arena.f64_tbl.get_entry(offset); term_stack.push(Term::Float(f.into())); } (HeapCellValueTag::Fixnum, n) => { @@ -602,7 +602,7 @@ impl Machine { self.machine_st .arena .code_index_tbl - .lookup(offset.into()) + .get_entry(offset.into()) .p() as usize }) .expect("couldn't get code index"); diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 931ee273..40e9a383 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -22,33 +22,30 @@ pub(super) fn set_code_index<'a, LS: LoadState<'a>>( code_idx: CodeIndex, code_ptr: IndexPtr, ) { - let mut code_idx_ptr = LS::machine_st(payload) - .arena - .code_index_tbl - .lookup_mut(code_idx.into()); - - let record = match compilation_target { - CompilationTarget::User => { - if IndexPtrTag::Undefined == code_idx_ptr.tag() { - code_idx_ptr.set(code_ptr); - RetractionRecord::AddedUserPredicate(key) - } else { - let replaced = code_idx_ptr.replace(code_ptr); - RetractionRecord::ReplacedUserPredicate(key, replaced) + let record = LS::machine_st(payload).arena.code_index_tbl.with_entry_mut( + code_idx.into(), + |code_idx_ptr| match compilation_target { + CompilationTarget::User => { + if IndexPtrTag::Undefined == code_idx_ptr.tag() { + *code_idx_ptr = code_ptr; + RetractionRecord::AddedUserPredicate(key) + } else { + let replaced = mem::replace(code_idx_ptr, code_ptr); + RetractionRecord::ReplacedUserPredicate(key, replaced) + } } - } - CompilationTarget::Module(ref module_name) => { - if IndexPtrTag::Undefined == code_idx_ptr.tag() { - code_idx_ptr.set(code_ptr); - RetractionRecord::AddedModulePredicate(*module_name, key) - } else { - let replaced = code_idx_ptr.replace(code_ptr); - RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced) + CompilationTarget::Module(ref module_name) => { + if IndexPtrTag::Undefined == code_idx_ptr.tag() { + *code_idx_ptr = code_ptr; + RetractionRecord::AddedModulePredicate(*module_name, key) + } else { + let replaced = mem::replace(code_idx_ptr, code_ptr); + RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced) + } } - } - }; + }, + ); - drop(code_idx_ptr); payload.retraction_info.push_record(record); } @@ -145,7 +142,7 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>( .entry(key) .or_insert_with(|| CodeIndex::default(code_idx_tbl)); - let src_code_index_ptr = *code_idx_tbl.lookup(src_code_index.into()); + let src_code_index_ptr = code_idx_tbl.get_entry(src_code_index.into()); set_code_index::( payload, @@ -158,7 +155,7 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>( if LS::machine_st(payload) .arena .code_index_tbl - .lookup(src_code_index.into()) + .get_entry(src_code_index.into()) .is_dynamic_undefined() { code_dir.insert(key, src_code_index); @@ -205,7 +202,7 @@ fn import_module_exports_into_module<'a, LS: LoadState<'a>>( if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() { let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl; - let src_code_ptr = *code_index_tbl.lookup(src_code_index.into()); + let src_code_ptr = code_index_tbl.get_entry(src_code_index.into()); let target_code_index = *code_dir .entry(key) .or_insert_with(|| CodeIndex::default(code_index_tbl)); @@ -259,7 +256,7 @@ fn import_qualified_module_exports<'a, LS: LoadState<'a>>( if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() { let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl; - let src_code_ptr = *code_index_tbl.lookup(src_code_index.into()); + let src_code_ptr = code_index_tbl.get_entry(src_code_index.into()); let target_code_index = *wam_prelude.indices.code_dir.entry(key).or_insert_with(|| { CodeIndex::new(IndexPtr::undefined(), code_index_tbl) @@ -320,7 +317,7 @@ fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>( if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() { let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl; - let src_code_ptr = *code_index_tbl.lookup(src_code_index.into()); + let src_code_ptr = code_index_tbl.get_entry(src_code_index.into()); let target_code_index = *code_dir .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl)); @@ -505,10 +502,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl; - let code_ptr = code_index_tbl.lookup((*code_index).into()); + let code_ptr = code_index_tbl.get_entry((*code_index).into()); if !code_ptr.is_undefined() && !code_ptr.is_dynamic_undefined() { - drop(code_ptr); let old_index_ptr = code_index.replace(code_index_tbl, IndexPtr::undefined()); self.payload.retraction_info.push_record( @@ -557,13 +553,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { (Some(module_code_idx), Some(target_code_idx)) => { let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl; - let module_code_ptr = code_index_tbl.lookup(module_code_idx.into()); - let target_code_ptr = code_index_tbl.lookup(target_code_idx.into()); + let module_code_ptr = + code_index_tbl.get_entry(module_code_idx.into()); + let target_code_ptr = + code_index_tbl.get_entry(target_code_idx.into()); if module_code_ptr == target_code_ptr { - drop(module_code_ptr); - drop(target_code_ptr); - let old_index_ptr = target_code_idx .replace(code_index_tbl, IndexPtr::undefined()); payload diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 2a65a1f9..02b8a2b0 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1225,11 +1225,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let code_idx_ptr = LS::machine_st(&mut self.payload) .arena .code_index_tbl - .lookup_mut(offset.into()); + .get_entry(offset.into()); if code_idx_ptr.is_undefined() { - drop(code_idx_ptr); - set_code_index::( &mut self.payload, &compilation_target, @@ -2015,8 +2013,7 @@ impl Machine { .machine_st .arena .code_index_tbl - .lookup(offset.into()) - .tag() + .with_entry(offset.into(), |idx| idx.tag()) }) .unwrap_or(IndexPtrTag::DynamicUndefined); @@ -2162,16 +2159,14 @@ impl Machine { let offset = loader.get_or_insert_code_index(key, compilation_target); - let mut code_idx = loader + loader .payload .machine_st .arena .code_index_tbl - .lookup_mut(offset.into()); - - code_idx.set(IndexPtr::undefined()); - - drop(code_idx); + .with_entry_mut(offset.into(), |code_idx| { + *code_idx = IndexPtr::undefined(); + }); loader.payload.compilation_target = clause_clause_compilation_target; diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 66caba46..4f04c2b1 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -186,12 +186,12 @@ impl CodeIndex { #[inline(always)] pub(crate) fn set(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) { - code_index_tbl.lookup_mut(self.0).set(value); + code_index_tbl.with_entry_mut(self.0, |idx| *idx = value); } #[inline(always)] pub(crate) fn replace(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) -> IndexPtr { - code_index_tbl.lookup_mut(self.0).replace(value) + code_index_tbl.with_entry_mut(self.0, |idx| std::mem::replace(idx, value)) } } diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 385d9a4e..f663656c 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -412,8 +412,8 @@ impl MachineState { let v1 = cell_as_f64_offset!(v1); let v2 = cell_as_f64_offset!(v2); - let v1 = self.arena.f64_tbl.lookup(v1); - let v2 = self.arena.f64_tbl.lookup(v2); + let v1 = self.arena.f64_tbl.get_entry(v1); + let v2 = self.arena.f64_tbl.get_entry(v2); if v1 != v2 { self.pdl.clear(); diff --git a/src/machine/mod.rs b/src/machine/mod.rs index e9e91f89..51ae44e4 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -253,7 +253,11 @@ impl Machine { ) -> std::process::ExitCode { if let Some(module) = self.indices.modules.get(&module_name) { if let Some(code_idx) = module.code_dir.get(&key) { - let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(code_idx.into()); + let index_ptr = self + .machine_st + .arena + .code_index_tbl + .get_entry(code_idx.into()); let p = index_ptr.local().unwrap(); // Leave a halting choice point to backtrack to in case the predicate fails or throws. @@ -327,7 +331,11 @@ impl Machine { if let Some(module) = self.indices.modules.get(&atom!("$atts")) { if let Some(code_idx) = module.code_dir.get(&(atom!("driver"), 2)) { - let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(code_idx.into()); + let index_ptr = self + .machine_st + .arena + .code_index_tbl + .get_entry(code_idx.into()); self.machine_st.attr_var_init.verify_attrs_loc = index_ptr.local().unwrap(); } } @@ -350,7 +358,7 @@ impl Machine { CodeIndex::new(IndexPtr::undefined(), code_index_tbl) }); - let src_code_ptr = *code_index_tbl.lookup(src_code_index.into()); + let src_code_ptr = code_index_tbl.get_entry(src_code_index.into()); target_code_index.set(code_index_tbl, src_code_ptr); } None => { @@ -1045,14 +1053,14 @@ impl Machine { if module_name == atom!("user") { if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { - let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let index_ptr = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); self.try_call(name, arity, index_ptr) } else { Err(self.machine_st.throw_undefined_error(name, arity)) } } else if let Some(module) = self.indices.modules.get(&module_name) { if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() { - let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + let index_ptr = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); self.try_call(name, arity, index_ptr) } else { self.undefined_procedure(name, arity) @@ -1076,15 +1084,23 @@ impl Machine { let (name, arity) = key; if module_name == atom!("user") { - if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { - let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + if let Some(offset) = self.indices.code_dir.get(&(name, arity)).cloned() { + let index_ptr = self + .machine_st + .arena + .code_index_tbl + .get_entry(offset.into()); self.try_execute(name, arity, index_ptr) } else { self.undefined_procedure(name, arity) } } else if let Some(module) = self.indices.modules.get(&module_name) { - if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() { - let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(idx.into()); + if let Some(offset) = module.code_dir.get(&(name, arity)).cloned() { + let index_ptr = self + .machine_st + .arena + .code_index_tbl + .get_entry(offset.into()); self.try_execute(name, arity, index_ptr) } else { self.undefined_procedure(name, arity) @@ -1131,7 +1147,7 @@ impl Machine { self.machine_st .arena .code_index_tbl - .lookup(code_idx.into()) + .get_entry(code_idx.into()) .local() }) .unwrap(); @@ -1142,7 +1158,7 @@ impl Machine { self.machine_st .arena .code_index_tbl - .lookup(code_idx.into()) + .get_entry(code_idx.into()) .local() }) .unwrap(); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 94728dce..24735325 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1246,7 +1246,7 @@ impl Machine { self.machine_st .arena .code_index_tbl - .lookup(idx.into()) + .get_entry(idx.into()) .local() }) .unwrap(); @@ -1477,7 +1477,11 @@ impl Machine { }; if let Some(code_idx) = index_cell_opt { - let index_ptr = *self.machine_st.arena.code_index_tbl.lookup(code_idx.into()); + let index_ptr = self + .machine_st + .arena + .code_index_tbl + .get_entry(code_idx.into()); if !index_ptr.is_undefined() { load_registers(&mut self.machine_st, goal, goal_arity); @@ -6005,7 +6009,7 @@ impl Machine { self.machine_st .arena .code_index_tbl - .lookup(idx.into()) + .get_entry(idx.into()) .local() .is_some() }) @@ -6030,10 +6034,10 @@ impl Machine { arity, module_name, ) - .map(|idx| *self.machine_st + .map(|idx| self.machine_st .arena .code_index_tbl - .lookup(idx.into())) + .get_entry(idx.into())) .unwrap_or(IndexPtr::dynamic_undefined()); !matches!(index.tag(), IndexPtrTag::DynamicUndefined | IndexPtrTag::Undefined) @@ -6050,10 +6054,10 @@ impl Machine { 0, module_name, ) - .map(|idx| *self.machine_st + .map(|idx| self.machine_st .arena .code_index_tbl - .lookup(idx.into())) + .get_entry(idx.into())) .unwrap_or(IndexPtr::dynamic_undefined()); !matches!(index.tag(), IndexPtrTag::DynamicUndefined) @@ -7480,7 +7484,7 @@ impl Machine { self.machine_st .arena .code_index_tbl - .lookup(first_idx.into()) + .get_entry(first_idx.into()) .local() }); diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 252b0f48..6ada6fb1 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -289,10 +289,10 @@ pub(crate) trait Unifier: DerefMut { (HeapCellValueTag::F64Offset, f2) => { let machine_st = self.deref_mut(); - let f1 = *machine_st.arena.f64_tbl.lookup(f1); - let f2 = *machine_st.arena.f64_tbl.lookup(f2.into()); + let f1 = machine_st.arena.f64_tbl.get_entry(f1); + let f2 = machine_st.arena.f64_tbl.get_entry(f2.into()); - self.fail = *f1 != *f2; + self.fail = f1 != f2; } _ => { self.fail = true; diff --git a/src/offset_table.rs b/src/offset_table.rs index f7d9efdf..c2b2ea8b 100644 --- a/src/offset_table.rs +++ b/src/offset_table.rs @@ -1,13 +1,12 @@ use std::cell::UnsafeCell; -use std::hash::{Hash, Hasher}; -use std::ops::{Deref, DerefMut}; -use std::sync::{Arc, RwLock, RwLockReadGuard}; +use std::sync::Arc; use std::{fmt, mem, ptr}; use arcu::atomic::Arcu; use arcu::epoch_counters::GlobalEpochCounterPool; use arcu::rcu_ref::RcuRef; use arcu::Rcu; +use parking_lot::RwLock; use crate::machine::machine_indices::IndexPtr; use crate::raw_block::RawBlock; @@ -55,7 +54,7 @@ impl From>> for OffsetTableImpl< } } -impl OffsetTableImpl { +impl OffsetTableImpl { #[inline(always)] pub fn new() -> Self { Self(InnerOffsetTableImpl::Serial(SerialOffsetTable::new())) @@ -70,10 +69,17 @@ impl OffsetTableImpl { }; let serial_tbl = mem::replace(serial_tbl, empty_serial_tbl); + let num_tbl_entries = serial_tbl.block.size() / size_of::(); let block = Arcu::new(serial_tbl.block, GlobalEpochCounterPool); - let growth_lock = RwLock::new(()); - let concurrent_tbl = Arc::new(ConcurrentOffsetTable { block, growth_lock }); + let offset_locks: Vec> = + (0..num_tbl_entries).map(|_| RwLock::new(())).collect(); + + let concurrent_tbl = Arc::new(ConcurrentOffsetTable { + block, + growth_lock: RwLock::new(()), + offset_locks: RwLock::new(offset_locks), + }); self.0 = InnerOffsetTableImpl::Concurrent(concurrent_tbl.clone()); @@ -88,23 +94,48 @@ impl OffsetTableImpl { match &mut self.0 { InnerOffsetTableImpl::Serial(_serial_tbl) => Ok(()), InnerOffsetTableImpl::Concurrent(concurrent_tbl) => { - let lock_guard = concurrent_tbl.growth_lock.write().unwrap(); - let raw_block = concurrent_tbl.block.replace(RawBlock::empty_block()); + let table_arc = std::mem::replace( + concurrent_tbl, + Arc::new(ConcurrentOffsetTable { + block: Arcu::new(RawBlock::empty_block(), GlobalEpochCounterPool), + growth_lock: RwLock::new(()), + offset_locks: RwLock::new(vec![]), + }), + ); - match Arc::try_unwrap(raw_block) { - Ok(block) => { - drop(lock_guard); - self.0 = InnerOffsetTableImpl::Serial(SerialOffsetTable { block }); + match Arc::try_unwrap(table_arc) { + Ok(table) => { + // this was the only instance of the concurrent table, as such + // at this point no build_with/with_entry{_mut} call can be in-progress/made + + // this shouldn't be able to fail + let raw_block = + Arc::try_unwrap(table.block.replace(RawBlock::empty_block())).unwrap(); + self.0 = + InnerOffsetTableImpl::Serial(SerialOffsetTable { block: raw_block }); Ok(()) } - Err(_) => Err(()), + Err(table_arc) => { + // restore the concurrent_tbl + *concurrent_tbl = table_arc; + Err(()) + } } } } } + + #[inline] + pub fn get_entry(&self, offset: >::Offset) -> T + where + Self: OffsetTable, + T: Copy, + { + self.with_entry(offset, |value| *value) + } } -impl Default for OffsetTableImpl { +impl Default for OffsetTableImpl { fn default() -> Self { Self::new() } @@ -119,6 +150,7 @@ struct SerialOffsetTable { pub struct ConcurrentOffsetTable { block: Arcu, GlobalEpochCounterPool>, growth_lock: RwLock<()>, + offset_locks: RwLock>>, } #[derive(Debug)] @@ -132,42 +164,24 @@ impl InnerOffsetTableImpl { #[inline(always)] fn build_with(&mut self, value: T) -> usize { match self { - Self::Concurrent(concurrent_tbl) => unsafe { concurrent_tbl.build_with(value) }, + Self::Concurrent(concurrent_tbl) => concurrent_tbl.build_with(value), Self::Serial(serial_tbl) => unsafe { serial_tbl.build_with(value) }, } } #[inline(always)] - fn lookup<'a>(&'a self, offset: usize) -> TablePtr<'a, T> { + fn with_entry R>(&self, offset: usize, f: F) -> R { match self { - Self::Concurrent(concurrent_tbl) => TablePtr({ - let (rcu_ref, guard_lock) = concurrent_tbl.lookup(offset); - InnerTablePtr::Concurrent { - rcu_ref, - guard_lock, - } - }), - Self::Serial(serial_tbl) => unsafe { - TablePtr(InnerTablePtr::Serial(serial_tbl.lookup(offset))) - }, + Self::Concurrent(concurrent_tbl) => concurrent_tbl.with_entry(offset, f), + Self::Serial(serial_tbl) => f(unsafe { serial_tbl.lookup(offset) }), } } #[inline(always)] - fn lookup_mut<'a>(&'a mut self, offset: usize) -> TablePtrMut<'a, T> { + fn with_entry_mut R>(&mut self, offset: usize, f: F) -> R { match self { - InnerOffsetTableImpl::Concurrent(concurrent_tbl) => TablePtrMut({ - let (rcu_ref, guard_lock) = concurrent_tbl.lookup_mut(offset); - InnerTablePtrMut::Concurrent { - rcu_ref, - guard_lock, - } - }), - InnerOffsetTableImpl::Serial(serial_tbl) => { - TablePtrMut(InnerTablePtrMut::Serial(unsafe { - serial_tbl.lookup_mut(offset) - })) - } + Self::Concurrent(concurrent_tbl) => concurrent_tbl.with_entry_mut(offset, f), + Self::Serial(serial_tbl) => f(unsafe { serial_tbl.lookup_mut(offset) }), } } } @@ -176,8 +190,9 @@ pub trait OffsetTable { type Offset: Copy + Into; fn build_with(&mut self, value: T) -> Self::Offset; - fn lookup<'a>(&'a self, offset: Self::Offset) -> TablePtr<'a, T>; - fn lookup_mut<'a>(&'a mut self, offset: Self::Offset) -> TablePtrMut<'a, T>; + + fn with_entry R>(&self, offset: Self::Offset, f: F) -> R; + fn with_entry_mut R>(&mut self, offset: Self::Offset, f: F) -> R; } impl OffsetTable> for OffsetTableImpl> { @@ -187,12 +202,18 @@ impl OffsetTable> for OffsetTableImpl> { F64Offset(self.0.build_with(value)) } - fn lookup<'a>(&'a self, offset: F64Offset) -> TablePtr<'a, OrderedFloat> { - self.0.lookup(offset.into()) + #[inline] + fn with_entry) -> R>(&self, offset: F64Offset, f: F) -> R { + self.0.with_entry(offset.into(), f) } - fn lookup_mut<'a>(&'a mut self, offset: F64Offset) -> TablePtrMut<'a, OrderedFloat> { - self.0.lookup_mut(offset.into()) + #[inline] + fn with_entry_mut) -> R>( + &mut self, + offset: F64Offset, + f: F, + ) -> R { + self.0.with_entry_mut(offset.into(), f) } } @@ -203,12 +224,18 @@ impl OffsetTable for OffsetTableImpl { CodeIndexOffset(self.0.build_with(value)) } - fn lookup<'a>(&'a self, offset: CodeIndexOffset) -> TablePtr<'a, IndexPtr> { - self.0.lookup(offset.into()) + #[inline] + fn with_entry R>(&self, offset: CodeIndexOffset, f: F) -> R { + self.0.with_entry(offset.into(), f) } - fn lookup_mut<'a>(&'a mut self, offset: CodeIndexOffset) -> TablePtrMut<'a, IndexPtr> { - self.0.lookup_mut(offset.into()) + #[inline] + fn with_entry_mut R>( + &mut self, + offset: CodeIndexOffset, + f: F, + ) -> R { + self.0.with_entry_mut(offset.into(), f) } } @@ -251,8 +278,8 @@ impl SerialOffsetTable { impl ConcurrentOffsetTable { #[allow(clippy::missing_safety_doc)] - unsafe fn build_with(&self, value: T) -> usize { - let update_guard = self.growth_lock.write().unwrap(); + fn build_with(&self, value: T) -> usize { + let growth_lock = self.growth_lock.write(); // we don't have an index table for lookups as AtomTable does so // just get the epoch after we take the upgrade lock @@ -260,10 +287,10 @@ impl ConcurrentOffsetTable { let mut ptr; loop { - ptr = block_epoch.alloc(mem::size_of::()); + ptr = unsafe { block_epoch.alloc(mem::size_of::()) }; if ptr.is_null() { - let new_block = block_epoch.grow_new().unwrap(); + let new_block = unsafe { block_epoch.grow_new().unwrap() }; self.block.replace(new_block); block_epoch = self.block.read(); } else { @@ -271,35 +298,46 @@ impl ConcurrentOffsetTable { } } - ptr::write(ptr as *mut T, value); + let new_tbl_sz = block_epoch.size() / size_of::(); + let mut offset_locks = self.offset_locks.write(); + + offset_locks.resize_with(new_tbl_sz, || RwLock::new(())); + + unsafe { + ptr::write(ptr as *mut T, value); + } let value = ptr.addr() - block_epoch.base.addr(); // AtomTable would have to update the index table at this point // explicit drop to ensure we don't accidentally drop it early - drop(update_guard); + drop(offset_locks); + drop(growth_lock); value } - #[inline] - fn lookup<'a>(&'a self, offset: usize) -> (RcuRef, T>, RwLockReadGuard<'a, ()>) { - let growth_lock_guard = self.growth_lock.read().unwrap(); + fn with_entry R>(&self, offset: usize, f: F) -> R { + let outer_offset_lock = self.offset_locks.read(); + let inner_offset_lock = outer_offset_lock[offset / size_of::()].read(); let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe { raw_block.base.add(offset).cast::().as_ref() }) - .expect("The offset should result in a non-null pointer"); + .expect("offset valid"); - (rcu_ref, growth_lock_guard) + let result = f(&*rcu_ref); + + drop(inner_offset_lock); + drop(outer_offset_lock); + + result } - #[inline] - fn lookup_mut<'a>( - &'a self, - offset: usize, - ) -> (RcuRef, UnsafeCell>, RwLockReadGuard<'a, ()>) { - let growth_lock_guard = self.growth_lock.read().unwrap(); + fn with_entry_mut R>(&self, offset: usize, f: F) -> R { + let growth_lock = self.growth_lock.read(); + let outer_offset_lock = self.offset_locks.read(); + let inner_offset_lock = outer_offset_lock[offset / size_of::()].write(); let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe { raw_block @@ -309,9 +347,15 @@ impl ConcurrentOffsetTable { .cast::>() .as_ref() }) - .expect("The offset should result in a non-null pointer"); + .expect("offset valid"); - (rcu_ref, growth_lock_guard) + let result = f(unsafe { &mut *rcu_ref.get().as_mut().unwrap() }); + + drop(inner_offset_lock); + drop(outer_offset_lock); + drop(growth_lock); + + result } } @@ -358,64 +402,6 @@ impl CodeIndexOffset { } } -#[derive(Debug)] -pub struct TablePtr<'a, T: RawBlockTraits>(InnerTablePtr<'a, T>); - -#[derive(Debug)] -enum InnerTablePtr<'a, T: RawBlockTraits> { - Concurrent { - rcu_ref: RcuRef, T>, - #[allow(dead_code)] - guard_lock: RwLockReadGuard<'a, ()>, - }, - Serial(&'a T), -} - -impl PartialEq for TablePtr<'_, T> { - fn eq(&self, other: &TablePtr<'_, T>) -> bool { - self.deref() == other.deref() - } -} - -impl Eq for TablePtr<'_, T> {} - -impl PartialOrd for TablePtr<'_, T> { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for TablePtr<'_, T> { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - (**self).cmp(&**other) - } -} - -impl Hash for TablePtr<'_, T> { - #[inline(always)] - fn hash(&self, hasher: &mut H) { - (self as &T).hash(hasher) - } -} - -impl fmt::Display for TablePtr<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self as &T) - } -} - -impl Deref for TablePtr<'_, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - match &self.0 { - InnerTablePtr::Concurrent { rcu_ref, .. } => rcu_ref, - InnerTablePtr::Serial(ref_mut) => ref_mut, - } - } -} - impl fmt::Display for CodeIndexOffset { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "CodeIndexOffset({})", self.0) @@ -434,97 +420,3 @@ impl fmt::Display for F64Offset { write!(f, "F64Offset({})", self.0) } } - -#[derive(Debug)] -pub struct TablePtrMut<'a, T: RawBlockTraits>(InnerTablePtrMut<'a, T>); - -#[derive(Debug)] -enum InnerTablePtrMut<'a, T: RawBlockTraits> { - Concurrent { - rcu_ref: RcuRef, UnsafeCell>, - #[allow(dead_code)] - guard_lock: RwLockReadGuard<'a, ()>, - }, - Serial(&'a mut T), -} - -impl PartialEq for TablePtrMut<'_, T> { - fn eq(&self, other: &TablePtrMut<'_, T>) -> bool { - self.deref() == other.deref() - } -} - -impl Eq for TablePtrMut<'_, T> {} - -impl PartialOrd for TablePtrMut<'_, T> { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for TablePtrMut<'_, T> { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - (**self).cmp(&**other) - } -} - -impl Hash for TablePtrMut<'_, T> { - #[inline(always)] - fn hash(&self, hasher: &mut H) { - (self as &T).hash(hasher) - } -} - -impl fmt::Display for TablePtrMut<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self as &T) - } -} - -impl Deref for TablePtrMut<'_, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - match &self.0 { - InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe { - rcu_ref.get().as_ref().unwrap() - }, - InnerTablePtrMut::Serial(ref_mut) => ref_mut, - } - } -} - -impl DerefMut for TablePtrMut<'_, T> { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - match &mut self.0 { - InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe { - &mut *rcu_ref.get().as_mut().unwrap() - }, - InnerTablePtrMut::Serial(ref_mut) => ref_mut, - } - } -} - -impl TablePtrMut<'_, IndexPtr> { - #[inline] - pub fn set(&mut self, val: IndexPtr) { - match &mut self.0 { - InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe { - *rcu_ref.get() = val; - }, - InnerTablePtrMut::Serial(ref_mut) => { - **ref_mut = val; - } - } - } - - #[inline] - pub fn replace(&mut self, val: IndexPtr) -> IndexPtr { - match &mut self.0 { - InnerTablePtrMut::Concurrent { rcu_ref, .. } => unsafe { rcu_ref.get().replace(val) }, - InnerTablePtrMut::Serial(ref_mut) => mem::replace(*ref_mut, val), - } - } -} diff --git a/src/parser/parser.rs b/src/parser/parser.rs index b989738d..a131ff75 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -962,14 +962,14 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::Literal(Literal::Rational(n)) => { self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r)) } - Token::Literal(Literal::F64Offset(n)) if self.lexer.machine_st.arena.f64_tbl.lookup(n).is_infinite() => { + Token::Literal(Literal::F64Offset(n)) if self.lexer.machine_st.arena.f64_tbl.get_entry(n).is_infinite() => { return Err(ParserError::InfiniteFloat( self.lexer.line_num, self.lexer.col_num, )); } Token::Literal(Literal::F64Offset(n)) => { - let n = *self.lexer.machine_st.arena.f64_tbl.lookup(n); + let n = self.lexer.machine_st.arena.f64_tbl.get_entry(n); self.negate_number( n, From e303e5a805e1b8092e7cc7977680866654ac82b6 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 1 Jul 2025 15:47:26 -0700 Subject: [PATCH 058/122] correct number_chars (#2976) --- src/machine/system_calls.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 24735325..d301a85a 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1002,8 +1002,17 @@ impl MachineState { let err = self.syntax_error(err); return Err(self.error_form(err, stub_gen())); } - Ok(Term::Literal(_, cell)) => { - unify!(self, nx, HeapCellValue::from(cell)); + Ok(Term::Literal(_, Literal::Rational(n))) => { + self.unify_rational(n, nx); + } + Ok(Term::Literal(_, Literal::F64Offset(n))) => { + self.unify_f64(n, 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); From b78ccf8f28b57db8069c6d74d13f440cc42ef25f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 8 Jul 2025 13:47:08 -0700 Subject: [PATCH 059/122] fmt improvements --- src/parser/ast.rs | 6 +++--- src/parser/lexer.rs | 12 +++++------- src/parser/parser.rs | 20 ++++++++++++++------ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 4fc10e05..aa9ea077 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -447,9 +447,9 @@ impl ParserError { ParserError::InvalidSingleQuotedCharacter(..) => { atom!("invalid_single_quoted_character") } - ParserError::InfiniteFloat(..) => { - atom!("infinite_float") - } + ParserError::InfiniteFloat(..) => { + atom!("infinite_float") + } ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => { atom!("unexpected_end_of_file") } diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 6584dd32..2b63380c 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -665,10 +665,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { let n = parse_float_lossy(&token)?; - Ok(Number::Float(float_alloc!( - n, - self.machine_st.arena - ))) + Ok(Number::Float(float_alloc!(n, self.machine_st.arena))) } fn skip_underscore_in_number(&mut self) -> Result { @@ -944,9 +941,10 @@ impl<'a, R: CharRead> Lexer<'a, R> { Ok(n) => Ok(Token::Literal(n.to_literal())), Err(_) => { let n = parse_float_lossy(&token_string)?; - Ok(Token::Literal(Literal::F64Offset( - float_alloc!(n, self.machine_st.arena), - ))) + Ok(Token::Literal(Literal::F64Offset(float_alloc!( + n, + self.machine_st.arena + )))) } }, Ok(NumberToken::Number(n)) => return Ok(Token::Literal(n.to_literal())), diff --git a/src/parser/parser.rs b/src/parser/parser.rs index a131ff75..7a889520 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -962,12 +962,20 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::Literal(Literal::Rational(n)) => { self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r)) } - Token::Literal(Literal::F64Offset(n)) if self.lexer.machine_st.arena.f64_tbl.get_entry(n).is_infinite() => { - return Err(ParserError::InfiniteFloat( - self.lexer.line_num, - self.lexer.col_num, - )); - } + Token::Literal(Literal::F64Offset(n)) + if self + .lexer + .machine_st + .arena + .f64_tbl + .get_entry(n) + .is_infinite() => + { + return Err(ParserError::InfiniteFloat( + self.lexer.line_num, + self.lexer.col_num, + )); + } Token::Literal(Literal::F64Offset(n)) => { let n = self.lexer.machine_st.arena.f64_tbl.get_entry(n); From 4efceda8c5f6ef7d85d30fe3455e1f1b12056498 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 14 Jul 2025 23:05:10 -0700 Subject: [PATCH 060/122] fix parsing partial number tokens in other radixes (#3000) --- src/parser/lexer.rs | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 2b63380c..5fd5b7ba 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -508,7 +508,13 @@ impl<'a, R: CharRead> Lexer<'a, R> { if hexadecimal_digit_char!(c) { self.skip_char(c); token.push(c); - c = try_nt!(token, self.lookahead_char()); + c = match self.lookahead_char() { + Ok(c) => c, + Err(e) if e.is_unexpected_eof() => { + break; + } + Err(e) => return Err(e), + }; } else { break; } @@ -533,7 +539,13 @@ impl<'a, R: CharRead> Lexer<'a, R> { if octal_digit_char!(c) { self.skip_char(c); token.push(c); - c = try_nt!(token, self.lookahead_char()); + c = match self.lookahead_char() { + Ok(c) => c, + Err(e) if e.is_unexpected_eof() => { + break; + } + Err(e) => return Err(e), + }; } else { break; } @@ -558,7 +570,13 @@ impl<'a, R: CharRead> Lexer<'a, R> { if binary_digit_char!(c) { self.skip_char(c); token.push(c); - c = try_nt!(token, self.lookahead_char()); + c = match self.lookahead_char() { + Ok(c) => c, + Err(e) if e.is_unexpected_eof() => { + break; + } + Err(e) => return Err(e), + }; } else { break; } @@ -662,9 +680,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { 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))) } @@ -686,12 +702,8 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } - fn parse_integer_by_radix( - &mut self, - token: &String, - radix: u32, - ) -> Result { - i64::from_str_radix(&token, radix) + fn parse_integer_by_radix(&mut self, token: &str, radix: u32) -> Result { + i64::from_str_radix(token, radix) .map(|n| { Fixnum::build_with_checked(n) .map(Number::Fixnum) @@ -708,7 +720,7 @@ impl<'a, R: CharRead> Lexer<'a, R> { } #[inline] - fn parse_integer(&mut self, token: &String) -> Result { + fn parse_integer(&mut self, token: &str) -> Result { self.parse_integer_by_radix(token, 10) } From 4aa2a457362dff130bd196f59def219a3ca411e4 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 16 Jul 2025 21:52:40 -0700 Subject: [PATCH 061/122] fix variadic_functor --- src/functor_macro.rs | 47 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/functor_macro.rs b/src/functor_macro.rs index 2725aa9d..ba19f682 100644 --- a/src/functor_macro.rs +++ b/src/functor_macro.rs @@ -202,12 +202,17 @@ pub(crate) fn variadic_functor( let key_value_pairs: Vec<_> = iter.collect(); let num_items = key_value_pairs.len(); + let mut functor_offset = 0; + + for (idx, kv_func) in key_value_pairs.iter().enumerate() { + let functor_size = cell_index!(Heap::compute_functor_byte_size(kv_func)); - for (idx, _) in key_value_pairs.iter().enumerate() { arg_vec.push(FunctorElement::Cell(str_loc_as_cell!( - 2 + num_items * 2 + idx + 2 + num_items * 2 + functor_offset ))); - arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(5 + idx))); + arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(4 + 2 * idx))); + + functor_offset += functor_size; } arg_vec.pop(); @@ -225,6 +230,7 @@ pub(crate) fn variadic_functor( #[allow(unused_parens)] mod tests { use super::*; + use indexmap::indexmap; use std::string::String; use FunctorElement::*; @@ -683,6 +689,41 @@ mod tests { "and another" ); assert_eq!(heap[20], empty_list_as_cell!()); + + let constants = indexmap![ + atom_as_cell!(atom!("a")) => IndexingCodePtr::External(2), + atom_as_cell!(atom!("d")) => IndexingCodePtr::External(7), + ]; + + let functor = variadic_functor( + atom!("switch_on_constants"), + 1, + constants.iter().map(|(c, ptr)| { + functor!(atom!(":"), [cell((c.clone())), indexing_code_ptr((*ptr))]) + }), + ); + + heap.truncate(0); + + let mut functor_writer = Heap::functor_writer(functor); + functor_writer(&mut heap).unwrap(); + + assert_eq!(heap[0], atom_as_cell!(atom!("switch_on_constants"), 1)); + assert_eq!(heap[1], list_loc_as_cell!(2)); + assert_eq!(heap[2], str_loc_as_cell!(6)); + assert_eq!(heap[3], list_loc_as_cell!(4)); + assert_eq!(heap[4], str_loc_as_cell!(11)); + assert_eq!(heap[5], empty_list_as_cell!()); + assert_eq!(heap[6], atom_as_cell!(atom!(":"), 2)); + assert_eq!(heap[7], atom_as_cell!(atom!("a"))); + assert_eq!(heap[8], str_loc_as_cell!(9)); + assert_eq!(heap[9], atom_as_cell!(atom!("external"), 1)); + assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(2))); + assert_eq!(heap[11], atom_as_cell!(atom!(":"), 2)); + assert_eq!(heap[12], atom_as_cell!(atom!("d"))); + assert_eq!(heap[13], str_loc_as_cell!(14)); + assert_eq!(heap[14], atom_as_cell!(atom!("external"), 1)); + assert_eq!(heap[15], fixnum_as_cell!(Fixnum::build_with(7))); } #[test] From 65dda019a26f402d07d4e16163355e58706cbfd4 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 20 Jul 2025 16:55:07 -0700 Subject: [PATCH 062/122] allow abolish_clause to abolish empty dynamic clauses (#3010) --- src/machine/loader.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 02b8a2b0..685a69a0 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -2120,14 +2120,16 @@ impl Machine { .indices .remove_predicate_skeleton(&compilation_target, &key) .map(|skeleton| { - let mut clause_clause_skeleton = loader - .wam_prelude - .indices - .remove_predicate_skeleton( + let mut clause_clause_skeleton = + match loader.wam_prelude.indices.remove_predicate_skeleton( &clause_clause_compilation_target, &(atom!("$clause"), 2), - ) - .unwrap(); + ) { + Some(skeleton) => skeleton, + None => { + return vec![]; + } + }; let result = skeleton .core From 9b293cf1b601ca1fd2a00e8645cc89a795c34b0c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 22 Jul 2025 20:16:24 -0700 Subject: [PATCH 063/122] detect end_of_file before end_of_stream in get_char (#2990) --- src/machine/system_calls.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index d301a85a..6c861ae6 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3545,24 +3545,22 @@ impl Machine { self.machine_st.unify_atom(end_of_file, addr); + return Ok(()); + } else if addr == atom_as_cell!(atom!("end_of_file")) { + self.machine_st.fail = true; return Ok(()); } let stub_gen = || functor_stub(atom!("get_char"), 2); - let result = self.machine_st.open_parsing_stream(stream); let addr = if addr.is_var() { addr } else { read_heap_cell!(addr, (HeapCellValueTag::Atom, (atom, _arity)) => { - char_as_cell!(atom.as_char().unwrap()) - } - /* - (HeapCellValueTag::Char) => { + debug_assert!(atom.as_char().is_some()); addr } - */ _ => { let err = self.machine_st.type_error(ValidType::InCharacter, addr); return Err(self.machine_st.error_form(err, stub_gen())); @@ -3570,7 +3568,7 @@ impl Machine { ) }; - let mut iter = match result { + let mut iter = match self.machine_st.open_parsing_stream(stream) { Ok(iter) => iter, Err(e) => { if e.is_unexpected_eof() { From edf21494d9c01abf8ff63e45ba5106a4e40ba8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 20:07:07 +0200 Subject: [PATCH 064/122] also run CI on rebis-dev --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70f8d1a2..50b1a375 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,9 @@ name: CI on: push: - branches: [master] + branches: + - master + - rebis-dev tags: - "v**" pull_request: From 7199e9a2dbdb3d0ad703a1c93bd316281f4c6792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 20:07:57 +0200 Subject: [PATCH 065/122] remove outdated comment --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50b1a375..47f5050d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,6 @@ jobs: - { os: ubuntu-22.04, rust-version: nightly, target: 'wasm32-unknown-unknown', publish: true, args: '--no-default-features' , test-args: '--no-run --no-default-features', use_swap: true } # Cargo.toml rust-version - { os: ubuntu-22.04, rust-version: "1.85", target: 'x86_64-unknown-linux-gnu'} - # rust versions - { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu', miri: true, components: "miri"} defaults: From 8cc74b2af71526f6b949f06d091510bf1f280d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:26:08 +0200 Subject: [PATCH 066/122] fix clippy::uninlined_format_args --- build/instructions_template.rs | 6 +++--- build/static_string_indexing.rs | 4 ++-- src/forms.rs | 6 +++--- src/functor_macro.rs | 4 ++-- src/heap_print.rs | 12 ++++++------ src/machine/loader.rs | 4 ++-- src/machine/machine_indices.rs | 2 +- src/machine/mock_wam.rs | 12 +++--------- src/machine/system_calls.rs | 12 ++++++------ src/parser/ast.rs | 14 +++++++------- 10 files changed, 35 insertions(+), 41 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index dc2ed9f7..2f760ea1 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -3262,14 +3262,14 @@ where let disc = match DiscriminantT::from_str(id.to_string().as_str()) { Ok(disc) => disc, Err(_) => { - panic!("can't generate discriminant {}", id); + panic!("can't generate discriminant {id}"); } }; match disc.get_str(key) { Some(prop) => prop, None => { - panic!("can't find property {} of discriminant {:?}", key, disc); + panic!("can't find property {key} of discriminant {disc:?}"); } } } @@ -3387,7 +3387,7 @@ impl InstructionData { (name, arity, CountableInference::HasDefault) } else { - panic!("type ID is: {}", id); + panic!("type ID is: {id}"); }; let v_ident = variant diff --git a/build/static_string_indexing.rs b/build/static_string_indexing.rs index bffb5c13..a577a517 100644 --- a/build/static_string_indexing.rs +++ b/build/static_string_indexing.rs @@ -126,14 +126,14 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea match file.read_to_string(&mut src) { Ok(_) => {} Err(e) => { - panic!("error reading file: {:?}", e); + panic!("error reading file: {e:?}"); } } let syntax = match syn::parse_file(&src) { Ok(s) => s, Err(e) => { - panic!("parse error: {} in file {:?}", e, path); + panic!("parse error: {e} in file {path:?}"); } }; Ok(syntax) diff --git a/src/forms.rs b/src/forms.rs index 1418b570..409da51e 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -627,9 +627,9 @@ impl Default for Number { impl fmt::Display for Number { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Number::Float(fl) => write!(f, "{}", fl), - Number::Integer(n) => write!(f, "{}", n), - Number::Rational(r) => write!(f, "{}", r), + Number::Float(fl) => write!(f, "{fl}"), + Number::Integer(n) => write!(f, "{n}"), + Number::Rational(r) => write!(f, "{r}"), Number::Fixnum(n) => write!(f, "{}", n.get_num()), } } diff --git a/src/functor_macro.rs b/src/functor_macro.rs index ba19f682..54bcb28c 100644 --- a/src/functor_macro.rs +++ b/src/functor_macro.rs @@ -739,12 +739,12 @@ mod tests { ] ); - println!("{:?}", stub); + println!("{stub:?}"); // now the error form let lineless_error_form = functor!(atom!("error"), [functor(stub), functor(culprit)]); - println!("{:?}", lineless_error_form); + println!("{lineless_error_form:?}"); let mut heap = Heap::new(); let mut functor_writer = Heap::functor_writer(lineless_error_form); diff --git a/src/heap_print.rs b/src/heap_print.rs index 9cc3a2d0..57fef895 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -831,13 +831,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { read_heap_cell!(cell, (HeapCellValueTag::Lis | HeapCellValueTag::Str, h) => { - Some(format!("{}", h)) + Some(format!("{h}")) } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { - Some(format!("_{}", h)) + Some(format!("_{h}")) } (HeapCellValueTag::StackVar, h) => { - Some(format!("_s_{}", h)) + Some(format!("_s_{h}")) } _ => { None @@ -1002,7 +1002,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { #[inline] fn print_ip_addr(&mut self, ip: IpAddr) { push_char!(self, '\''); - append_str!(self, &format!("{}", ip)); + append_str!(self, &format!("{ip}")); push_char!(self, '\''); } @@ -1039,7 +1039,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.print_rational(max_depth, r, *op); } n => { - let output_str = format!("{}", n); + let output_str = format!("{n}"); push_space_if_amb!(self, &output_str, { append_str!(self, &output_str); @@ -1086,7 +1086,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) { Some(op_desc) => { if r.is_int() { - let output_str = format!("{}", r); + let output_str = format!("{r}"); push_space_if_amb!(self, &output_str, { append_str!(self, &output_str); diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 685a69a0..08282f68 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1407,10 +1407,10 @@ impl MachineState { term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap())); } (HeapCellValueTag::StackVar, h) => { - term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", 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)))); + term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{h}")))); } (HeapCellValueTag::Atom, (name, arity)) => { let h = iter.focus().value() as usize; diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 4f04c2b1..07d77f6a 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -206,7 +206,7 @@ impl VarKey { #[inline] pub(crate) fn to_string(&self) -> String { match self { - VarKey::AnonVar(h) => format!("_{}", h), + VarKey::AnonVar(h) => format!("_{h}"), VarKey::VarPtr(var) => var.borrow().to_string(), } } diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index b7201b71..941ff81e 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -195,15 +195,11 @@ pub fn all_cells_marked_and_unforwarded(heap: &Heap, offset: usize) { assert!( cell.get_mark_bit(), - "cell {:?} at index {} is not marked", - cell, - curr_idx + "cell {cell:?} at index {curr_idx} is not marked" ); assert!( !cell.get_forwarding_bit(), - "cell {:?} at index {} is forwarded", - cell, - curr_idx + "cell {cell:?} at index {curr_idx} is forwarded" ); } } @@ -227,9 +223,7 @@ pub fn all_cells_unmarked(iter: &impl SizedHeap) { assert!( !cell.get_mark_bit(), - "cell {:?} at index {} is still marked", - cell, - curr_idx + "cell {cell:?} at index {curr_idx} is still marked" ); } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 6c861ae6..244d56af 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2916,7 +2916,7 @@ impl Machine { let string = match Number::try_from((n, &self.machine_st.arena.f64_tbl)) { Ok(Number::Float(OrderedFloat(n))) => { - format!("{0:<20?}", n) + format!("{n:<20?}") } Ok(Number::Fixnum(n)) => n.get_num().to_string(), Ok(Number::Integer(n)) => n.to_string(), @@ -3245,7 +3245,7 @@ impl Machine { let n: u32 = (&*n).try_into().unwrap(); let n = char::try_from(n); if let Ok(c) = n { - write!(&mut stream, "{}", c).unwrap(); + write!(&mut stream, "{c}").unwrap(); return Ok(()); } } @@ -3253,7 +3253,7 @@ impl Machine { let n = n.get_num(); if let Some(c) = u32::try_from(n).ok().and_then(char::from_u32) { - write!(&mut stream, "{}", c).unwrap(); + write!(&mut stream, "{c}").unwrap(); return Ok(()); } } @@ -3295,13 +3295,13 @@ impl Machine { read_heap_cell!(addr, (HeapCellValueTag::Atom, (name, _arity)) => { if let Some(c) = name.as_char() { - write!(&mut stream, "{}", c).unwrap(); + write!(&mut stream, "{c}").unwrap(); return Ok(()); } } /* (HeapCellValueTag::Char, c) => { - write!(&mut stream, "{}", c).unwrap(); + write!(&mut stream, "{c}").unwrap(); return Ok(()); } */ @@ -8622,7 +8622,7 @@ impl Machine { ]; for spec in SPECIFIERS { - fstr.push_str(&format!("'{}'=\"%{}\", ", spec, spec).to_string()); + fstr.push_str(&format!("'{spec}'=\"%{spec}\", ")); } fstr.push_str("finis]."); diff --git a/src/parser/ast.rs b/src/parser/ast.rs index aa9ea077..654b2901 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -268,8 +268,8 @@ impl RegType { impl fmt::Display for RegType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - RegType::Perm(val) => write!(f, "Y{}", val), - RegType::Temp(val) => write!(f, "X{}", val), + RegType::Perm(val) => write!(f, "Y{val}"), + RegType::Temp(val) => write!(f, "X{val}"), } } } @@ -291,10 +291,10 @@ impl VarReg { impl fmt::Display for VarReg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), - VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), - VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg), - VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg), + VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{reg}"), + VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{reg}"), + VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{reg} A{arg}"), + VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{reg} A{arg}"), } } } @@ -830,7 +830,7 @@ impl Var { #[inline(always)] pub fn to_string(&self) -> String { match self { - Var::InSitu(n) | Var::Generated(n) => format!("_{}", n), + Var::InSitu(n) | Var::Generated(n) => format!("_{n}"), Var::Named(value) => value.as_ref().clone(), } } From 72631b3e0b10f317f92cab34aee558715292af42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:28:30 +0200 Subject: [PATCH 067/122] fix clone on copy values --- build/instructions_template.rs | 2 +- src/functor_macro.rs | 6 +++--- src/machine/compile.rs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 2f760ea1..31c329b9 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -1055,7 +1055,7 @@ fn generate_instruction_preface() -> TokenStream { constants.iter().map(|(c, ptr)| { functor!( atom!(":"), - [cell((c.clone())), indexing_code_ptr((*ptr))] + [cell((*c)), indexing_code_ptr((*ptr))] ) }), ) diff --git a/src/functor_macro.rs b/src/functor_macro.rs index 54bcb28c..591fa185 100644 --- a/src/functor_macro.rs +++ b/src/functor_macro.rs @@ -698,9 +698,9 @@ mod tests { let functor = variadic_functor( atom!("switch_on_constants"), 1, - constants.iter().map(|(c, ptr)| { - functor!(atom!(":"), [cell((c.clone())), indexing_code_ptr((*ptr))]) - }), + constants + .iter() + .map(|(c, ptr)| functor!(atom!(":"), [cell((*c)), indexing_code_ptr((*ptr))])), ); heap.truncate(0); diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 7dcbee14..8e799009 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -133,7 +133,7 @@ fn merge_indices( ); retraction_info.push_record(RetractionRecord::AddedIndex( - skeleton[clause_index].opt_arg_index_key.clone(), + skeleton[clause_index].opt_arg_index_key, clause_loc, )); } else { @@ -246,7 +246,7 @@ fn remove_index_from_subsequence( // appear anywhere inside an Internal record. retraction_info.push_record(RetractionRecord::RemovedIndex( index_loc, - opt_arg_index_key.clone(), + *opt_arg_index_key, offset, )); } @@ -808,7 +808,7 @@ fn prepend_compiled_clause( skeleton.clauses[0].clause_start = clause_loc + 2; retraction_info.push_record(RetractionRecord::AddedIndex( - skeleton.clauses[0].opt_arg_index_key.clone(), + skeleton.clauses[0].opt_arg_index_key, skeleton.clauses[0].clause_start, )); @@ -1070,7 +1070,7 @@ fn append_compiled_clause( skeleton.clauses[target_pos].opt_arg_index_key += index_loc - 1; retraction_info.push_record(RetractionRecord::AddedIndex( - skeleton.clauses[target_pos].opt_arg_index_key.clone(), + skeleton.clauses[target_pos].opt_arg_index_key, skeleton.clauses[target_pos].clause_start, )); From ae3019d9230d12beedeffb08f817b05db7420086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:31:34 +0200 Subject: [PATCH 068/122] fix unecessary reference/dereference --- src/atom_table.rs | 2 +- src/forms.rs | 6 +++--- src/iterators.rs | 2 +- src/machine/dispatch.rs | 2 +- src/machine/heap.rs | 2 +- src/machine/system_calls.rs | 8 ++++---- src/machine/unify.rs | 2 +- src/parser/ast.rs | 6 +++--- src/parser/parser.rs | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/atom_table.rs b/src/atom_table.rs index 12910753..d7796d73 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -254,7 +254,7 @@ impl std::ops::Deref for AtomString<'_> { fn deref(&self) -> &Self::Target { match self { Self::Static(reference) => reference, - Self::Inlined(inlined) => inlined_to_str(&inlined), + Self::Inlined(inlined) => inlined_to_str(inlined), Self::Dynamic(guard) => guard.deref(), } } diff --git a/src/forms.rs b/src/forms.rs index 409da51e..26f37b3e 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -372,11 +372,11 @@ pub enum ModuleSource { impl ModuleSource { pub(crate) fn as_functor_stub(&self) -> MachineStub { - match self { - &ModuleSource::Library(name) => { + match *self { + ModuleSource::Library(name) => { functor!(atom!("library"), [atom_as_cell(name)]) } - &ModuleSource::File(name) => { + ModuleSource::File(name) => { functor!(name) } } diff --git a/src/iterators.rs b/src/iterators.rs index 5bd51d99..8e2e43dd 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -403,7 +403,7 @@ impl<'a> Iterator for ClauseIterator<'a> { self.state_stack .push(ClauseIteratorState::RemainingBranches(branches, 0)); } - &ChunkedTerms::Chunk { ref terms } => { + ChunkedTerms::Chunk { ref terms } => { return Some(ClauseItem::Chunk { terms }); } } diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 2428f7d2..af34bcd7 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -3277,7 +3277,7 @@ impl Machine { &Instruction::PutPartialString(_, ref string, reg) => { self.machine_st[reg] = backtrack_on_resource_error!( self.machine_st, - self.machine_st.heap.allocate_pstr(&string) + self.machine_st.heap.allocate_pstr(string) ); self.machine_st.p += 1; diff --git a/src/machine/heap.rs b/src/machine/heap.rs index fdf24047..66e511f5 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1009,7 +1009,7 @@ impl<'a> PStrSegmentIter<'a> { let string_buf = unsafe { let char_ptr = heap.inner.ptr.add(pstr_loc); let slice = std::slice::from_raw_parts(char_ptr, heap.inner.byte_len - pstr_loc); - std::str::from_utf8_unchecked(&slice) + std::str::from_utf8_unchecked(slice) }; PStrSegmentIter { string_buf } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 244d56af..ac09b7f8 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2327,7 +2327,7 @@ impl Machine { let cell = step_or_resource_error!( self.machine_st, - self.machine_st.heap.allocate_cstr(&*name.as_str()) + self.machine_st.heap.allocate_cstr(&name.as_str()) ); unify!(self.machine_st, self.machine_st.registers[2], cell); @@ -2386,7 +2386,7 @@ impl Machine { self.machine_st, sized_iter_to_heap_list( &mut self.machine_st.heap, - (&*name).chars().count(), + name.chars().count(), iter, ) ); @@ -7637,7 +7637,7 @@ impl Machine { let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); let cstr_cell = - step_or_resource_error!(self.machine_st, self.machine_st.heap.allocate_cstr(&buffer)); + step_or_resource_error!(self.machine_st, self.machine_st.heap.allocate_cstr(buffer)); unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]); } @@ -8719,7 +8719,7 @@ impl Machine { Ok(result) } scraper::Node::Comment(comment) => { - let comment = self.machine_st.heap.allocate_cstr(&comment)?; + let comment = self.machine_st.heap.allocate_cstr(comment)?; let result = str_loc_as_cell!(self.machine_st.heap.cell_len()); let mut writer = self.machine_st.heap.reserve(2)?; diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 6ada6fb1..fdc430ee 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -290,7 +290,7 @@ pub(crate) trait Unifier: DerefMut { let machine_st = self.deref_mut(); let f1 = machine_st.arena.f64_tbl.get_entry(f1); - let f2 = machine_st.arena.f64_tbl.get_entry(f2.into()); + let f2 = machine_st.arena.f64_tbl.get_entry(f2); self.fail = f1 != f2; } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 654b2901..da9353ec 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -858,9 +858,9 @@ impl Term { } pub fn name(&self) -> Option { - match self { - &Term::Literal(_, Literal::Atom(atom)) => Some(atom), - &Term::Clause(_, atom, ..) => Some(atom), + match *self { + Term::Literal(_, Literal::Atom(atom)) => Some(atom), + Term::Clause(_, atom, ..) => Some(atom), _ => None, } } diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 7a889520..a874face 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -111,7 +111,7 @@ pub(crate) fn as_partial_string( tail_ref = tail; } Term::CompleteString(_, cstr) => { - string += &*cstr.as_str(); + string += cstr.as_str(); tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); break; } From 495bcd73f2d17b3ac43600e4300291b346a88c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:33:13 +0200 Subject: [PATCH 069/122] fix unecessary return --- src/ffi.rs | 4 ++-- src/machine/load_state.rs | 4 ++-- src/parser/lexer.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ffi.rs b/src/ffi.rs index a3015b6d..55bb525b 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -324,7 +324,7 @@ impl ForeignFunctionTable { let mut pointer_args = Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?; - return unsafe { + unsafe { macro_rules! call_and_return { ($type:ty) => {{ let mut n: Box = Box::new(0); @@ -410,7 +410,7 @@ impl ForeignFunctionTable { } _ => unreachable!(), } - }; + } } fn read_struct( diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 40e9a383..ae572aff 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -688,12 +688,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl; if module_name == atom!("user") { - return *self + *self .wam_prelude .indices .code_dir .entry(key) - .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl)); + .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl)) } else { self.get_or_insert_local_code_index(module_name, key) } diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 5fd5b7ba..2f756cf4 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -959,8 +959,8 @@ impl<'a, R: CharRead> Lexer<'a, R> { )))) } }, - Ok(NumberToken::Number(n)) => return Ok(Token::Literal(n.to_literal())), - Err(e) => return Err(e), + Ok(NumberToken::Number(n)) => Ok(Token::Literal(n.to_literal())), + Err(e) => Err(e), } } From a639fec153af879b381fc28b697a2b625cd40f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:34:15 +0200 Subject: [PATCH 070/122] fix match/if-let can be simplified to ? --- src/machine/cycle_detection.rs | 10 ++-------- src/machine/system_calls.rs | 4 +--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/machine/cycle_detection.rs b/src/machine/cycle_detection.rs index da125518..a800a9b6 100644 --- a/src/machine/cycle_detection.rs +++ b/src/machine/cycle_detection.rs @@ -137,10 +137,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { let cell = self.heap[h]; let arity = cell_as_atom_cell!(self.heap[h]).get_arity(); - let last_cell_loc = match self.traverse_subterm(h + 1, arity) { - Some(last_cell_loc) => last_cell_loc, - None => return None, - }; + let last_cell_loc = self.traverse_subterm(h + 1, arity)?; if last_cell_loc == h { if self.backward() { @@ -171,10 +168,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { let mut cell = self.heap[self.current]; cell.set_value(self.next); - let last_cell_loc = match self.traverse_subterm(self.next as usize, 2) { - Some(last_cell_loc) => last_cell_loc, - None => return None, - }; + let last_cell_loc = self.traverse_subterm(self.next as usize, 2)?; if self.cycle_detection_active() { for idx in (self.next as usize..last_cell_loc).rev() { diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index ac09b7f8..10323c5c 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -4152,9 +4152,7 @@ impl Machine { let mut functor_writer = Heap::functor_writer(functor); - if let Err(e) = functor_writer(heap) { - return Err(e); - } + functor_writer(heap)?; num_functors += 1; } From 58b9a6ad6927b434b74d26ba62e93debcdcc3ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:35:40 +0200 Subject: [PATCH 071/122] ignore wrong self convention --- src/parser/lexer.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 2f756cf4..0ca5ef69 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -63,6 +63,7 @@ enum Number { impl Number { #[inline] + #[allow(clippy::wrong_self_convention)] fn to_literal(self) -> Literal { match self { Number::BigInt(ibig) => Literal::Integer(ibig), @@ -80,6 +81,7 @@ enum NumberToken { impl NumberToken { #[inline] + #[allow(clippy::wrong_self_convention)] fn to_token(self) -> Option { match self { NumberToken::Number(number) => Some(Token::Literal(number.to_literal())), From 1d26f98688fc4df8723072ba83366063585bf14e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:35:55 +0200 Subject: [PATCH 072/122] fix legacy int constants --- src/parser/ast.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parser/ast.rs b/src/parser/ast.rs index da9353ec..18389225 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -10,7 +10,6 @@ use std::cell::{Cell, Ref, RefCell, RefMut}; use std::fmt; use std::hash::Hash; use std::hash::Hasher; -use std::i64; use std::io::{Error as IOError, ErrorKind}; use std::ops::Not; use std::ops::RangeInclusive; From 166ec02973dc275ee4fe96779622ab7de3282548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:36:53 +0200 Subject: [PATCH 073/122] ignore clippy::unbuffered_bytes in test helper functions --- src/machine/mock_wam.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 941ff81e..d157ee14 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -249,6 +249,7 @@ pub(crate) fn parse_and_write_parsed_term_to_heap( impl Machine { /// For use in tests. + #[allow(clippy::unbuffered_bytes)] pub fn test_load_file(&mut self, file: &str) -> Vec { let stream = Stream::from_owned_string( std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), @@ -260,6 +261,7 @@ impl Machine { } /// For use in tests. + #[allow(clippy::unbuffered_bytes)] pub fn test_load_string(&mut self, code: &str) -> Vec { let stream = Stream::from_owned_string(code.to_owned(), &mut self.machine_st.arena); From 6d7c217227c0ddc1c0782e26a54e25bed42c4ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:37:23 +0200 Subject: [PATCH 074/122] fix unecessary mut --- src/machine/mock_wam.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index d157ee14..0fcebd41 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -56,7 +56,7 @@ impl MockWAM { let mut printer = HCPrinter::new( &mut self.machine_st.heap, &mut self.machine_st.stack, - &mut self.machine_st.arena, + &self.machine_st.arena, &self.op_dir, PrinterOutputter::new(), term_write_result.heap_loc, From fae5e13bd51a1810e9f98bd88a1ed906e94cff20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:38:26 +0200 Subject: [PATCH 075/122] impl From rather than Into --- src/machine/machine_indices.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 07d77f6a..3c918883 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -159,17 +159,17 @@ impl From for CodeIndex { } } -impl Into for CodeIndex { +impl From for CodeIndexOffset { #[inline(always)] - fn into(self) -> CodeIndexOffset { - self.0 + fn from(value: CodeIndex) -> CodeIndexOffset { + value.0 } } -impl Into for &'_ CodeIndex { +impl From<&'_ CodeIndex> for CodeIndexOffset { #[inline(always)] - fn into(self) -> CodeIndexOffset { - self.0 + fn from(value: &'_ CodeIndex) -> CodeIndexOffset { + value.0 } } From 73cc872b5010936e6759f014b81f3a1054d9727c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:38:48 +0200 Subject: [PATCH 076/122] check not empty instead of len > 0 --- src/debray_allocator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 3bc96dfc..53c7f206 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -251,7 +251,7 @@ impl DebrayAllocator { } } - if self.branch_stack.len() > 0 { + if !self.branch_stack.is_empty() { for var_num in subsumed_hits { self.branch_stack.add_branch_occurrence(var_num); } From 6885074006223d75364b0faa3b4c6d4f5d63bebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:40:05 +0200 Subject: [PATCH 077/122] fix clippy::unit_arg --- src/machine/machine_state.rs | 4 ++-- src/machine/streams.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index fac5d7b6..7663c952 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -659,8 +659,8 @@ impl MachineState { &self.atom_tbl, ) ); - - Ok(unify_fn!(*self, var_names_offset, var_names_addr)) + unify_fn!(*self, var_names_offset, var_names_addr); + Ok(()) } pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult { diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 1f9fae09..25e9a75a 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1653,7 +1653,8 @@ impl MachineState { }; stream.set_past_end_of_stream(true); - Ok(unify!(self, result, end_of_stream)) + unify!(self, result, end_of_stream); + Ok(()) } EOFAction::Reset => { if !stream.reset() { From 7593f88d5a18476ff4ba13d7666cda6b58ebcafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:40:38 +0200 Subject: [PATCH 078/122] ingore nerver looping loop, but add a todo --- src/machine/system_calls.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 10323c5c..77230c01 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -989,6 +989,7 @@ impl MachineState { } } + #[allow(clippy::never_loop)] // TODO why is there a loop here that never loops? loop { match lexer.lookahead_char() { Err(e) if e.is_unexpected_eof() => { From c885d1a7e7ddabc01aec6439ef5f3f241f4ffc1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:41:23 +0200 Subject: [PATCH 079/122] collaps els-if / if-if --- src/machine/heap.rs | 6 ++---- src/machine/machine_state_impl.rs | 10 ++++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 66e511f5..0aad650a 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -745,10 +745,8 @@ impl Heap { // the heap to a pre-allocated resource error pub(crate) fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), usize> { unsafe { - if self.inner.byte_len == self.inner.byte_cap { - if !self.grow() { - return Err(self.resource_error_offset()); - } + if self.inner.byte_len == self.inner.byte_cap && !self.grow() { + return Err(self.resource_error_offset()); } // SAFETY: diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index f663656c..3f14253d 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -847,13 +847,11 @@ impl MachineState { if let Some(c) = char_iter.next() { if n == 1 { self.unify_char(c, a3); + } else if char_iter.next().is_some() { + unify_fn!(*self, pstr_loc_as_cell!(pstr_loc + c.len_utf8()), a3); } else { - if char_iter.next().is_some() { - unify_fn!(*self, pstr_loc_as_cell!(pstr_loc + c.len_utf8()), a3); - } else { - let tail_idx = Heap::pstr_tail_idx(pstr_loc + c.len_utf8()); - unify_fn!(*self, self.heap[tail_idx], a3); - } + let tail_idx = Heap::pstr_tail_idx(pstr_loc + c.len_utf8()); + unify_fn!(*self, self.heap[tail_idx], a3); } } else { unreachable!() From 014d1b00954a313c71ecf977d79cd71fb29226e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:41:51 +0200 Subject: [PATCH 080/122] remove already implied must_use --- src/machine/heap.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 0aad650a..e69050ab 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -612,7 +612,6 @@ impl Heap { } } - #[must_use] pub fn reserve(&mut self, num_cells: usize) -> Result { let section; let len = heap_index!(num_cells); From 876685191960eb810c109014df1ee918032b8a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:43:59 +0200 Subject: [PATCH 081/122] replace single non-wildcard pattern match with if let --- src/machine/load_state.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index ae572aff..89c50153 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -546,27 +546,21 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { for export in removed_module.module_decl.exports.iter() { match export { ModuleExport::PredicateKey(ref key) => { - match ( + if let (Some(module_code_idx), Some(target_code_idx)) = ( removed_module.code_dir.get(key).cloned(), code_dir.get_mut(key).cloned(), ) { - (Some(module_code_idx), Some(target_code_idx)) => { - let code_index_tbl = - &mut LS::machine_st(payload).arena.code_index_tbl; - let module_code_ptr = - code_index_tbl.get_entry(module_code_idx.into()); - let target_code_ptr = - code_index_tbl.get_entry(target_code_idx.into()); + let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl; + let module_code_ptr = code_index_tbl.get_entry(module_code_idx.into()); + let target_code_ptr = code_index_tbl.get_entry(target_code_idx.into()); - if module_code_ptr == target_code_ptr { - let old_index_ptr = target_code_idx - .replace(code_index_tbl, IndexPtr::undefined()); - payload - .retraction_info - .push_record(predicate_retractor(*key, old_index_ptr)); - } + if module_code_ptr == target_code_ptr { + let old_index_ptr = + target_code_idx.replace(code_index_tbl, IndexPtr::undefined()); + payload + .retraction_info + .push_record(predicate_retractor(*key, old_index_ptr)); } - _ => {} } } ModuleExport::OpDecl(op_decl) => { From df3f1236f79675918485a56c53b881f8ea5d6316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:44:52 +0200 Subject: [PATCH 082/122] replace always erroring of_else with map_err --- src/machine/system_calls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 77230c01..cdd87dfc 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3936,14 +3936,14 @@ impl Machine { self.indices.remove_stream(stream); - stream.close().or_else(|_| { + stream.close().map_err(|_| { let stub = functor_stub(atom!("close"), 1); let addr = stream.into(); let err = self .machine_st .existence_error(ExistenceError::Stream(addr)); - Err(self.machine_st.error_form(err, stub)) + self.machine_st.error_form(err, stub) }) } From 3365cffa962ec0bd8a6198252f9bc46a145df20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:45:26 +0200 Subject: [PATCH 083/122] prefere for loop --- src/machine/system_calls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index cdd87dfc..6c91bada 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -194,7 +194,7 @@ fn pstr_segment_char_count_up_to( let mut byte_offset = 0; if max_chars > 0 { - while let Some(c) = char_iter.next() { + for c in &mut char_iter { if c == '\u{0}' { break; } From e7600884fb5e6ad0181f6843240e1fd44d31789d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:45:44 +0200 Subject: [PATCH 084/122] remove unecessary into_iter --- src/machine/machine_indices.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 3c918883..7f7bfe35 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -526,7 +526,7 @@ impl IndexStore { &'a self, range: R, ) -> impl Iterator + 'a { - self.streams.range(range).into_iter().copied() + self.streams.range(range).copied() } /// Forcibly sets `alias` to `stream`. From de89a78cbb160099be4d08af74fd46821cce3805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:45:57 +0200 Subject: [PATCH 085/122] remove unecessary cast --- src/machine/system_calls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 6c91bada..15a0d6a6 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -784,7 +784,7 @@ impl MachineState { let steps = if max_steps > -1 { std::cmp::min(max_steps, num_steps as i64) } else { - max_steps as i64 + max_steps }; self.finalize_skip_max_list(steps, pstr_loc); // cell); From 4f04d2dfca8aa566432843242535e964aaa1c358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Thu, 31 Jul 2025 21:46:21 +0200 Subject: [PATCH 086/122] replace .skip(n).next() with .nth(n) --- src/machine/system_calls.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 15a0d6a6..8c0eee0a 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3793,11 +3793,7 @@ impl Machine { #[inline(always)] pub(crate) fn first_stream(&mut self) { - let first_stream = self - .indices - .iter_streams(..) - .filter(|s| !s.is_null_stream()) - .next(); + let first_stream = self.indices.iter_streams(..).find(|s| !s.is_null_stream()); if let Some(first_stream) = first_stream { let stream = first_stream.into(); @@ -3817,8 +3813,7 @@ impl Machine { .indices .iter_streams(prev_stream..) .filter(|s| !s.is_null_stream()) - .skip(1) - .next(); + .nth(1); if let Some(next_stream) = next_stream { let var = self.deref_register(2).as_var().unwrap(); From ae0baf489354cd01cb54d855ccab1921d3a0dd38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 19 Jul 2025 20:50:53 +0200 Subject: [PATCH 087/122] [WIP] add support to spawn new processes --- .github/workflows/ci.yml | 2 +- Cargo.toml | 2 +- build/instructions_template.rs | 4 + src/arena.rs | 10 ++ src/lib/error.pl | 14 ++- src/lib/process.pl | 52 ++++++++++ src/machine/dispatch.rs | 8 ++ src/machine/streams.rs | 81 ++++++++++++++-- src/machine/system_calls.rs | 168 +++++++++++++++++++++++++++++++++ 9 files changed, 326 insertions(+), 15 deletions(-) create mode 100644 src/lib/process.pl diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47f5050d..0b3071ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,7 @@ jobs: # FIXME(issue #2138): run wasm tests, failing to run since https://github.com/mthom/scryer-prolog/pull/2137 removed wasm-pack - { os: ubuntu-22.04, rust-version: nightly, target: 'wasm32-unknown-unknown', publish: true, args: '--no-default-features' , test-args: '--no-run --no-default-features', use_swap: true } # Cargo.toml rust-version - - { os: ubuntu-22.04, rust-version: "1.85", target: 'x86_64-unknown-linux-gnu'} + - { os: ubuntu-22.04, rust-version: "1.87", target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'} - { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu', miri: true, components: "miri"} defaults: diff --git a/Cargo.toml b/Cargo.toml index 3087a3a2..67f65bc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["prolog", "prolog-interpreter", "prolog-system"] categories = ["command-line-utilities"] build = "build/main.rs" # Remember to check CI -rust-version = "1.85" +rust-version = "1.87" [lib] crate-type = ["cdylib", "rlib"] diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 31c329b9..6ea7a5a5 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -537,6 +537,8 @@ enum SystemClauseType { UnsetEnv, #[strum_discriminants(strum(props(Arity = "2", Name = "$shell")))] Shell, + #[strum_discriminants(strum(props(Arity = "8", Name = "$process_create")))] + ProcessCreate, #[strum_discriminants(strum(props(Arity = "1", Name = "$pid")))] Pid, #[strum_discriminants(strum(props(Arity = "4", Name = "$chars_base64")))] @@ -1825,6 +1827,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallSetEnv | &Instruction::CallUnsetEnv | &Instruction::CallShell | + &Instruction::CallProcessCreate | &Instruction::CallPid | &Instruction::CallCharsBase64 | &Instruction::CallDevourWhitespace | @@ -2063,6 +2066,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteSetEnv | &Instruction::ExecuteUnsetEnv | &Instruction::ExecuteShell | + &Instruction::ExecuteProcessCreate | &Instruction::ExecutePid | &Instruction::ExecuteCharsBase64 | &Instruction::ExecuteDevourWhitespace | diff --git a/src/arena.rs b/src/arena.rs index 2a3fc8b9..2b312070 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -14,6 +14,8 @@ use ordered_float::OrderedFloat; use std::fmt; use std::fmt::Debug; use std::hash::{Hash, Hasher}; +use std::io::PipeReader; +use std::io::PipeWriter; use std::mem; use std::mem::ManuallyDrop; use std::net::TcpListener; @@ -71,7 +73,9 @@ pub enum ArenaHeaderTag { TcpListener = 0b1000000, HttpListener = 0b1000001, HttpResponse = 0b1000010, + PipeWriter = 0b1000011, Dropped = 0b1000100, + PipeReader = 0b1000101, } #[bitfield] @@ -546,6 +550,12 @@ unsafe fn drop_slab_in_place(value: NonNull, tag: ArenaHeaderTag) { ArenaHeaderTag::StandardErrorStream => { drop_typed_slab_in_place!(StandardErrorStream, value); } + ArenaHeaderTag::PipeReader => { + drop_typed_slab_in_place!(PipeReader, value); + } + ArenaHeaderTag::PipeWriter => { + drop_typed_slab_in_place!(PipeWriter, value); + } ArenaHeaderTag::NullStream => { unreachable!("NullStream is never arena allocated!"); } diff --git a/src/lib/error.pl b/src/lib/error.pl index 67df8a32..0eb2a6d4 100644 --- a/src/lib/error.pl +++ b/src/lib/error.pl @@ -82,6 +82,9 @@ must_be_(octet_chars, Cs) :- ; true ). must_be_(list, Term) :- check_(error:ilist, list, Term). +must_be_(list(Elem), Term) :- + must_be_(list, Term), + check_all(Elem, Term). must_be_(type, Term) :- check_(error:type, type, Term). must_be_(boolean, Term) :- check_(error:boolean, boolean, Term). must_be_(pair, Term) :- check_(error:pair, pair, Term). @@ -96,10 +99,12 @@ must_be_(term, Term) :- % We cannot use maplist(must_be(character), Cs), because library(lists) % uses library(error), so importing it would create a cyclic dependency. -all_characters([]). -all_characters([C|Cs]) :- - must_be(character, C), - all_characters(Cs). +check_all(_, []). +check_all(Type, [Head| Tail]) :- + must_be(Type, Head), + check_all(Type, Tail). + +all_characters(Cs) :- check_all(character, Cs). check_(Pred, Type, Term) :- ( var(Term) -> instantiation_error(must_be/2) @@ -141,6 +146,7 @@ type(octet_character). type(octet_chars). type(chars). type(list). +type(list(Type)) :- type(Type). type(var). type(boolean). type(term). diff --git a/src/lib/process.pl b/src/lib/process.pl new file mode 100644 index 00000000..e712bd69 --- /dev/null +++ b/src/lib/process.pl @@ -0,0 +1,52 @@ +:- module(process, [process_create/3]). + +:- use_module(library(error)). +:- use_module(library(iso_ext)). +:- use_module(library(lists), [append/3, member/2]). + +process_create(Exe, Args, Options) :- + must_be(chars, Exe), + must_be(list(chars), Args), + must_be(list, Options), + check_option(Sin, find_stdio(Sin, stdin, Options), valid_stdio, [std], Stdin), + check_option(Sout, find_stdio(Sout, stdout, Options), valid_stdio, [std], Stdout), + check_option(Serr, find_stdio(Serr, stderr, Options), valid_stdio, [std], Stderr), + check_option(Envs, find_env(Envs, Options), valid_env, [environment, []], EnvVars), + check_option(P, member(process(P), Options), valid_pid, _, Pid), + check_option(C, member(cwd(C), Options), valid_cwd, _, Cwd), + '$process_create'(Exe, Args, Stdin, Stdout, Stderr, EnvVars, Cwd, Pid). + + +check_option(Template, Goal, Pred, Default, Choice) :- + findall(Template, Goal, Solutions), + check_option_(Solutions, Pred, Default, Choice). + +check_option_([] , Pred , Default , Default ) :- call(Pred, Default). +check_option_([Choice] , Pred , _ , Choice ) :- call(Pred, Choice). +check_option_([X1,X2|Xs], _ , _ , _ ) :- throw(error(duplicate_option, process_create/3, [X1, X2 | Xs])). + +find_stdio([std], Kind, Options ) :- Elem =.. [Kind, std], member(Elem, Options). +find_stdio([null], Kind, Options ) :- Elem =.. [Kind, null], member(Elem, Options). +find_stdio([pipe, Stream], Kind, Options) :- Elem =.. [Kind, pipe(Stream)], member(Elem, Options). +find_stdio([file, Path], Kind, Options ) :- Elem =.. [Kind, file(Path)], member(Elem, Options). + +valid_stdio([std]). +valid_stdio([null]). +valid_stdio([pipe, Stream]) :- must_be(var, Stream). +valid_stdio([file, Path]) :- must_be(chars, Path). + +find_env([env, E], Options) :- member(env(E), Options). +find_env([environment, E], Options) :- member(environment(E), Options). + +valid_cwd(Cwd) :- must_be(chars, Cwd). + +valid_env([env, E]) :- valid_env_(E). +valid_env([environment, E]) :- valid_env_(E). + +valid_env_([]). +valid_env_([N=V|Es]) :- + must_be(chars, N), + must_be(chars, V), + valid_env_(Es). + +valid_pid(Pid) :- must_be(var, Pid). diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index af34bcd7..36068ca2 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -4787,6 +4787,14 @@ impl Machine { self.shell(); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } + &Instruction::CallProcessCreate => { + try_or_throw!(self.machine_st, self.process_create()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteProcessCreate => { + try_or_throw!(self.machine_st, self.process_create()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } &Instruction::CallPid => { self.pid(); step_or_fail!(self, self.machine_st.p += 1); diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 25e9a75a..871ea617 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -23,6 +23,8 @@ use std::fmt::Debug; use std::fs::{File, OpenOptions}; use std::hash::Hash; use std::io; +use std::io::PipeReader; +use std::io::PipeWriter; use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; use std::mem::ManuallyDrop; use std::net::{Shutdown, TcpStream}; @@ -588,6 +590,8 @@ arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream); arena_allocated_impl_for_stream!(StandardErrorStream, StandardErrorStream); arena_allocated_impl_for_stream!(CharReader, CallbackStream); arena_allocated_impl_for_stream!(CharReader, InputChannelStream); +arena_allocated_impl_for_stream!(CharReader, PipeReader); +arena_allocated_impl_for_stream!(CharReader, PipeWriter); #[derive(Debug, Copy, Clone)] pub enum Stream { @@ -608,6 +612,8 @@ pub enum Stream { StandardError(TypedArenaPtr), Callback(TypedArenaPtr), InputChannel(TypedArenaPtr), + PipeReader(TypedArenaPtr), + PipeWriter(TypedArenaPtr), } impl From> for Stream { @@ -726,6 +732,8 @@ impl Stream { Stream::StandardError(ptr) => ptr.header_ptr(), Stream::Callback(ptr) => ptr.header_ptr(), Stream::InputChannel(ptr) => ptr.header_ptr(), + Stream::PipeReader(ptr) => ptr.header_ptr(), + Stream::PipeWriter(ptr) => ptr.header_ptr(), } } @@ -748,6 +756,8 @@ impl Stream { Stream::StandardError(ref ptr) => &ptr.options, Stream::Callback(ref ptr) => &ptr.options, Stream::InputChannel(ref ptr) => &ptr.options, + Stream::PipeReader(ref ptr) => &ptr.options, + Stream::PipeWriter(ref ptr) => &ptr.options, } } @@ -770,6 +780,8 @@ impl Stream { Stream::StandardError(ref mut ptr) => &mut ptr.options, Stream::Callback(ref mut ptr) => &mut ptr.options, Stream::InputChannel(ref mut ptr) => &mut ptr.options, + Stream::PipeReader(ref mut ptr) => &mut ptr.options, + Stream::PipeWriter(ref mut ptr) => &mut ptr.options, } } @@ -793,6 +805,8 @@ impl Stream { Stream::StandardError(ptr) => ptr.lines_read += incr_num_lines_read, Stream::Callback(ptr) => ptr.lines_read += incr_num_lines_read, Stream::InputChannel(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::PipeReader(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::PipeWriter(_) => {} } } @@ -816,6 +830,8 @@ impl Stream { Stream::StandardError(ptr) => ptr.lines_read = value, Stream::Callback(ptr) => ptr.lines_read = value, Stream::InputChannel(ptr) => ptr.lines_read = value, + Stream::PipeReader(ptr) => ptr.lines_read = value, + Stream::PipeWriter(_) => {} } } @@ -839,6 +855,8 @@ impl Stream { Stream::StandardError(ptr) => ptr.lines_read, Stream::Callback(ptr) => ptr.lines_read, Stream::InputChannel(ptr) => ptr.lines_read, + Stream::PipeReader(ptr) => ptr.lines_read, + Stream::PipeWriter(_) => 0, } } } @@ -856,6 +874,8 @@ impl CharRead for Stream { Stream::StaticString(src) => (*src).peek_char(), Stream::Byte(cursor) => (*cursor).peek_char(), Stream::InputChannel(cursor) => (*cursor).peek_char(), + Stream::PipeReader(cursor) => (*cursor).peek_char(), + #[cfg(feature = "http")] Stream::HttpWrite(_) => Some(Err(std::io::Error::new( ErrorKind::PermissionDenied, @@ -865,7 +885,8 @@ impl CharRead for Stream { | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::Null(_) - | Stream::Callback(_) => Some(Err(std::io::Error::new( + | Stream::Callback(_) + | Stream::PipeWriter(_) => Some(Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::ReadFromOutputStream, ))), @@ -884,6 +905,7 @@ impl CharRead for Stream { Stream::StaticString(src) => (*src).read_char(), Stream::Byte(cursor) => (*cursor).read_char(), Stream::InputChannel(cursor) => (*cursor).read_char(), + Stream::PipeReader(cursor) => (*cursor).read_char(), #[cfg(feature = "http")] Stream::HttpWrite(_) => Some(Err(std::io::Error::new( ErrorKind::PermissionDenied, @@ -893,7 +915,8 @@ impl CharRead for Stream { | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::Null(_) - | Stream::Callback(_) => Some(Err(std::io::Error::new( + | Stream::Callback(_) + | Stream::PipeWriter(_) => Some(Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::ReadFromOutputStream, ))), @@ -911,13 +934,15 @@ impl CharRead for Stream { Stream::Readline(rl_stream) => rl_stream.put_back_char(c), Stream::StaticString(src) => src.put_back_char(c), Stream::Byte(cursor) => cursor.put_back_char(c), + Stream::PipeReader(cursor) => cursor.put_back_char(c), #[cfg(feature = "http")] Stream::HttpWrite(_) => {} Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::Null(_) - | Stream::Callback(_) => {} + | Stream::Callback(_) + | Stream::PipeWriter(_) => {} Stream::InputChannel(_) => {} } } @@ -934,13 +959,15 @@ impl CharRead for Stream { Stream::StaticString(ref mut src) => src.consume(nread), Stream::Byte(ref mut cursor) => cursor.consume(nread), Stream::InputChannel(ref mut cursor) => cursor.consume(nread), + Stream::PipeReader(ref mut cursor) => cursor.consume(nread), #[cfg(feature = "http")] Stream::HttpWrite(_) => {} Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::Null(_) - | Stream::Callback(_) => {} + | Stream::Callback(_) + | Stream::PipeWriter(_) => {} } } } @@ -959,6 +986,7 @@ impl Read for Stream { Stream::StaticString(src) => (*src).read(buf), Stream::Byte(cursor) => (*cursor).read(buf), Stream::InputChannel(cursor) => (*cursor).read(buf), + Stream::PipeReader(cursor) => (*cursor).read(buf), #[cfg(feature = "http")] Stream::HttpWrite(_) => Err(std::io::Error::new( ErrorKind::PermissionDenied, @@ -967,7 +995,8 @@ impl Read for Stream { Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) - | Stream::Callback(_) => Err(std::io::Error::new( + | Stream::Callback(_) + | Stream::PipeWriter(_) => Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::ReadFromOutputStream, )), @@ -989,6 +1018,7 @@ impl Write for Stream { Stream::StandardError(stream) => stream.write(buf), #[cfg(feature = "http")] Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf), + Stream::PipeWriter(ref mut stream) => stream.get_mut().write(buf), #[cfg(feature = "http")] Stream::HttpRead(_) => Err(std::io::Error::new( ErrorKind::PermissionDenied, @@ -998,7 +1028,8 @@ impl Write for Stream { Stream::StaticString(_) | Stream::InputChannel(_) | Stream::Readline(_) - | Stream::InputFile(..) => Err(std::io::Error::new( + | Stream::InputFile(..) + | Stream::PipeReader(_) => Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::WriteToInputStream, )), @@ -1015,6 +1046,7 @@ impl Write for Stream { Stream::Callback(ref mut callback_stream) => callback_stream.stream.get_mut().flush(), Stream::StandardError(stream) => stream.stream.flush(), Stream::StandardOutput(stream) => stream.stream.flush(), + Stream::PipeWriter(ref mut stream) => stream.stream.get_mut().flush(), #[cfg(feature = "http")] Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(), #[cfg(feature = "http")] @@ -1026,7 +1058,8 @@ impl Write for Stream { Stream::StaticString(_) | Stream::InputChannel(_) | Stream::Readline(_) - | Stream::InputFile(_) => Err(std::io::Error::new( + | Stream::InputFile(_) + | Stream::PipeReader(_) => Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::FlushToInputStream, )), @@ -1192,6 +1225,8 @@ impl Stream { Stream::StandardError(stream) => stream.past_end_of_stream, Stream::Callback(stream) => stream.past_end_of_stream, Stream::InputChannel(stream) => stream.past_end_of_stream, + Stream::PipeReader(stream) => stream.past_end_of_stream, + Stream::PipeWriter(stream) => stream.past_end_of_stream, } } @@ -1220,6 +1255,8 @@ impl Stream { Stream::StandardError(stream) => stream.past_end_of_stream = value, Stream::Callback(stream) => stream.past_end_of_stream = value, Stream::InputChannel(stream) => stream.past_end_of_stream = value, + Stream::PipeReader(stream) => stream.past_end_of_stream = value, + Stream::PipeWriter(stream) => stream.past_end_of_stream = value, } } @@ -1330,7 +1367,8 @@ impl Stream { | Stream::InputChannel(_) | Stream::Readline(_) | Stream::StaticString(_) - | Stream::InputFile(..) => atom!("read"), + | Stream::InputFile(..) + | Stream::PipeReader(_) => atom!("read"), Stream::NamedTcp(..) => atom!("read_append"), Stream::OutputFile(file) if file.is_append => atom!("append"), #[cfg(feature = "http")] @@ -1338,7 +1376,8 @@ impl Stream { Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) - | Stream::Callback(_) => { + | Stream::Callback(_) + | Stream::PipeWriter(_) => { atom!("write") } Stream::Null(_) => atom!(""), @@ -1372,6 +1411,20 @@ impl Stream { )) } + pub(crate) fn from_pipe_writer(writer: io::PipeWriter, arena: &mut Arena) -> Stream { + Stream::PipeWriter(arena_alloc!( + ManuallyDrop::new(StreamLayout::new(CharReader::new(writer))), + arena + )) + } + + pub(crate) fn from_pipe_reader(reader: io::PipeReader, arena: &mut Arena) -> Stream { + Stream::PipeReader(arena_alloc!( + ManuallyDrop::new(StreamLayout::new(CharReader::new(reader))), + arena + )) + } + #[inline] pub(crate) fn from_tcp_stream(address: Atom, tcp_stream: TcpStream, arena: &mut Arena) -> Self { tcp_stream.set_read_timeout(None).unwrap(); @@ -1512,6 +1565,16 @@ impl Stream { Ok(()) } + Stream::PipeReader(mut stream) => { + stream.drop_payload(); + Ok(()) + } + + Stream::PipeWriter(mut stream) => { + stream.drop_payload(); + Ok(()) + } + Stream::Null(_) => Ok(()), Stream::Readline(_) | Stream::StandardOutput(_) | Stream::StandardError(_) => { diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 8c0eee0a..7e448e03 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -56,6 +56,7 @@ use std::net::{SocketAddr, ToSocketAddrs}; use std::net::{TcpListener, TcpStream}; use std::num::NonZeroU32; use std::process; +use std::process::Stdio; #[cfg(feature = "http")] use std::str::FromStr; #[cfg(feature = "http")] @@ -8393,6 +8394,173 @@ impl Machine { }; } + pub(crate) fn process_create(&mut self) -> CallResult { + fn stub_gen() -> Vec { + functor_stub(atom!("process_create"), 3) + } + + let exe_r = self.deref_register(1); + let args_r = self.deref_register(2); + let stdin_r = self.deref_register(3); + let stdout_r = self.deref_register(4); + let stderr_r = self.deref_register(5); + let env_r = self.deref_register(6); + let cwd_r = self.deref_register(7); + let pid_r = self.deref_register(8); + + let exe = self.machine_st.value_to_str_like(exe_r).unwrap(); + + let args = self + .machine_st + .try_from_list(args_r, stub_gen) + .unwrap() + .into_iter() + .map(|arg| { + self.machine_st + .value_to_str_like(arg) + .unwrap() + .as_str() + .to_string() + }) + .collect::>(); + + let stdin_args = self.machine_st.try_from_list(stdin_r, stub_gen)?; + let stdin = self.handle_input_stream(stdin_args)?; + + let stdout_args = self.machine_st.try_from_list(stdout_r, stub_gen)?; + let stdout = self.handle_output_stream(stdout_args)?; + + let stderr_args = self.machine_st.try_from_list(stderr_r, stub_gen)?; + let stderr = self.handle_output_stream(stderr_args)?; + + let env_args = self.machine_st.try_from_list(env_r, stub_gen)?; + + let clear_env = match env_args[0].to_atom() { + Some(atom!("env")) => true, + Some(atom!("environment")) => false, + _ => panic!("Invalid value for clear_env"), + }; + + let env_names = self.machine_st.try_from_list(env_args[1], stub_gen)?; + let env_values = self.machine_st.try_from_list(env_args[2], stub_gen)?; + + let envs = env_names + .into_iter() + .zip(env_values) + .map(|(name, value)| { + let name = self + .machine_st + .value_to_str_like(name) + .unwrap() + .as_str() + .to_string(); + let value = self + .machine_st + .value_to_str_like(value) + .unwrap() + .as_str() + .to_string(); + (name, value) + }) + .collect::>(); + + let cwd = self.machine_st.value_to_str_like(cwd_r); + + let mut command = std::process::Command::new(&*exe.as_str()); + command.args(args); + + if let Some(cwd) = cwd { + command.current_dir(&*cwd.as_str()); + } + + if clear_env { + command.env_clear(); + } + + command + .envs(envs) + .stdin(stdin) + .stdout(stdout) + .stderr(stderr); + + match command.spawn() { + Ok(child) => { + self.machine_st + .unify_fixnum(Fixnum::build_with(child.id()), pid_r); + Ok(()) + } + Err(_) => { + self.machine_st.fail = true; + Ok(()) + } + } + } + + fn handle_output_stream(&mut self, args: Vec) -> Result { + Ok(match args[0].to_atom() { + Some(atom!("std")) => Stdio::inherit(), + Some(atom!("null")) => Stdio::null(), + Some(atom!("pipe")) => { + // TODO handler Err + let (reader, writer) = std::io::pipe().unwrap(); + + let stream = Stream::from_pipe_reader(reader, &mut self.machine_st.arena); + + self.indices + .add_stream(stream, atom!("process_create"), 3) + .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + + self.machine_st + .bind(args[2].as_var().unwrap(), stream.into()); + + Stdio::from(writer) + } + Some(atom!("file")) => { + let path = self.machine_st.value_to_str_like(args[1]).unwrap(); + + // TODO handler Err + let file = std::fs::File::open(&*path.as_str()).unwrap(); + Stdio::from(file) + } + _ => { + panic!("Invalid stdin tag") + } + }) + } + + fn handle_input_stream(&mut self, args: Vec) -> Result { + Ok(match args[0].to_atom() { + Some(atom!("std")) => Stdio::inherit(), + Some(atom!("null")) => Stdio::null(), + Some(atom!("pipe")) => { + // TODO handler Err + let (reader, writer) = std::io::pipe().unwrap(); + + let stream = Stream::from_pipe_writer(writer, &mut self.machine_st.arena); + + self.indices + .add_stream(stream, atom!("process_create"), 3) + .map_err(|stub_gen| stub_gen(&mut self.machine_st)) + .unwrap(); + + self.machine_st + .bind(args[2].as_var().unwrap(), stream.into()); + + Stdio::from(reader) + } + Some(atom!("file")) => { + let path = self.machine_st.value_to_str_like(args[1]).unwrap(); + + // TODO handler Err + let file = std::fs::File::open(&*path.as_str()).unwrap(); + Stdio::from(file) + } + _ => { + panic!("Invalid stdin tag") + } + }) + } + #[inline(always)] pub(crate) fn chars_base64(&mut self) -> CallResult { let padding = cell_as_atom!(self.deref_register(3)); From d79ece24974ab2a175d4af1aab5870055686829a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 19 Jul 2025 21:00:36 +0200 Subject: [PATCH 088/122] fix indices --- src/machine/system_calls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 7e448e03..51092f64 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8441,8 +8441,8 @@ impl Machine { _ => panic!("Invalid value for clear_env"), }; - let env_names = self.machine_st.try_from_list(env_args[1], stub_gen)?; - let env_values = self.machine_st.try_from_list(env_args[2], stub_gen)?; + let env_names = self.machine_st.try_from_list(env_args[0], stub_gen)?; + let env_values = self.machine_st.try_from_list(env_args[1], stub_gen)?; let envs = env_names .into_iter() From 003e9d461008b4d7249639694c657e4faa0c3e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 19 Jul 2025 21:33:19 +0200 Subject: [PATCH 089/122] get it working --- src/lib/process.pl | 9 +++++---- src/machine/system_calls.rs | 19 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index e712bd69..f0a0a819 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -6,7 +6,6 @@ process_create(Exe, Args, Options) :- must_be(chars, Exe), - must_be(list(chars), Args), must_be(list, Options), check_option(Sin, find_stdio(Sin, stdin, Options), valid_stdio, [std], Stdin), check_option(Sout, find_stdio(Sout, stdout, Options), valid_stdio, [std], Stdout), @@ -35,10 +34,12 @@ valid_stdio([null]). valid_stdio([pipe, Stream]) :- must_be(var, Stream). valid_stdio([file, Path]) :- must_be(chars, Path). -find_env([env, E], Options) :- member(env(E), Options). -find_env([environment, E], Options) :- member(environment(E), Options). +find_env([env, ME], Options) :- member(env(E), Options), maplist(assign_to_list, E, ME). +find_env([environment, ME], Options) :- member(environment(E), Options), maplist(assign_to_list, E, ME). -valid_cwd(Cwd) :- must_be(chars, Cwd). +assign_to_list(N=V, [N,v]). + +valid_cwd(Cwd). valid_env([env, E]) :- valid_env_(E). valid_env([environment, E]) :- valid_env_(E). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 51092f64..63aabd8b 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8441,28 +8441,27 @@ impl Machine { _ => panic!("Invalid value for clear_env"), }; - let env_names = self.machine_st.try_from_list(env_args[0], stub_gen)?; - let env_values = self.machine_st.try_from_list(env_args[1], stub_gen)?; - - let envs = env_names + let envs = self + .machine_st + .try_from_list(env_args[1], stub_gen)? .into_iter() - .zip(env_values) - .map(|(name, value)| { + .map(|entry| { + let entry = self.machine_st.try_from_list(entry, stub_gen)?; let name = self .machine_st - .value_to_str_like(name) + .value_to_str_like(entry[0]) .unwrap() .as_str() .to_string(); let value = self .machine_st - .value_to_str_like(value) + .value_to_str_like(entry[1]) .unwrap() .as_str() .to_string(); - (name, value) + Ok((name, value)) }) - .collect::>(); + .collect::, MachineStub>>()?; let cwd = self.machine_st.value_to_str_like(cwd_r); From 2b052bf8dd8aa2b00396e9e1244627b3bbfa916d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 19 Jul 2025 21:44:28 +0200 Subject: [PATCH 090/122] fix more things --- src/lib/process.pl | 5 +++-- src/machine/system_calls.rs | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index f0a0a819..f20e225a 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -6,6 +6,7 @@ process_create(Exe, Args, Options) :- must_be(chars, Exe), + must_be(list(chars), Args), must_be(list, Options), check_option(Sin, find_stdio(Sin, stdin, Options), valid_stdio, [std], Stdin), check_option(Sout, find_stdio(Sout, stdout, Options), valid_stdio, [std], Stdout), @@ -37,9 +38,9 @@ valid_stdio([file, Path]) :- must_be(chars, Path). find_env([env, ME], Options) :- member(env(E), Options), maplist(assign_to_list, E, ME). find_env([environment, ME], Options) :- member(environment(E), Options), maplist(assign_to_list, E, ME). -assign_to_list(N=V, [N,v]). +assign_to_list(N=V, [N,V]). -valid_cwd(Cwd). +valid_cwd(Cwd) :- var(Cwd) -> true ; must_be(chars). valid_env([env, E]) :- valid_env_(E). valid_env([environment, E]) :- valid_env_(E). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 63aabd8b..d48ad555 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8510,7 +8510,7 @@ impl Machine { .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; self.machine_st - .bind(args[2].as_var().unwrap(), stream.into()); + .bind(args[1].as_var().unwrap(), stream.into()); Stdio::from(writer) } @@ -8539,11 +8539,10 @@ impl Machine { self.indices .add_stream(stream, atom!("process_create"), 3) - .map_err(|stub_gen| stub_gen(&mut self.machine_st)) - .unwrap(); + .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; self.machine_st - .bind(args[2].as_var().unwrap(), stream.into()); + .bind(args[1].as_var().unwrap(), stream.into()); Stdio::from(reader) } From 82e989f63142fbbe19a8b772f5123b18aba0e7e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 19 Jul 2025 22:56:51 +0200 Subject: [PATCH 091/122] add comments and try to fix binding the child process pid --- src/machine/system_calls.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index d48ad555..ecffbdb7 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8399,13 +8399,19 @@ impl Machine { functor_stub(atom!("process_create"), 3) } + // String let exe_r = self.deref_register(1); + // [String,...] let args_r = self.deref_register(2); + // [std] | [null] | [pipe, Var] | [file, String] let stdin_r = self.deref_register(3); let stdout_r = self.deref_register(4); let stderr_r = self.deref_register(5); + // [env | environment, [[String, String],...]] let env_r = self.deref_register(6); + // Var | String let cwd_r = self.deref_register(7); + // Var let pid_r = self.deref_register(8); let exe = self.machine_st.value_to_str_like(exe_r).unwrap(); @@ -8484,11 +8490,16 @@ impl Machine { match command.spawn() { Ok(child) => { - self.machine_st - .unify_fixnum(Fixnum::build_with(child.id()), pid_r); + let pid = child.id(); + self.machine_st.bind( + pid_r.as_var().unwrap(), + fixnum_as_cell!(Fixnum::build_with(pid)), + ); Ok(()) } - Err(_) => { + Err(err) => { + // TODO give better error indication + dbg!(err); self.machine_st.fail = true; Ok(()) } From 6c7833b9c7452eef4fd854b379eb2a8a0556bedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 00:51:50 +0200 Subject: [PATCH 092/122] restructure option parsing --- src/lib/process.pl | 102 +++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 36 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index f20e225a..6215355f 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -2,53 +2,83 @@ :- use_module(library(error)). :- use_module(library(iso_ext)). -:- use_module(library(lists), [append/3, member/2]). +:- use_module(library(lists), [append/3, member/2, maplist/2, maplist/3, select/3]). process_create(Exe, Args, Options) :- must_be(chars, Exe), - must_be(list(chars), Args), + must_be(list, Args), + maplist(must_be(chars), Args), must_be(list, Options), - check_option(Sin, find_stdio(Sin, stdin, Options), valid_stdio, [std], Stdin), - check_option(Sout, find_stdio(Sout, stdout, Options), valid_stdio, [std], Stdout), - check_option(Serr, find_stdio(Serr, stderr, Options), valid_stdio, [std], Stderr), - check_option(Envs, find_env(Envs, Options), valid_env, [environment, []], EnvVars), - check_option(P, member(process(P), Options), valid_pid, _, Pid), - check_option(C, member(cwd(C), Options), valid_cwd, _, Cwd), - '$process_create'(Exe, Args, Stdin, Stdout, Stderr, EnvVars, Cwd, Pid). + must_be_known_options([stdin, stdout, stderr, env, environment, pid, cwd], [], Options), + check_options( + [ + ([stdin], valid_stdio, stdin(std), stdin(Stdin)), + ([stdout], valid_stdio, stdout(std), stdout(Stdout)), + ([stderr], valid_stdio, stderr(std), stderr(Stderr)), + ([env, environment], valid_env, environment([]), Env), + ([pid], valid_pid, pid(_), pid(Pid)), + ([cwd], valid_cwd, cwd(_), cwd(Cwd)) + ], + Options + ), + Stdin =.. Stdin1, + Stdout =.. Stdout1, + Stderr =.. Stderr1, + simplify_env(Env, Env1), + '$process_create'(Exe, Args, Stdin1, Stdout1, Stderr1, Env1, Cwd, Pid). +must_be_known_options(_, _, []). +must_be_known_options(Valid, Found, [X|XS]) :- + X =.. [Option|_], + ( + member(Option, Found) -> throw(error(duplicate_option, process_create/3, Option)) ; + member(Option, Valid) -> true ; + throw(error(invalid_option, process_create/3, Option)) + ), + must_be_known_options(Valid, [Option | Found], XS). -check_option(Template, Goal, Pred, Default, Choice) :- - findall(Template, Goal, Solutions), - check_option_(Solutions, Pred, Default, Choice). - -check_option_([] , Pred , Default , Default ) :- call(Pred, Default). -check_option_([Choice] , Pred , _ , Choice ) :- call(Pred, Choice). -check_option_([X1,X2|Xs], _ , _ , _ ) :- throw(error(duplicate_option, process_create/3, [X1, X2 | Xs])). +check_options([], _). +check_options([X | XS], Options) :- + (Kinds, Pred, Default, Choice) = X, + findall(P, find_option(Kinds, P, Options), Solutions), + ( + Solutions = [] -> Choice = Default; + Solutions = [Provided] -> call(Pred, Provided), Choice = Provided ; + throw(error(duplicate_option, process_create/3, Solutions)) + ), + check_options(XS, Options). -find_stdio([std], Kind, Options ) :- Elem =.. [Kind, std], member(Elem, Options). -find_stdio([null], Kind, Options ) :- Elem =.. [Kind, null], member(Elem, Options). -find_stdio([pipe, Stream], Kind, Options) :- Elem =.. [Kind, pipe(Stream)], member(Elem, Options). -find_stdio([file, Path], Kind, Options ) :- Elem =.. [Kind, file(Path)], member(Elem, Options). +find_option([Kind|_], Found, Options) :- Found =.. [Kind,_], member(Found, Options). +find_option([_|Kinds], Found, Options) :- find_option(Kinds, Found, Options). -valid_stdio([std]). -valid_stdio([null]). -valid_stdio([pipe, Stream]) :- must_be(var, Stream). -valid_stdio([file, Path]) :- must_be(chars, Path). +valid_stdio(IO) :- IO =.. [_, Arg], + ( + valid_stdio_(Arg) -> true ; + throw(error(invalid_stdio, process_create/3, Arg)) + ). -find_env([env, ME], Options) :- member(env(E), Options), maplist(assign_to_list, E, ME). -find_env([environment, ME], Options) :- member(environment(E), Options), maplist(assign_to_list, E, ME). +valid_stdio_(std). +valid_stdio_(null). +valid_stdio_(pipe(Stream)) :- must_be(var, Stream). +valid_stdio_(file(Path)) :- must_be(chars, Path). -assign_to_list(N=V, [N,V]). - -valid_cwd(Cwd) :- var(Cwd) -> true ; must_be(chars). - -valid_env([env, E]) :- valid_env_(E). -valid_env([environment, E]) :- valid_env_(E). +valid_env(env(E)) :- valid_env_(E). +valid_env(environment(E)) :- valid_env_(E). valid_env_([]). -valid_env_([N=V|Es]) :- - must_be(chars, N), +valid_env_([E| ES]) :- + ( + E =.. [=, N, V] -> true ; + throw(error(invalid_env_entry, process_create/3, E)) + ), + must_be(chars, N), must_be(chars, V), - valid_env_(Es). + valid_env_(ES). -valid_pid(Pid) :- must_be(var, Pid). +valid_pid(pid(Pid)) :- must_be(var, Pid). +valid_cwd(cwd(Cwd)) :- must_be(chars, Cwd). + +simplify_env(E, [Kind, Envs1]) :- E =.. [Kind, Envs], simplify_env_(Envs, Envs1). + +simplify_env_([],[]). +simplify_env_([N=V|E],[[N, V]|E1]) :- simplify_env_(E, E1). From 183761eba4b12b9f352655014bdc7b87d479ac24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 01:25:16 +0200 Subject: [PATCH 093/122] adjust default cwd --- src/lib/process.pl | 2 +- src/machine/system_calls.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 6215355f..06e82a29 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -17,7 +17,7 @@ process_create(Exe, Args, Options) :- ([stderr], valid_stdio, stderr(std), stderr(Stderr)), ([env, environment], valid_env, environment([]), Env), ([pid], valid_pid, pid(_), pid(Pid)), - ([cwd], valid_cwd, cwd(_), cwd(Cwd)) + ([cwd], valid_cwd, cwd("."), cwd(Cwd)) ], Options ), diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index ecffbdb7..1ec6c988 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8409,7 +8409,7 @@ impl Machine { let stderr_r = self.deref_register(5); // [env | environment, [[String, String],...]] let env_r = self.deref_register(6); - // Var | String + // String ("." for keep current cwd) let cwd_r = self.deref_register(7); // Var let pid_r = self.deref_register(8); @@ -8469,12 +8469,12 @@ impl Machine { }) .collect::, MachineStub>>()?; - let cwd = self.machine_st.value_to_str_like(cwd_r); + let cwd = self.machine_st.value_to_str_like(cwd_r).unwrap(); let mut command = std::process::Command::new(&*exe.as_str()); command.args(args); - if let Some(cwd) = cwd { + if &*cwd.as_str() != "." { command.current_dir(&*cwd.as_str()); } From 129c80bf16b3a20237b8bfb0952a15d932b98020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 01:52:34 +0200 Subject: [PATCH 094/122] undo changes to error.pl --- src/lib/error.pl | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/lib/error.pl b/src/lib/error.pl index 0eb2a6d4..67df8a32 100644 --- a/src/lib/error.pl +++ b/src/lib/error.pl @@ -82,9 +82,6 @@ must_be_(octet_chars, Cs) :- ; true ). must_be_(list, Term) :- check_(error:ilist, list, Term). -must_be_(list(Elem), Term) :- - must_be_(list, Term), - check_all(Elem, Term). must_be_(type, Term) :- check_(error:type, type, Term). must_be_(boolean, Term) :- check_(error:boolean, boolean, Term). must_be_(pair, Term) :- check_(error:pair, pair, Term). @@ -99,12 +96,10 @@ must_be_(term, Term) :- % We cannot use maplist(must_be(character), Cs), because library(lists) % uses library(error), so importing it would create a cyclic dependency. -check_all(_, []). -check_all(Type, [Head| Tail]) :- - must_be(Type, Head), - check_all(Type, Tail). - -all_characters(Cs) :- check_all(character, Cs). +all_characters([]). +all_characters([C|Cs]) :- + must_be(character, C), + all_characters(Cs). check_(Pred, Type, Term) :- ( var(Term) -> instantiation_error(must_be/2) @@ -146,7 +141,6 @@ type(octet_character). type(octet_chars). type(chars). type(list). -type(list(Type)) :- type(Type). type(var). type(boolean). type(term). From e321f29b9c54bf7ee8e7eb4cddc6d406ec52ba92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 18:34:45 +0200 Subject: [PATCH 095/122] rename pid to process --- src/lib/process.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 06e82a29..52fc2b2a 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -16,7 +16,7 @@ process_create(Exe, Args, Options) :- ([stdout], valid_stdio, stdout(std), stdout(Stdout)), ([stderr], valid_stdio, stderr(std), stderr(Stderr)), ([env, environment], valid_env, environment([]), Env), - ([pid], valid_pid, pid(_), pid(Pid)), + ([process], valid_pid, process(_), process(Pid)), ([cwd], valid_cwd, cwd("."), cwd(Cwd)) ], Options From 8971809c838ca5deb782af63a4c073598b0fc137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 18:47:44 +0200 Subject: [PATCH 096/122] adjust errors --- src/lib/process.pl | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 52fc2b2a..645841ff 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -31,9 +31,9 @@ must_be_known_options(_, _, []). must_be_known_options(Valid, Found, [X|XS]) :- X =.. [Option|_], ( - member(Option, Found) -> throw(error(duplicate_option, process_create/3, Option)) ; + member(Option, Found) -> error(evaluation_error(duplicate_options), process_create/3); member(Option, Valid) -> true ; - throw(error(invalid_option, process_create/3, Option)) + domain_error(process_create_option, Option, process_create/3) ), must_be_known_options(Valid, [Option | Found], XS). @@ -44,7 +44,7 @@ check_options([X | XS], Options) :- ( Solutions = [] -> Choice = Default; Solutions = [Provided] -> call(Pred, Provided), Choice = Provided ; - throw(error(duplicate_option, process_create/3, Solutions)) + error(evaluation_error(confliction_options), process_create/3) ), check_options(XS, Options). @@ -54,7 +54,7 @@ find_option([_|Kinds], Found, Options) :- find_option(Kinds, Found, Options). valid_stdio(IO) :- IO =.. [_, Arg], ( valid_stdio_(Arg) -> true ; - throw(error(invalid_stdio, process_create/3, Arg)) + domain_error(process_create_option, Arg, process_create/3) ). valid_stdio_(std). @@ -62,14 +62,19 @@ valid_stdio_(null). valid_stdio_(pipe(Stream)) :- must_be(var, Stream). valid_stdio_(file(Path)) :- must_be(chars, Path). -valid_env(env(E)) :- valid_env_(E). -valid_env(environment(E)) :- valid_env_(E). +valid_env(env(E)) :- ( + valid_env_(E) -> true ; + domain_error(process_create_option, env(E), process_create/3) + ). +valid_env(environment(E)) :- ( + valid_env_(E) -> true ; + domain_error(process_create_option, environment(E), process_create/3) + ). valid_env_([]). valid_env_([E| ES]) :- ( E =.. [=, N, V] -> true ; - throw(error(invalid_env_entry, process_create/3, E)) ), must_be(chars, N), must_be(chars, V), From 43dd1587fbba71a12da27dbe19407c02119c2abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 20:11:12 +0200 Subject: [PATCH 097/122] handle some error cases and replace unwrap with expect --- src/machine/system_calls.rs | 84 +++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 1ec6c988..d09344b0 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8414,17 +8414,20 @@ impl Machine { // Var let pid_r = self.deref_register(8); - let exe = self.machine_st.value_to_str_like(exe_r).unwrap(); + let exe = self + .machine_st + .value_to_str_like(exe_r) + .expect("invalid values should have been rejected on the prolog side"); let args = self .machine_st .try_from_list(args_r, stub_gen) - .unwrap() + .expect("invalid values should have been rejected on the prolog side") .into_iter() .map(|arg| { self.machine_st .value_to_str_like(arg) - .unwrap() + .expect("invalid values should have been rejected on the prolog side") .as_str() .to_string() }) @@ -8456,20 +8459,23 @@ impl Machine { let name = self .machine_st .value_to_str_like(entry[0]) - .unwrap() + .expect("invalid values should have been rejected on the prolog side") .as_str() .to_string(); let value = self .machine_st .value_to_str_like(entry[1]) - .unwrap() + .expect("invalid values should have been rejected on the prolog side") .as_str() .to_string(); Ok((name, value)) }) .collect::, MachineStub>>()?; - let cwd = self.machine_st.value_to_str_like(cwd_r).unwrap(); + let cwd = self + .machine_st + .value_to_str_like(cwd_r) + .expect("invalid values should have been rejected on the prolog side"); let mut command = std::process::Command::new(&*exe.as_str()); command.args(args); @@ -8492,16 +8498,20 @@ impl Machine { Ok(child) => { let pid = child.id(); self.machine_st.bind( - pid_r.as_var().unwrap(), + pid_r + .as_var() + .expect("invalid values should have been rejected on the prolog side"), fixnum_as_cell!(Fixnum::build_with(pid)), ); Ok(()) } - Err(err) => { - // TODO give better error indication - dbg!(err); - self.machine_st.fail = true; - Ok(()) + Err(_) => { + let perm_error = self.machine_st.permission_error( + Permission::Create, + atom!("process"), + stub_gen(), + ); + Err(self.machine_st.error_form(perm_error, stub_gen())) } } } @@ -8511,8 +8521,16 @@ impl Machine { Some(atom!("std")) => Stdio::inherit(), Some(atom!("null")) => Stdio::null(), Some(atom!("pipe")) => { - // TODO handler Err - let (reader, writer) = std::io::pipe().unwrap(); + let (reader, writer) = match std::io::pipe() { + Ok(pipe_pair) => pipe_pair, + Err(_) => { + return Err(self.machine_st.open_permission_error( + atom!("anonymous_pipe"), + atom!("process_create"), + 3, + )); + } + }; let stream = Stream::from_pipe_reader(reader, &mut self.machine_st.arena); @@ -8528,12 +8546,20 @@ impl Machine { Some(atom!("file")) => { let path = self.machine_st.value_to_str_like(args[1]).unwrap(); - // TODO handler Err - let file = std::fs::File::open(&*path.as_str()).unwrap(); + let file = match std::fs::File::open(&*path.as_str()) { + Ok(file) => file, + Err(_) => { + return Err(self.machine_st.open_permission_error( + args[1], + atom!("process_create"), + 3, + )); + } + }; Stdio::from(file) } _ => { - panic!("Invalid stdin tag") + panic!("Invalid stdout tag") } }) } @@ -8543,8 +8569,16 @@ impl Machine { Some(atom!("std")) => Stdio::inherit(), Some(atom!("null")) => Stdio::null(), Some(atom!("pipe")) => { - // TODO handler Err - let (reader, writer) = std::io::pipe().unwrap(); + let (reader, writer) = match std::io::pipe() { + Ok(pipe_pair) => pipe_pair, + Err(_) => { + return Err(self.machine_st.open_permission_error( + atom!("anonymous_pipe"), + atom!("process_create"), + 3, + )); + } + }; let stream = Stream::from_pipe_writer(writer, &mut self.machine_st.arena); @@ -8560,8 +8594,16 @@ impl Machine { Some(atom!("file")) => { let path = self.machine_st.value_to_str_like(args[1]).unwrap(); - // TODO handler Err - let file = std::fs::File::open(&*path.as_str()).unwrap(); + let file = match std::fs::File::open(&*path.as_str()) { + Ok(file) => file, + Err(_) => { + return Err(self.machine_st.open_permission_error( + args[1], + atom!("process_create"), + 3, + )); + } + }; Stdio::from(file) } _ => { From 1ee4f7a55f966afb54dbd2598c4c18be6f887c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 21:08:44 +0200 Subject: [PATCH 098/122] store child process in machine state --- src/machine/machine_state.rs | 3 +++ src/machine/machine_state_impl.rs | 2 ++ src/machine/system_calls.rs | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 7663c952..6d583b00 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -20,9 +20,11 @@ use crate::parser::dashu::Integer; use indexmap::IndexMap; +use std::collections::BTreeMap; use std::convert::TryFrom; use std::fmt; use std::ops::{Index, IndexMut, Range}; +use std::process::Child; use std::sync::Arc; pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1]; @@ -97,6 +99,7 @@ pub struct MachineState { pub(crate) unify_fn: fn(&mut MachineState), pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue), pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool, + pub(crate) child_processes: BTreeMap, } impl fmt::Debug for MachineState { diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 3f14253d..e8b9d644 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -19,6 +19,7 @@ use crate::types::*; use indexmap::IndexSet; use std::cmp::Ordering; +use std::collections::BTreeMap; use std::convert::TryFrom; impl MachineState { @@ -67,6 +68,7 @@ impl MachineState { unify_fn: MachineState::unify, bind_fn: MachineState::bind, run_cleaners_fn: |_| false, + child_processes: BTreeMap::new(), } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index d09344b0..ff95d22b 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8497,12 +8497,16 @@ impl Machine { match command.spawn() { Ok(child) => { let pid = child.id(); + + self.machine_st.child_processes.insert(pid, child); + self.machine_st.bind( pid_r .as_var() .expect("invalid values should have been rejected on the prolog side"), fixnum_as_cell!(Fixnum::build_with(pid)), ); + Ok(()) } Err(_) => { From 97e2e5d7f0259fcd066269fd37a46f0b9f9c9dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 22:57:06 +0200 Subject: [PATCH 099/122] implement process_release/1, process_wait/2, process_wait/3, and process_kill/1 --- build/instructions_template.rs | 8 ++ src/lib/process.pl | 35 ++++++++- src/machine/dispatch.rs | 16 ++++ src/machine/machine_errors.rs | 12 +++ src/machine/system_calls.rs | 136 +++++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+), 4 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 6ea7a5a5..0c1320b1 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -539,6 +539,10 @@ enum SystemClauseType { Shell, #[strum_discriminants(strum(props(Arity = "8", Name = "$process_create")))] ProcessCreate, + #[strum_discriminants(strum(props(Arity = "3", Name = "$process_wait")))] + ProcessWait, + #[strum_discriminants(strum(props(Arity = "1", Name = "$process_kill")))] + ProcessKill, #[strum_discriminants(strum(props(Arity = "1", Name = "$pid")))] Pid, #[strum_discriminants(strum(props(Arity = "4", Name = "$chars_base64")))] @@ -1828,6 +1832,8 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallUnsetEnv | &Instruction::CallShell | &Instruction::CallProcessCreate | + &Instruction::CallProcessWait | + &Instruction::CallProcessKill | &Instruction::CallPid | &Instruction::CallCharsBase64 | &Instruction::CallDevourWhitespace | @@ -2067,6 +2073,8 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteUnsetEnv | &Instruction::ExecuteShell | &Instruction::ExecuteProcessCreate | + &Instruction::ExecuteProcessWait | + &Instruction::ExecuteProcessKill | &Instruction::ExecutePid | &Instruction::ExecuteCharsBase64 | &Instruction::ExecuteDevourWhitespace | diff --git a/src/lib/process.pl b/src/lib/process.pl index 645841ff..d7bd15f9 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -1,4 +1,10 @@ -:- module(process, [process_create/3]). +:- module(process, [ + process_create/3, + process_release/1, + process_wait/2, + process_wait/3, + process_kill/1 +]). :- use_module(library(error)). :- use_module(library(iso_ext)). @@ -27,6 +33,29 @@ process_create(Exe, Args, Options) :- simplify_env(Env, Env1), '$process_create'(Exe, Args, Stdin1, Stdout1, Stderr1, Env1, Cwd, Pid). +process_wait(Pid, Status) :- process_wait(Pid, Status, []). + +process_wait(Pid, Status, Options) :- + must_be(integer, Pid), + must_be_known_options([timeout], [], Options),check_options( + [ + ([timeout], valid_timeout, infinite, timeout(Timeout)) + ], + Options + ), + '$process_wait'(Pid, Exit, Timeout), + Exit = Status. + +valid_timeout(timeout(infinite)). +valid_timeout(timeout(0)). + +process_kill(Pid) :- + must_be(integer, Pid), + '$process_kill'(Pid). + +process_release(Pid) :- process_wait(Pid, _). + + must_be_known_options(_, _, []). must_be_known_options(Valid, Found, [X|XS]) :- X =.. [Option|_], @@ -73,9 +102,7 @@ valid_env(environment(E)) :- ( valid_env_([]). valid_env_([E| ES]) :- - ( - E =.. [=, N, V] -> true ; - ), + E =.. [=, N, V], must_be(chars, N), must_be(chars, V), valid_env_(ES). diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 36068ca2..66133c3c 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -4795,6 +4795,22 @@ impl Machine { try_or_throw!(self.machine_st, self.process_create()); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } + &Instruction::CallProcessWait => { + try_or_throw!(self.machine_st, self.process_wait()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteProcessWait => { + try_or_throw!(self.machine_st, self.process_wait()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallProcessKill => { + try_or_throw!(self.machine_st, self.process_kill()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteProcessKill => { + try_or_throw!(self.machine_st, self.process_kill()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } &Instruction::CallPid => { self.pid(); step_or_fail!(self, self.machine_st.p += 1); diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 4551991e..fec32ddd 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -405,6 +405,17 @@ impl MachineState { [atom_as_cell((atom!("stream"))), cell(culprit)] ); + MachineError { + stub, + location: None, + } + } + ExistenceError::Process(culprit) => { + let stub = functor!( + atom!("existence_error"), + [atom_as_cell((atom!("process"))), cell(culprit)] + ); + MachineError { stub, location: None, @@ -1003,6 +1014,7 @@ pub enum ExistenceError { }, SourceSink(HeapCellValue), Stream(HeapCellValue), + Process(HeapCellValue), } #[derive(Debug)] diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index ff95d22b..f40a6cbc 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8616,6 +8616,142 @@ impl Machine { }) } + pub(crate) fn process_wait(&mut self) -> CallResult { + fn stub_gen() -> Vec { + functor_stub(atom!("process_wait"), 2) + } + + // Pid + let pid_r = self.deref_register(1); + // Var | Status + let status_r = self.deref_register(2); + // timeout | 0 + let timeout_r = self.deref_register(3); + + let Some(pid) = pid_r + .to_fixnum() + .and_then(|elem| elem.get_num().try_into().ok()) + else { + let err = self + .machine_st + .existence_error(ExistenceError::Process(pid_r)); + return Err(self.machine_st.error_form(err, stub_gen())); + }; + let Some(mut child) = self.machine_st.child_processes.remove(&pid) else { + let err = self + .machine_st + .existence_error(ExistenceError::Process(pid_r)); + return Err(self.machine_st.error_form(err, stub_gen())); + }; + + let status = if let Some(atom) = timeout_r.to_atom() { + match atom { + atom!("infinite") => child.wait().map(Some), + _ => { + panic!("Invalid Timeout value") + } + } + } else if let Some(timeout) = timeout_r.to_fixnum() { + if timeout.get_num() == 0 { + child.try_wait() + } else { + panic!("Invalid Timeout value") + } + } else { + panic!("Invalid Timeout value") + }; + + match status { + Ok(None) => { + unify!(self.machine_st, status_r, atom_as_cell!(atom!("timeout"))); + Ok(()) + } + Ok(Some(exit_status)) => { + if let Some(exit_code) = exit_status.code() { + let mut writer = + Heap::functor_writer(functor!(atom!("exit"), [fixnum(exit_code)])); + + match writer(&mut self.machine_st.heap) { + Ok(loc) => { + unify!(self.machine_st, status_r, loc); + } + Err(resource_err_loc) => { + self.machine_st.throw_resource_error(resource_err_loc); + } + } + Ok(()) + } else { + #[cfg(unix)] + { + use std::os::unix::process::ExitStatusExt; + + if let Some(signal) = ExitStatusExt::signal(&exit_status) { + let mut writer = + Heap::functor_writer(functor!(atom!("signal"), [fixnum(signal)])); + + match writer(&mut self.machine_st.heap) { + Ok(loc) => { + unify!(self.machine_st, status_r, loc); + } + Err(resource_err_loc) => { + self.machine_st.throw_resource_error(resource_err_loc); + } + }; + Ok(()) + } else { + unify!(self.machine_st, status_r, atom_as_cell!(atom!("unknown"))); + Ok(()) + } + } + #[cfg(not(unix))] + { + unify!(self.machine_st, status_r, atom_as_cell!(atom!("unknown"))); + Ok(()) + } + } + } + Err(_) => { + let perm_error = self.machine_st.permission_error( + Permission::Modify, + atom!("process"), + stub_gen(), + ); + Err(self.machine_st.error_form(perm_error, stub_gen())) + } + } + } + + pub(crate) fn process_kill(&mut self) -> CallResult { + fn stub_gen() -> Vec { + functor_stub(atom!("process_kill"), 1) + } + + // Pid + let pid_r = self.deref_register(1); + let Some(pid) = pid_r + .to_fixnum() + .and_then(|elem| elem.get_num().try_into().ok()) + else { + let err = self + .machine_st + .existence_error(ExistenceError::Process(pid_r)); + return Err(self.machine_st.error_form(err, stub_gen())); + }; + let Some(mut child) = self.machine_st.child_processes.remove(&pid) else { + let err = self + .machine_st + .existence_error(ExistenceError::Process(pid_r)); + return Err(self.machine_st.error_form(err, stub_gen())); + }; + if child.kill().is_err() { + let perm_error = + self.machine_st + .permission_error(Permission::Modify, atom!("process"), stub_gen()); + return Err(self.machine_st.error_form(perm_error, stub_gen())); + } + Ok(()) + } + #[inline(always)] pub(crate) fn chars_base64(&mut self) -> CallResult { let padding = cell_as_atom!(self.deref_register(3)); From 746d4fd10663ce612b12b4727dfe331a348c5cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 23:04:01 +0200 Subject: [PATCH 100/122] make atom!() with a new value less annoying --- build/static_string_indexing.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build/static_string_indexing.rs b/build/static_string_indexing.rs index a577a517..7309f1cf 100644 --- a/build/static_string_indexing.rs +++ b/build/static_string_indexing.rs @@ -194,6 +194,7 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea macro_rules! atom { #((#static_str_keys) => { Atom { index: #indices } };)* + ($name:literal) => {compile_error!(concat!("unknown static atom ", $name))}; } pub static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! { From ff546a0f9ad39e7d3561063a081ada67833de32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 23:52:25 +0200 Subject: [PATCH 101/122] incorporate suggestion by triska --- src/lib/process.pl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index d7bd15f9..7a595c0b 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -101,8 +101,7 @@ valid_env(environment(E)) :- ( ). valid_env_([]). -valid_env_([E| ES]) :- - E =.. [=, N, V], +valid_env_([N=V|ES]) :- must_be(chars, N), must_be(chars, V), valid_env_(ES). From 7f233da10c6fef0b91de1d21e390e4165e55c9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 20 Jul 2025 23:53:01 +0200 Subject: [PATCH 102/122] fix timeout default value in process_wait/3 --- src/lib/process.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 7a595c0b..b17b3224 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -39,7 +39,7 @@ process_wait(Pid, Status, Options) :- must_be(integer, Pid), must_be_known_options([timeout], [], Options),check_options( [ - ([timeout], valid_timeout, infinite, timeout(Timeout)) + ([timeout], valid_timeout, timeout(infinite), timeout(Timeout)) ], Options ), From ca52c65902987b47d1fd392a2f81cd4529c5a431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Mon, 21 Jul 2025 00:06:03 +0200 Subject: [PATCH 103/122] don't remove the child on wait/kill - important for wait with timout(0) as we may want to try again until the process has realy exited. - make process_release release the process instead --- build/instructions_template.rs | 4 ++++ src/lib/process.pl | 4 +++- src/machine/dispatch.rs | 8 +++++++ src/machine/system_calls.rs | 43 ++++++++++++++++++++++++---------- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 0c1320b1..346e68af 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -543,6 +543,8 @@ enum SystemClauseType { ProcessWait, #[strum_discriminants(strum(props(Arity = "1", Name = "$process_kill")))] ProcessKill, + #[strum_discriminants(strum(props(Arity = "1", Name = "$process_release")))] + ProcessRelease, #[strum_discriminants(strum(props(Arity = "1", Name = "$pid")))] Pid, #[strum_discriminants(strum(props(Arity = "4", Name = "$chars_base64")))] @@ -1834,6 +1836,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallProcessCreate | &Instruction::CallProcessWait | &Instruction::CallProcessKill | + &Instruction::CallProcessRelease | &Instruction::CallPid | &Instruction::CallCharsBase64 | &Instruction::CallDevourWhitespace | @@ -2075,6 +2078,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteProcessCreate | &Instruction::ExecuteProcessWait | &Instruction::ExecuteProcessKill | + &Instruction::ExecuteProcessRelease | &Instruction::ExecutePid | &Instruction::ExecuteCharsBase64 | &Instruction::ExecuteDevourWhitespace | diff --git a/src/lib/process.pl b/src/lib/process.pl index b17b3224..358484c5 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -53,7 +53,9 @@ process_kill(Pid) :- must_be(integer, Pid), '$process_kill'(Pid). -process_release(Pid) :- process_wait(Pid, _). +process_release(Pid) :- + process_wait(Pid, _), + '$process_release'(Pid). must_be_known_options(_, _, []). diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 66133c3c..00396e23 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -4811,6 +4811,14 @@ impl Machine { try_or_throw!(self.machine_st, self.process_kill()); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } + &Instruction::CallProcessRelease => { + try_or_throw!(self.machine_st, self.process_release()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteProcessRelease => { + try_or_throw!(self.machine_st, self.process_release()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } &Instruction::CallPid => { self.pid(); step_or_fail!(self, self.machine_st.p += 1); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index f40a6cbc..a1eb15be 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8498,13 +8498,14 @@ impl Machine { Ok(child) => { let pid = child.id(); + dbg!(pid); + self.machine_st.child_processes.insert(pid, child); - self.machine_st.bind( - pid_r - .as_var() - .expect("invalid values should have been rejected on the prolog side"), - fixnum_as_cell!(Fixnum::build_with(pid)), + unify!( + self.machine_st, + pid_r, + fixnum_as_cell!(Fixnum::build_with(pid)) ); Ok(()) @@ -8637,7 +8638,7 @@ impl Machine { .existence_error(ExistenceError::Process(pid_r)); return Err(self.machine_st.error_form(err, stub_gen())); }; - let Some(mut child) = self.machine_st.child_processes.remove(&pid) else { + let Some(child) = self.machine_st.child_processes.get_mut(&pid) else { let err = self .machine_st .existence_error(ExistenceError::Process(pid_r)); @@ -8679,7 +8680,6 @@ impl Machine { self.machine_st.throw_resource_error(resource_err_loc); } } - Ok(()) } else { #[cfg(unix)] { @@ -8687,7 +8687,7 @@ impl Machine { if let Some(signal) = ExitStatusExt::signal(&exit_status) { let mut writer = - Heap::functor_writer(functor!(atom!("signal"), [fixnum(signal)])); + Heap::functor_writer(functor!(atom!("killed"), [fixnum(signal)])); match writer(&mut self.machine_st.heap) { Ok(loc) => { @@ -8696,19 +8696,17 @@ impl Machine { Err(resource_err_loc) => { self.machine_st.throw_resource_error(resource_err_loc); } - }; - Ok(()) + } } else { unify!(self.machine_st, status_r, atom_as_cell!(atom!("unknown"))); - Ok(()) } } #[cfg(not(unix))] { unify!(self.machine_st, status_r, atom_as_cell!(atom!("unknown"))); - Ok(()) } } + Ok(()) } Err(_) => { let perm_error = self.machine_st.permission_error( @@ -8737,7 +8735,7 @@ impl Machine { .existence_error(ExistenceError::Process(pid_r)); return Err(self.machine_st.error_form(err, stub_gen())); }; - let Some(mut child) = self.machine_st.child_processes.remove(&pid) else { + let Some(child) = self.machine_st.child_processes.get_mut(&pid) else { let err = self .machine_st .existence_error(ExistenceError::Process(pid_r)); @@ -8752,6 +8750,25 @@ impl Machine { Ok(()) } + pub(crate) fn process_release(&mut self) -> CallResult { + fn stub_gen() -> Vec { + functor_stub(atom!("process_release"), 1) + } + + let pid_r = self.deref_register(1); + let Some(pid) = pid_r + .to_fixnum() + .and_then(|elem| elem.get_num().try_into().ok()) + else { + let err = self + .machine_st + .existence_error(ExistenceError::Process(pid_r)); + return Err(self.machine_st.error_form(err, stub_gen())); + }; + self.machine_st.child_processes.remove(&pid); + Ok(()) + } + #[inline(always)] pub(crate) fn chars_base64(&mut self) -> CallResult { let padding = cell_as_atom!(self.deref_register(3)); From 87dbad2294641c2a4951f62add343128b142ae57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Mon, 21 Jul 2025 00:06:46 +0200 Subject: [PATCH 104/122] fix rename pid to process --- src/lib/process.pl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 358484c5..157aa520 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -15,14 +15,14 @@ process_create(Exe, Args, Options) :- must_be(list, Args), maplist(must_be(chars), Args), must_be(list, Options), - must_be_known_options([stdin, stdout, stderr, env, environment, pid, cwd], [], Options), + must_be_known_options([stdin, stdout, stderr, env, environment, process, cwd], [], Options), check_options( [ ([stdin], valid_stdio, stdin(std), stdin(Stdin)), ([stdout], valid_stdio, stdout(std), stdout(Stdout)), ([stderr], valid_stdio, stderr(std), stderr(Stderr)), ([env, environment], valid_env, environment([]), Env), - ([process], valid_pid, process(_), process(Pid)), + ([process], valid_process, process(_), process(Pid)), ([cwd], valid_cwd, cwd("."), cwd(Cwd)) ], Options @@ -108,7 +108,8 @@ valid_env_([N=V|ES]) :- must_be(chars, V), valid_env_(ES). -valid_pid(pid(Pid)) :- must_be(var, Pid). +valid_process(process(Pid)) :- must_be(var, Pid). + valid_cwd(cwd(Cwd)) :- must_be(chars, Cwd). simplify_env(E, [Kind, Envs1]) :- E =.. [Kind, Envs], simplify_env_(Envs, Envs1). From d2ffd4f4bf2bd82dbfcc3e378fd8a9da158ed299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Mon, 21 Jul 2025 00:25:34 +0200 Subject: [PATCH 105/122] adjust error for duplicate options --- src/lib/process.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 157aa520..54707b7c 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -62,7 +62,7 @@ must_be_known_options(_, _, []). must_be_known_options(Valid, Found, [X|XS]) :- X =.. [Option|_], ( - member(Option, Found) -> error(evaluation_error(duplicate_options), process_create/3); + member(Option, Found) -> domain_error(non_duplicate_process_create_options, process_create/3); member(Option, Valid) -> true ; domain_error(process_create_option, Option, process_create/3) ), From dc495f10f8469700bc90e9f8ab30b2a8c5f9cc0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 13:14:29 +0200 Subject: [PATCH 106/122] change behaviour in supposedly unreachable cases --- src/machine/machine_errors.rs | 9 +++++++++ src/machine/system_calls.rs | 9 ++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index fec32ddd..084c8a83 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -601,6 +601,15 @@ impl MachineState { } } + pub(super) fn unreachable_error(&self) -> MachineError { + let stub = functor!(atom!("system_error")); + + MachineError { + stub, + location: None, + } + } + #[cfg(feature = "ffi")] pub(super) fn ffi_error(&self, err: FFIError) -> MachineError { let error_atom = match err { diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index a1eb15be..214c6d3a 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8680,6 +8680,7 @@ impl Machine { self.machine_st.throw_resource_error(resource_err_loc); } } + Ok(()) } else { #[cfg(unix)] { @@ -8697,16 +8698,18 @@ impl Machine { self.machine_st.throw_resource_error(resource_err_loc); } } + Ok(()) } else { - unify!(self.machine_st, status_r, atom_as_cell!(atom!("unknown"))); + let err = self.machine_st.unreachable_error(); + Err(self.machine_st.error_form(err, stub_gen())) } } #[cfg(not(unix))] { - unify!(self.machine_st, status_r, atom_as_cell!(atom!("unknown"))); + let err = self.machine_st.unreachable_error(); + Err(self.machine_st.error_form(err, stub_gen())) } } - Ok(()) } Err(_) => { let perm_error = self.machine_st.permission_error( From 1120bcde29ef331e00c83bb13072b0ce71c18754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 13:30:56 +0200 Subject: [PATCH 107/122] add documentation --- src/lib/process.pl | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/lib/process.pl b/src/lib/process.pl index 54707b7c..603a3260 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -10,6 +10,37 @@ :- use_module(library(iso_ext)). :- use_module(library(lists), [append/3, member/2, maplist/2, maplist/3, select/3]). + +%% process_create(+Exe, +Args:list, +Options). +% +% Create a new process by executing the executable Exe and passing it the Arguments Args. +% +% Note: On windows please take note of [windows argument splitting](https://doc.rust-lang.org/std/process/index.html#windows-argument-splitting). +% +% Options is a list consisting of the following options: +% +% * `cwd(+Path)` Set the processes working directory to `Path` +% * `process(-Pid)` `Pid` will be assigned the spawned processes process id +% * `env(+List)` Don't inherit environment variables and set the variables defined in `List` +% * `environment(+List)` Inherit environment variables and set/override the variables defined in `List` +% * `stdin(Spec)`, `stdout(Spec)` or `stderr(Spec)` defines how to redirect the spawned processes io streams +% +% The elements of `List` in `env(List)`/`environment(List)` List must be string pairs using `=/2`. +% `env/1` and `environment/1` may not be both specified. +% +% The following stdio `Spec` are available: +% +% * `std` inherit the current processes original stdio streams (does currently not account for stdio being changed by `set_input` or `set_output`) +% * `file(+Path)` attach the strea to the file at `Path` +% * `null` discards writes and behaves as eof for read. Equivalent to using `file(/dev/null)` +% * `pipe(-Steam)` create a new pipe and assigne one end to the created process and the other end to `Stream` +% +% Specifying an option multiple times is an error, when an option is not specified the following defaults apply: +% +% - `cwd(".")` +% - `environment([])` +% - `stdin(std)`, `stdout(std)`, `stderr(std)` +% process_create(Exe, Args, Options) :- must_be(chars, Exe), must_be(list, Args), @@ -33,8 +64,32 @@ process_create(Exe, Args, Options) :- simplify_env(Env, Env1), '$process_create'(Exe, Args, Stdin1, Stdout1, Stderr1, Env1, Cwd, Pid). + +%% process_wait(+Pid, Status). +% +% See `process_create/3` with `Options = []` +% process_wait(Pid, Status) :- process_wait(Pid, Status, []). + +%% process_wait(+Pid, Status, Options). +% +% Wait for the child process with `Pid` to exit. +% +% Only works for processes spawned with `process_create/3` that have not yet been release with `process_release/1` +% +% When the process exits regulary `Status` will be unified with `exit(Exit)` where `Exit` is the processes exit code. +% When the process exits was killed `Status` will be unified with `killed(Signal)` where `Signal` is the signal number that killed the process. +% When the process doesn't exit before the timeout `Status` will be unified with `timeout`. +% +% `Options` is a a list of the following options +% +% * timeout(Timeout) supported values for `Timeout` are 0 or `infinite` +% +% Each options may be specified at most once, when an option is not specified the following defaults apply: +% +% - timeout(infinite) +% process_wait(Pid, Status, Options) :- must_be(integer, Pid), must_be_known_options([timeout], [], Options),check_options( @@ -49,10 +104,26 @@ process_wait(Pid, Status, Options) :- valid_timeout(timeout(infinite)). valid_timeout(timeout(0)). + +%% process_kill(+Pid). +% +% Kill the child process identified by `Pid`. +% On Unix this sends SIGKILL. +% +% Only works for processes spawned with `process_create/3` that have not yet been release with `process_release/1` +% process_kill(Pid) :- must_be(integer, Pid), '$process_kill'(Pid). +%% process_release(+Pid) +% +% release child process object of the process identified by `Pid` +% +% It's an error if +% * the `Pid` is not associated with a child process created by `process_create/3`, +% * the child project object has already been released +% process_release(Pid) :- process_wait(Pid, _), '$process_release'(Pid). From dc08a4ab11fcd9ee052215d4dae341e3346b91d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 18:21:00 +0200 Subject: [PATCH 108/122] get process_create working and add tests --- build/instructions_template.rs | 4 + src/arena.rs | 20 +++- src/heap_print.rs | 17 ++++ src/lib/lists.pl | 10 +- src/lib/process.pl | 70 +++++++------ src/machine/dispatch.rs | 8 ++ src/machine/machine_errors.rs | 2 + src/machine/machine_state.rs | 3 - src/machine/machine_state_impl.rs | 2 - src/machine/system_calls.rs | 148 ++++++++++++++++++---------- src/macros.rs | 6 ++ tests/scryer/cli/unix/process.md | 4 + tests/scryer/cli/windows/process.md | 4 + tests/scryer/main.rs | 16 ++- 14 files changed, 223 insertions(+), 91 deletions(-) create mode 100644 tests/scryer/cli/unix/process.md create mode 100644 tests/scryer/cli/windows/process.md diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 346e68af..1cf004b1 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -539,6 +539,8 @@ enum SystemClauseType { Shell, #[strum_discriminants(strum(props(Arity = "8", Name = "$process_create")))] ProcessCreate, + #[strum_discriminants(strum(props(Arity = "2", Name = "$process_id")))] + ProcessId, #[strum_discriminants(strum(props(Arity = "3", Name = "$process_wait")))] ProcessWait, #[strum_discriminants(strum(props(Arity = "1", Name = "$process_kill")))] @@ -1834,6 +1836,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::CallUnsetEnv | &Instruction::CallShell | &Instruction::CallProcessCreate | + &Instruction::CallProcessId | &Instruction::CallProcessWait | &Instruction::CallProcessKill | &Instruction::CallProcessRelease | @@ -2076,6 +2079,7 @@ fn generate_instruction_preface() -> TokenStream { &Instruction::ExecuteUnsetEnv | &Instruction::ExecuteShell | &Instruction::ExecuteProcessCreate | + &Instruction::ExecuteProcessId | &Instruction::ExecuteProcessWait | &Instruction::ExecuteProcessKill | &Instruction::ExecuteProcessRelease | diff --git a/src/arena.rs b/src/arena.rs index 2b312070..ee9dda20 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -20,6 +20,7 @@ use std::mem; use std::mem::ManuallyDrop; use std::net::TcpListener; use std::ops::{Deref, DerefMut}; +use std::process::Child; use std::ptr; use std::ptr::addr_of_mut; use std::ptr::NonNull; @@ -75,7 +76,8 @@ pub enum ArenaHeaderTag { HttpResponse = 0b1000010, PipeWriter = 0b1000011, Dropped = 0b1000100, - PipeReader = 0b1000101, + PipeReader = 0b1001001, + ChildProcess = 0b1001010, } #[bitfield] @@ -391,6 +393,19 @@ impl ArenaAllocated for HttpResponse { } } +impl ArenaAllocated for Child { + type Payload = ManuallyDrop; + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::ChildProcess + } +} +impl AllocateInArena for Child { + fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr { + Child::alloc(arena, ManuallyDrop::new(self)) + } +} + #[repr(C)] #[derive(Debug)] pub struct AllocSlab { @@ -556,6 +571,9 @@ unsafe fn drop_slab_in_place(value: NonNull, tag: ArenaHeaderTag) { ArenaHeaderTag::PipeWriter => { drop_typed_slab_in_place!(PipeWriter, value); } + ArenaHeaderTag::ChildProcess => { + drop_typed_slab_in_place!(Child, value); + } ArenaHeaderTag::NullStream => { unreachable!("NullStream is never arena allocated!"); } diff --git a/src/heap_print.rs b/src/heap_print.rs index 57fef895..2186c8ed 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1789,6 +1789,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { (ArenaHeaderTag::Dropped, _value) => { self.print_impromptu_atom(atom!("$dropped_value")); } + (ArenaHeaderTag::ChildProcess, process) => { + + let process_atom = atom!("$process"); + + if self.format_struct(max_depth, 1, process_atom) { + let atom = TokenOrRedirect::NumberFocus(max_depth, NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(process.id()))), op); + + let process_root = self.state_stack.pop().unwrap(); + + self.state_stack.pop(); + self.state_stack.pop(); + + self.state_stack.push(atom); + self.state_stack.push(TokenOrRedirect::Open); + self.state_stack.push(process_root); + } + } _ => { } ); diff --git a/src/lib/lists.pl b/src/lib/lists.pl index 3d1cc6a2..9c972f01 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -7,7 +7,7 @@ List manipulation predicates maplist/3, maplist/4, maplist/5, maplist/6, maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, nth0/4, nth1/3, nth1/4, sum_list/2, transpose/2, list_to_set/2, list_max/2, - list_min/2, permutation/2]). + list_min/2, permutation/2, filter/3]). /* Author: Mark Thom, Jan Wielemaker, and Richard O'Keefe Copyright (c) 2018-2021, Mark Thom @@ -538,3 +538,11 @@ perm([], []). perm(List, [First|Perm]) :- select(First, List, Rest), perm(Rest, Perm). + + +%% filter(+Predicate, ?Xs1 ?Xs2). +% +% Succeeds if Xs2 is the list of elements X from Xs1 for which call(Pred, X) succeeds. +% +filter(_, [], []). +filter(Pred, [X1|XS1], XS) :- call(Pred, X1) -> filter(Pred, XS1, XS2), XS = [X1|XS2] ; filter(Pred, XS1, XS). \ No newline at end of file diff --git a/src/lib/process.pl b/src/lib/process.pl index 603a3260..d66c2ea4 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -1,5 +1,6 @@ :- module(process, [ process_create/3, + process_id/2, process_release/1, process_wait/2, process_wait/3, @@ -8,7 +9,7 @@ :- use_module(library(error)). :- use_module(library(iso_ext)). -:- use_module(library(lists), [append/3, member/2, maplist/2, maplist/3, select/3]). +:- use_module(library(lists), [member/2, maplist/2, filter/3]). %% process_create(+Exe, +Args:list, +Options). @@ -20,7 +21,7 @@ % Options is a list consisting of the following options: % % * `cwd(+Path)` Set the processes working directory to `Path` -% * `process(-Pid)` `Pid` will be assigned the spawned processes process id +% * `process(-Process)` `Process` will be assigned a process handle for the spawned process % * `env(+List)` Don't inherit environment variables and set the variables defined in `List` % * `environment(+List)` Inherit environment variables and set/override the variables defined in `List` % * `stdin(Spec)`, `stdout(Spec)` or `stderr(Spec)` defines how to redirect the spawned processes io streams @@ -53,7 +54,7 @@ process_create(Exe, Args, Options) :- ([stdout], valid_stdio, stdout(std), stdout(Stdout)), ([stderr], valid_stdio, stderr(std), stderr(Stderr)), ([env, environment], valid_env, environment([]), Env), - ([process], valid_process, process(_), process(Pid)), + ([process], valid_uninit_process, process(_), process(Process)), ([cwd], valid_cwd, cwd("."), cwd(Cwd)) ], Options @@ -62,21 +63,27 @@ process_create(Exe, Args, Options) :- Stdout =.. Stdout1, Stderr =.. Stderr1, simplify_env(Env, Env1), - '$process_create'(Exe, Args, Stdin1, Stdout1, Stderr1, Env1, Cwd, Pid). + '$process_create'(Exe, Args, Stdin1, Stdout1, Stderr1, Env1, Cwd, Process). +%% process_id(+Process, -Pid). +% +process_id(Process, Pid) :- + valid_process(Process, process_id/2), + write(valid), nl, + must_be(var, Pid), + write(var), nl, + '$process_id'(Process, Pid). -%% process_wait(+Pid, Status). +%% process_wait(+Process, Status). % % See `process_create/3` with `Options = []` % -process_wait(Pid, Status) :- process_wait(Pid, Status, []). +process_wait(Process, Status) :- process_wait(Process, Status, []). -%% process_wait(+Pid, Status, Options). +%% process_wait(+Process, Status, Options). % -% Wait for the child process with `Pid` to exit. -% -% Only works for processes spawned with `process_create/3` that have not yet been release with `process_release/1` +% Wait for the process behind the process handle `Process` to exit. % % When the process exits regulary `Status` will be unified with `exit(Exit)` where `Exit` is the processes exit code. % When the process exits was killed `Status` will be unified with `killed(Signal)` where `Signal` is the signal number that killed the process. @@ -90,43 +97,42 @@ process_wait(Pid, Status) :- process_wait(Pid, Status, []). % % - timeout(infinite) % -process_wait(Pid, Status, Options) :- - must_be(integer, Pid), +process_wait(Process, Status, Options) :- + valid_process(Process, process_wait/3), must_be_known_options([timeout], [], Options),check_options( [ ([timeout], valid_timeout, timeout(infinite), timeout(Timeout)) ], Options ), - '$process_wait'(Pid, Exit, Timeout), + '$process_wait'(Process, Exit, Timeout), Exit = Status. valid_timeout(timeout(infinite)). valid_timeout(timeout(0)). -%% process_kill(+Pid). +%% process_kill(+Process). % -% Kill the child process identified by `Pid`. +% Kill the process using the process handle `Process`. % On Unix this sends SIGKILL. % % Only works for processes spawned with `process_create/3` that have not yet been release with `process_release/1` % -process_kill(Pid) :- - must_be(integer, Pid), - '$process_kill'(Pid). +process_kill(Process) :- + valid_process(Process, process_kill/1), + '$process_kill'(Process). -%% process_release(+Pid) +%% process_release(+Process) % -% release child process object of the process identified by `Pid` +% wait for the process to exit (if not already) and release process handle `Process` % -% It's an error if -% * the `Pid` is not associated with a child process created by `process_create/3`, -% * the child project object has already been released +% It's an error if `Process` is not a valid process handle % -process_release(Pid) :- - process_wait(Pid, _), - '$process_release'(Pid). +process_release(Process) :- + valid_process(Process, process_release/1), + process_wait(Process, _), + '$process_release'(Process). must_be_known_options(_, _, []). @@ -142,16 +148,16 @@ must_be_known_options(Valid, Found, [X|XS]) :- check_options([], _). check_options([X | XS], Options) :- (Kinds, Pred, Default, Choice) = X, - findall(P, find_option(Kinds, P, Options), Solutions), + filter(process:find_option(Kinds), Options, Solutions), ( Solutions = [] -> Choice = Default; Solutions = [Provided] -> call(Pred, Provided), Choice = Provided ; - error(evaluation_error(confliction_options), process_create/3) + error(evaluation_error(confliction_options, Solutions), process_create/3) ), check_options(XS, Options). -find_option([Kind|_], Found, Options) :- Found =.. [Kind,_], member(Found, Options). -find_option([_|Kinds], Found, Options) :- find_option(Kinds, Found, Options). +find_option([Kind|_], Found) :- Found =.. [Kind,_]. +find_option([_|Kinds], Found) :- find_option(Kinds, Found). valid_stdio(IO) :- IO =.. [_, Arg], ( @@ -179,7 +185,9 @@ valid_env_([N=V|ES]) :- must_be(chars, V), valid_env_(ES). -valid_process(process(Pid)) :- must_be(var, Pid). +valid_uninit_process(process(Process)) :- must_be(var, Process). + +valid_process(Process, Context) :- var(Process) -> instantiation_error(Context) ; true. valid_cwd(cwd(Cwd)) :- must_be(chars, Cwd). diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 00396e23..8a8921e6 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -4795,6 +4795,14 @@ impl Machine { try_or_throw!(self.machine_st, self.process_create()); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } + &Instruction::CallProcessId => { + try_or_throw!(self.machine_st, self.process_id()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteProcessId => { + try_or_throw!(self.machine_st, self.process_id()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } &Instruction::CallProcessWait => { try_or_throw!(self.machine_st, self.process_wait()); step_or_fail!(self, self.machine_st.p += 1); diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 084c8a83..c6836709 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -44,6 +44,7 @@ pub(crate) enum ValidType { // PredicateIndicator, // Variable TcpListener, + Process, } impl ValidType { @@ -67,6 +68,7 @@ impl ValidType { // ValidType::PredicateIndicator => atom!("predicate_indicator"), // ValidType::Variable => atom!("variable") ValidType::TcpListener => atom!("tcp_listener"), + ValidType::Process => atom!("process"), } } } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 6d583b00..7663c952 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -20,11 +20,9 @@ use crate::parser::dashu::Integer; use indexmap::IndexMap; -use std::collections::BTreeMap; use std::convert::TryFrom; use std::fmt; use std::ops::{Index, IndexMut, Range}; -use std::process::Child; use std::sync::Arc; pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1]; @@ -99,7 +97,6 @@ pub struct MachineState { pub(crate) unify_fn: fn(&mut MachineState), pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue), pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool, - pub(crate) child_processes: BTreeMap, } impl fmt::Debug for MachineState { diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index e8b9d644..3f14253d 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -19,7 +19,6 @@ use crate::types::*; use indexmap::IndexSet; use std::cmp::Ordering; -use std::collections::BTreeMap; use std::convert::TryFrom; impl MachineState { @@ -68,7 +67,6 @@ impl MachineState { unify_fn: MachineState::unify, bind_fn: MachineState::bind, run_cleaners_fn: |_| false, - child_processes: BTreeMap::new(), } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 214c6d3a..0fc6e35d 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -56,6 +56,7 @@ use std::net::{SocketAddr, ToSocketAddrs}; use std::net::{TcpListener, TcpStream}; use std::num::NonZeroU32; use std::process; +use std::process::Child; use std::process::Stdio; #[cfg(feature = "http")] use std::str::FromStr; @@ -8496,16 +8497,13 @@ impl Machine { match command.spawn() { Ok(child) => { - let pid = child.id(); - - dbg!(pid); - - self.machine_st.child_processes.insert(pid, child); + let child_process_alloc: TypedArenaPtr = + arena_alloc!(child, &mut self.machine_st.arena); unify!( self.machine_st, pid_r, - fixnum_as_cell!(Fixnum::build_with(pid)) + typed_arena_ptr_as_cell!(child_process_alloc) ); Ok(()) @@ -8617,44 +8615,84 @@ impl Machine { }) } + pub(crate) fn process_id(&mut self) -> CallResult { + fn stub_gen() -> Vec { + functor_stub(atom!("process_id"), 2) + } + + // Process + let process_r = self.deref_register(1); + // Pid + let pid_r = self.deref_register(2); + + let Some(ptr) = process_r.to_untyped_arena_ptr() else { + let err = self.machine_st.type_error(ValidType::Process, process_r); + return Err(self.machine_st.error_form(err, stub_gen())); + }; + + let process = match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::ChildProcess, child_process) => { + child_process + } + (ArenaHeaderTag::Dropped, _dropped) => { + let err = self.machine_st.existence_error(ExistenceError::Process(process_r)); + return Err(self.machine_st.error_form(err, stub_gen())); + } + _ => { + let err = self.machine_st.type_error(ValidType::Process, process_r); + return Err(self.machine_st.error_form(err, stub_gen())); + } + ); + + self.machine_st.bind( + pid_r.as_var().unwrap(), + fixnum_as_cell!(Fixnum::build_with(process.id())), + ); + + Ok(()) + } + pub(crate) fn process_wait(&mut self) -> CallResult { fn stub_gen() -> Vec { functor_stub(atom!("process_wait"), 2) } - // Pid - let pid_r = self.deref_register(1); + // Process + let process_r = self.deref_register(1); // Var | Status let status_r = self.deref_register(2); // timeout | 0 let timeout_r = self.deref_register(3); - let Some(pid) = pid_r - .to_fixnum() - .and_then(|elem| elem.get_num().try_into().ok()) - else { - let err = self - .machine_st - .existence_error(ExistenceError::Process(pid_r)); - return Err(self.machine_st.error_form(err, stub_gen())); - }; - let Some(child) = self.machine_st.child_processes.get_mut(&pid) else { - let err = self - .machine_st - .existence_error(ExistenceError::Process(pid_r)); + let Some(ptr) = process_r.to_untyped_arena_ptr() else { + let err = self.machine_st.type_error(ValidType::Process, process_r); return Err(self.machine_st.error_form(err, stub_gen())); }; + let mut process = match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::ChildProcess, child_process) => { + child_process + } + (ArenaHeaderTag::Dropped, _dropped) => { + let err = self.machine_st.existence_error(ExistenceError::Process(process_r)); + return Err(self.machine_st.error_form(err, stub_gen())); + } + _ => { + let err = self.machine_st.type_error(ValidType::Process, process_r); + return Err(self.machine_st.error_form(err, stub_gen())); + } + ); + let status = if let Some(atom) = timeout_r.to_atom() { match atom { - atom!("infinite") => child.wait().map(Some), + atom!("infinite") => process.wait().map(Some), _ => { panic!("Invalid Timeout value") } } } else if let Some(timeout) = timeout_r.to_fixnum() { if timeout.get_num() == 0 { - child.try_wait() + process.try_wait() } else { panic!("Invalid Timeout value") } @@ -8728,23 +8766,28 @@ impl Machine { } // Pid - let pid_r = self.deref_register(1); - let Some(pid) = pid_r - .to_fixnum() - .and_then(|elem| elem.get_num().try_into().ok()) - else { - let err = self - .machine_st - .existence_error(ExistenceError::Process(pid_r)); + let process_r = self.deref_register(1); + + let Some(ptr) = process_r.to_untyped_arena_ptr() else { + let err = self.machine_st.type_error(ValidType::Process, process_r); return Err(self.machine_st.error_form(err, stub_gen())); }; - let Some(child) = self.machine_st.child_processes.get_mut(&pid) else { - let err = self - .machine_st - .existence_error(ExistenceError::Process(pid_r)); - return Err(self.machine_st.error_form(err, stub_gen())); - }; - if child.kill().is_err() { + + let mut process = match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::ChildProcess, child_process) => { + child_process + } + (ArenaHeaderTag::Dropped, _dropped) => { + let err = self.machine_st.existence_error(ExistenceError::Process(process_r)); + return Err(self.machine_st.error_form(err, stub_gen())); + } + _ => { + let err = self.machine_st.type_error(ValidType::Process, process_r); + return Err(self.machine_st.error_form(err, stub_gen())); + } + ); + + if process.kill().is_err() { let perm_error = self.machine_st .permission_error(Permission::Modify, atom!("process"), stub_gen()); @@ -8758,18 +8801,23 @@ impl Machine { functor_stub(atom!("process_release"), 1) } - let pid_r = self.deref_register(1); - let Some(pid) = pid_r - .to_fixnum() - .and_then(|elem| elem.get_num().try_into().ok()) - else { - let err = self - .machine_st - .existence_error(ExistenceError::Process(pid_r)); - return Err(self.machine_st.error_form(err, stub_gen())); - }; - self.machine_st.child_processes.remove(&pid); - Ok(()) + let process = self.deref_register(1); + + if let Some(ptr) = process.to_untyped_arena_ptr() { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::ChildProcess, child_process) => { + child_process.drop_payload(); + + return Ok(()); + } + _ => { + } + ); + } + + let err = self.machine_st.type_error(ValidType::Process, process); + + Err(self.machine_st.error_form(err, stub_gen())) } #[inline(always)] diff --git a/src/macros.rs b/src/macros.rs index e301832b..10467419 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -218,6 +218,12 @@ macro_rules! match_untyped_arena_ptr_pat_body { #[allow(unused_braces)] $code }}; + ($ptr:ident, ChildProcess, $listener:ident, $code:expr) => {{ + #[allow(unused_mut)] + let mut $listener = unsafe { $ptr.as_typed_ptr::() }; + #[allow(unused_braces)] + $code + }}; ($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{ let $s = Stream::from_tag($ptr.get_tag(), $ptr); #[allow(unused_braces)] diff --git a/tests/scryer/cli/unix/process.md b/tests/scryer/cli/unix/process.md new file mode 100644 index 00000000..8a1aef06 --- /dev/null +++ b/tests/scryer/cli/unix/process.md @@ -0,0 +1,4 @@ +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("false", [], [process(P)]), process_wait(P, exit(1)), halt' + +``` diff --git a/tests/scryer/cli/windows/process.md b/tests/scryer/cli/windows/process.md new file mode 100644 index 00000000..c83520cc --- /dev/null +++ b/tests/scryer/cli/windows/process.md @@ -0,0 +1,4 @@ +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("cmd", ["/C", "exit", "1"], [process(P)]), process_wait(P, exit(1)), halt' + +``` diff --git a/tests/scryer/main.rs b/tests/scryer/main.rs index a501bd42..19c78c59 100644 --- a/tests/scryer/main.rs +++ b/tests/scryer/main.rs @@ -19,9 +19,19 @@ mod src_tests; ignore = "miri isolation, unsupported operation: can't call foreign function" )] fn cli_tests() { - trycmd::TestCases::new() + let cases = trycmd::TestCases::new(); + cases .default_bin_name("scryer-prolog") .case("tests/scryer/cli/issues/*.toml") - .case("tests/scryer/cli/src_tests/*.toml") - .case("tests/scryer/cli/src_tests/*.md"); + .case("tests/scryer/cli/src_tests/*.toml"); + + #[cfg(windows)] + { + cases.case("tests/scryer/cli/windows/*.md"); + } + + #[cfg(unix)] + { + cases.case("tests/scryer/cli/unix/*.md"); + } } From ab675e071a2b16522424dceee0196b0451c94ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 18:46:47 +0200 Subject: [PATCH 109/122] adjust error kind --- src/lib/process.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index d66c2ea4..6f682ac8 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -152,7 +152,7 @@ check_options([X | XS], Options) :- ( Solutions = [] -> Choice = Default; Solutions = [Provided] -> call(Pred, Provided), Choice = Provided ; - error(evaluation_error(confliction_options, Solutions), process_create/3) + error(domain_error(non_confliction_process_options, Solutions), process_create/3) ), check_options(XS, Options). From 25edde2eb4f65e5d798a39499978e70baa200d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 21:02:42 +0200 Subject: [PATCH 110/122] replace filter by tfiltert and fix Pipe{Reader,Writer} streams --- src/lib/lists.pl | 10 +--------- src/lib/process.pl | 19 ++++++++++++------- src/machine/streams.rs | 4 ++++ src/macros.rs | 14 ++++++++++++++ 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/lib/lists.pl b/src/lib/lists.pl index 9c972f01..3d1cc6a2 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -7,7 +7,7 @@ List manipulation predicates maplist/3, maplist/4, maplist/5, maplist/6, maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, nth0/4, nth1/3, nth1/4, sum_list/2, transpose/2, list_to_set/2, list_max/2, - list_min/2, permutation/2, filter/3]). + list_min/2, permutation/2]). /* Author: Mark Thom, Jan Wielemaker, and Richard O'Keefe Copyright (c) 2018-2021, Mark Thom @@ -538,11 +538,3 @@ perm([], []). perm(List, [First|Perm]) :- select(First, List, Rest), perm(Rest, Perm). - - -%% filter(+Predicate, ?Xs1 ?Xs2). -% -% Succeeds if Xs2 is the list of elements X from Xs1 for which call(Pred, X) succeeds. -% -filter(_, [], []). -filter(Pred, [X1|XS1], XS) :- call(Pred, X1) -> filter(Pred, XS1, XS2), XS = [X1|XS2] ; filter(Pred, XS1, XS). \ No newline at end of file diff --git a/src/lib/process.pl b/src/lib/process.pl index 6f682ac8..d02713e9 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -9,7 +9,8 @@ :- use_module(library(error)). :- use_module(library(iso_ext)). -:- use_module(library(lists), [member/2, maplist/2, filter/3]). +:- use_module(library(lists), [member/2, maplist/2]). +:- use_module(library(reif), [tfilter/3]). %% process_create(+Exe, +Args:list, +Options). @@ -148,7 +149,7 @@ must_be_known_options(Valid, Found, [X|XS]) :- check_options([], _). check_options([X | XS], Options) :- (Kinds, Pred, Default, Choice) = X, - filter(process:find_option(Kinds), Options, Solutions), + tfilter(process:find_option(Kinds), Options, Solutions), ( Solutions = [] -> Choice = Default; Solutions = [Provided] -> call(Pred, Provided), Choice = Provided ; @@ -156,11 +157,11 @@ check_options([X | XS], Options) :- ), check_options(XS, Options). -find_option([Kind|_], Found) :- Found =.. [Kind,_]. -find_option([_|Kinds], Found) :- find_option(Kinds, Found). +find_option(Names, Found, T) :- (functor(Found, Name, 1), member(Name, Names)) -> T = true ; T = false. -valid_stdio(IO) :- IO =.. [_, Arg], +valid_stdio(IO) :- arg(1, IO, Arg), ( + var(Arg) -> instantiation_error(process_create/3) ; valid_stdio_(Arg) -> true ; domain_error(process_create_option, Arg, process_create/3) ). @@ -170,11 +171,15 @@ valid_stdio_(null). valid_stdio_(pipe(Stream)) :- must_be(var, Stream). valid_stdio_(file(Path)) :- must_be(chars, Path). -valid_env(env(E)) :- ( +valid_env(env(E)) :- + must_be(list, E), + ( valid_env_(E) -> true ; domain_error(process_create_option, env(E), process_create/3) ). -valid_env(environment(E)) :- ( +valid_env(environment(E)) :- + must_be(list, E), + ( valid_env_(E) -> true ; domain_error(process_create_option, environment(E), process_create/3) ). diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 871ea617..596b09de 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -694,6 +694,8 @@ impl Stream { ArenaHeaderTag::InputChannelStream => { Stream::InputChannel(unsafe { ptr.as_typed_ptr() }) } + ArenaHeaderTag::PipeReader => Stream::PipeReader(unsafe { ptr.as_typed_ptr() }), + ArenaHeaderTag::PipeWriter => Stream::PipeWriter(unsafe { ptr.as_typed_ptr() }), _ => unreachable!(), } } @@ -1601,6 +1603,7 @@ impl Stream { | Stream::Readline(_) | Stream::StaticString(_) | Stream::InputFile(..) + | Stream::PipeReader(_) | Stream::Null(_) => true, _ => false, } @@ -1619,6 +1622,7 @@ impl Stream { | Stream::Byte(_) | Stream::OutputFile(..) | Stream::Callback(_) + | Stream::PipeWriter(_) | Stream::Null(_) => true, _ => false, } diff --git a/src/macros.rs b/src/macros.rs index 10467419..79470f18 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -218,6 +218,18 @@ macro_rules! match_untyped_arena_ptr_pat_body { #[allow(unused_braces)] $code }}; + ($ptr:ident, PipeReader, $listener:ident, $code:expr) => {{ + #[allow(unused_mut)] + let mut $listener = unsafe { $ptr.as_typed_ptr::() }; + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, PipeWriter, $listener:ident, $code:expr) => {{ + #[allow(unused_mut)] + let mut $listener = unsafe { $ptr.as_typed_ptr::() }; + #[allow(unused_braces)] + $code + }}; ($ptr:ident, ChildProcess, $listener:ident, $code:expr) => {{ #[allow(unused_mut)] let mut $listener = unsafe { $ptr.as_typed_ptr::() }; @@ -246,6 +258,8 @@ macro_rules! match_untyped_arena_ptr_pat { | ArenaHeaderTag::InputChannelStream | ArenaHeaderTag::StandardOutputStream | ArenaHeaderTag::StandardErrorStream + | ArenaHeaderTag::PipeReader + | ArenaHeaderTag::PipeWriter }; ($tag:ident) => { ArenaHeaderTag::$tag From 70d65bcea841d8c2e2b8f16d34d2f9ea53683917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 21:18:15 +0200 Subject: [PATCH 111/122] add another test and remove unecessary module qualification --- src/lib/process.pl | 2 +- tests/scryer/cli/windows/process.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index d02713e9..878b295d 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -149,7 +149,7 @@ must_be_known_options(Valid, Found, [X|XS]) :- check_options([], _). check_options([X | XS], Options) :- (Kinds, Pred, Default, Choice) = X, - tfilter(process:find_option(Kinds), Options, Solutions), + tfilter(find_option(Kinds), Options, Solutions), ( Solutions = [] -> Choice = Default; Solutions = [Provided] -> call(Pred, Provided), Choice = Provided ; diff --git a/tests/scryer/cli/windows/process.md b/tests/scryer/cli/windows/process.md index c83520cc..2b3fdbf5 100644 --- a/tests/scryer/cli/windows/process.md +++ b/tests/scryer/cli/windows/process.md @@ -2,3 +2,8 @@ $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("cmd", ["/C", "exit", "1"], [process(P)]), process_wait(P, exit(1)), halt' ``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), use_module(library(format)), process_create("cmd", [], [process(P), stdout(null), stdin(pipe(S))]), format(S, "exit 1~n", []), process_wait(P, Status), halt' + +``` \ No newline at end of file From eb82d1b6d40aa3aaf4f1eec7b071ad1a000c05a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 21:39:44 +0200 Subject: [PATCH 112/122] reformat ; --- src/lib/process.pl | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 878b295d..0d457d6d 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -139,10 +139,9 @@ process_release(Process) :- must_be_known_options(_, _, []). must_be_known_options(Valid, Found, [X|XS]) :- X =.. [Option|_], - ( - member(Option, Found) -> domain_error(non_duplicate_process_create_options, process_create/3); - member(Option, Valid) -> true ; - domain_error(process_create_option, Option, process_create/3) + ( member(Option, Found) -> domain_error(non_duplicate_process_create_options, process_create/3) + ; member(Option, Valid) -> true + ; domain_error(process_create_option, Option, process_create/3) ), must_be_known_options(Valid, [Option | Found], XS). @@ -150,20 +149,18 @@ check_options([], _). check_options([X | XS], Options) :- (Kinds, Pred, Default, Choice) = X, tfilter(find_option(Kinds), Options, Solutions), - ( - Solutions = [] -> Choice = Default; - Solutions = [Provided] -> call(Pred, Provided), Choice = Provided ; - error(domain_error(non_confliction_process_options, Solutions), process_create/3) + ( Solutions = [] -> Choice = Default + ; Solutions = [Provided] -> call(Pred, Provided), Choice = Provided + ; error(domain_error(non_confliction_process_options, Solutions), process_create/3) ), check_options(XS, Options). find_option(Names, Found, T) :- (functor(Found, Name, 1), member(Name, Names)) -> T = true ; T = false. valid_stdio(IO) :- arg(1, IO, Arg), - ( - var(Arg) -> instantiation_error(process_create/3) ; - valid_stdio_(Arg) -> true ; - domain_error(process_create_option, Arg, process_create/3) + ( var(Arg) -> instantiation_error(process_create/3) + ; valid_stdio_(Arg) -> true + ; domain_error(process_create_option, Arg, process_create/3) ). valid_stdio_(std). @@ -173,15 +170,13 @@ valid_stdio_(file(Path)) :- must_be(chars, Path). valid_env(env(E)) :- must_be(list, E), - ( - valid_env_(E) -> true ; - domain_error(process_create_option, env(E), process_create/3) + ( valid_env_(E) -> true + ; domain_error(process_create_option, env(E), process_create/3) ). valid_env(environment(E)) :- must_be(list, E), - ( - valid_env_(E) -> true ; - domain_error(process_create_option, environment(E), process_create/3) + ( valid_env_(E) -> true + ; domain_error(process_create_option, environment(E), process_create/3) ). valid_env_([]). From 62e43a3ab0364dfa1f372f055279903356f08dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 21:55:18 +0200 Subject: [PATCH 113/122] use functor/3 for must_be_known_options --- src/lib/process.pl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 0d457d6d..2f8ceec1 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -10,7 +10,7 @@ :- use_module(library(error)). :- use_module(library(iso_ext)). :- use_module(library(lists), [member/2, maplist/2]). -:- use_module(library(reif), [tfilter/3]). +:- use_module(library(reif), [tfilter/3, memberd_t/3]). %% process_create(+Exe, +Args:list, +Options). @@ -138,7 +138,7 @@ process_release(Process) :- must_be_known_options(_, _, []). must_be_known_options(Valid, Found, [X|XS]) :- - X =.. [Option|_], + functor(X, Option, 1), ( member(Option, Found) -> domain_error(non_duplicate_process_create_options, process_create/3) ; member(Option, Valid) -> true ; domain_error(process_create_option, Option, process_create/3) @@ -155,7 +155,9 @@ check_options([X | XS], Options) :- ), check_options(XS, Options). -find_option(Names, Found, T) :- (functor(Found, Name, 1), member(Name, Names)) -> T = true ; T = false. +find_option(Names, Found, T) :- + functor(Found, Name, 1), + memberd_t(Name, Names, T). valid_stdio(IO) :- arg(1, IO, Arg), ( var(Arg) -> instantiation_error(process_create/3) From d0a6dc9df2b2a33bef002f34a19ec079537c4452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 22:08:58 +0200 Subject: [PATCH 114/122] address comment by triska https://github.com/mthom/scryer-prolog/pull/3009#discussion_r2233221091 --- src/lib/process.pl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 2f8ceec1..fcc17491 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -51,12 +51,12 @@ process_create(Exe, Args, Options) :- must_be_known_options([stdin, stdout, stderr, env, environment, process, cwd], [], Options), check_options( [ - ([stdin], valid_stdio, stdin(std), stdin(Stdin)), - ([stdout], valid_stdio, stdout(std), stdout(Stdout)), - ([stderr], valid_stdio, stderr(std), stderr(Stderr)), - ([env, environment], valid_env, environment([]), Env), - ([process], valid_uninit_process, process(_), process(Process)), - ([cwd], valid_cwd, cwd("."), cwd(Cwd)) + option([stdin], valid_stdio, stdin(std), stdin(Stdin)), + option([stdout], valid_stdio, stdout(std), stdout(Stdout)), + option([stderr], valid_stdio, stderr(std), stderr(Stderr)), + option([env, environment], valid_env, environment([]), Env), + option([process], valid_uninit_process, process(_), process(Process)), + option([cwd], valid_cwd, cwd("."), cwd(Cwd)) ], Options ), @@ -102,7 +102,7 @@ process_wait(Process, Status, Options) :- valid_process(Process, process_wait/3), must_be_known_options([timeout], [], Options),check_options( [ - ([timeout], valid_timeout, timeout(infinite), timeout(Timeout)) + option([timeout], valid_timeout, timeout(infinite), timeout(Timeout)) ], Options ), @@ -147,7 +147,7 @@ must_be_known_options(Valid, Found, [X|XS]) :- check_options([], _). check_options([X | XS], Options) :- - (Kinds, Pred, Default, Choice) = X, + option(Kinds, Pred, Default, Choice) = X, tfilter(find_option(Kinds), Options, Solutions), ( Solutions = [] -> Choice = Default ; Solutions = [Provided] -> call(Pred, Provided), Choice = Provided From 143f32be233e8e19ad771b937c1a6d01db58af47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 23:10:29 +0200 Subject: [PATCH 115/122] adjust options checking and add more tests --- src/lib/process.pl | 49 +++++++++++++++++---------- tests/scryer/cli/src_tests/process.md | 29 ++++++++++++++++ tests/scryer/main.rs | 3 +- 3 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 tests/scryer/cli/src_tests/process.md diff --git a/src/lib/process.pl b/src/lib/process.pl index fcc17491..6f293179 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -9,7 +9,7 @@ :- use_module(library(error)). :- use_module(library(iso_ext)). -:- use_module(library(lists), [member/2, maplist/2]). +:- use_module(library(lists), [member/2, maplist/2, maplist/3, append/2]). :- use_module(library(reif), [tfilter/3, memberd_t/3]). @@ -48,7 +48,6 @@ process_create(Exe, Args, Options) :- must_be(list, Args), maplist(must_be(chars), Args), must_be(list, Options), - must_be_known_options([stdin, stdout, stderr, env, environment, process, cwd], [], Options), check_options( [ option([stdin], valid_stdio, stdin(std), stdin(Stdin)), @@ -58,7 +57,9 @@ process_create(Exe, Args, Options) :- option([process], valid_uninit_process, process(_), process(Process)), option([cwd], valid_cwd, cwd("."), cwd(Cwd)) ], - Options + Options, + process_create_option, + process_create/3 ), Stdin =.. Stdin1, Stdout =.. Stdout1, @@ -100,11 +101,13 @@ process_wait(Process, Status) :- process_wait(Process, Status, []). % process_wait(Process, Status, Options) :- valid_process(Process, process_wait/3), - must_be_known_options([timeout], [], Options),check_options( + check_options( [ option([timeout], valid_timeout, timeout(infinite), timeout(Timeout)) ], - Options + Options, + process_wait_option, + process_wait/3 ), '$process_wait'(Process, Exit, Timeout), Exit = Status. @@ -136,24 +139,34 @@ process_release(Process) :- '$process_release'(Process). -must_be_known_options(_, _, []). -must_be_known_options(Valid, Found, [X|XS]) :- - functor(X, Option, 1), - ( member(Option, Found) -> domain_error(non_duplicate_process_create_options, process_create/3) - ; member(Option, Valid) -> true - ; domain_error(process_create_option, Option, process_create/3) - ), - must_be_known_options(Valid, [Option | Found], XS). +must_be_known_options(Valid, Options, Domain, Context) :- must_be_known_options_(Valid, [], Options, Domain, Context). -check_options([], _). -check_options([X | XS], Options) :- +must_be_known_options_(_, _, [], _, _). +must_be_known_options_(Valid, Found, [X|XS], Domain, Context) :- + functor(X, Option, 1), + ( member(Option, Found) -> domain_error(non_duplicate_options, Option , Context) + ; member(Option, Valid) -> true + ; domain_error(Domain, Option, Context) + ), + must_be_known_options_(Valid, [Option | Found], XS, Domain, Context). + +check_options(KnownOptions, Options, Domain, Context) :- + maplist(option_names, KnownOptions, Namess), + append(Namess, Names), + must_be_known_options(Names, Options, Domain, Context), + check_options_(KnownOptions, Options, Context). + +option_names(option(Names,_,_,_), Names). + +check_options_([], _, _). +check_options_([X | XS], Options, Context) :- option(Kinds, Pred, Default, Choice) = X, tfilter(find_option(Kinds), Options, Solutions), ( Solutions = [] -> Choice = Default ; Solutions = [Provided] -> call(Pred, Provided), Choice = Provided - ; error(domain_error(non_confliction_process_options, Solutions), process_create/3) + ; domain_error(non_conflicting_options, Solutions, Context) ), - check_options(XS, Options). + check_options_(XS, Options, Context). find_option(Names, Found, T) :- functor(Found, Name, 1), @@ -162,7 +175,7 @@ find_option(Names, Found, T) :- valid_stdio(IO) :- arg(1, IO, Arg), ( var(Arg) -> instantiation_error(process_create/3) ; valid_stdio_(Arg) -> true - ; domain_error(process_create_option, Arg, process_create/3) + ; domain_error(stdio_spec, Arg, process_create/3) ). valid_stdio_(std). diff --git a/tests/scryer/cli/src_tests/process.md b/tests/scryer/cli/src_tests/process.md new file mode 100644 index 00000000..76f8b3e4 --- /dev/null +++ b/tests/scryer/cli/src_tests/process.md @@ -0,0 +1,29 @@ +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid(_), process(P)]), process_kill(P, _), halt' +use_module(library(process)),process_create([],[],[invalid(_[..]),process(P)]),process_kill(P,_[..]),halt causes: error(domain_error(process_create_option,invalid),process_create/3) + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(null), stdin(null), process(P)]), process_kill(P, _), halt' +use_module(library(process)),process_create([],[],[stdin(null),stdin(null),process(P)]),process_kill(P,_[..]),halt causes: error(domain_error(non_duplicate_options,stdin),process_create/3) + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [env([]), environment([]), process(P)]), process_kill(P, _), halt' +use_module(library(process)),process_create([],[],[env([]),environment([]),process(P)]),process_kill(P,_[..]),halt causes: error(domain_error(non_conflicting_options,[env([]),environment([])]),process_create/3) + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(pid, _, [invalid(_), timeout(0)]), halt' +use_module(library(process)),process_wait(pid,_[..],[invalid(_[..]),timeout(0)]),halt causes: error(domain_error(process_wait_option,invalid),process_wait/3) + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(invalid), process(P)]), process_kill(P, _), halt' +use_module(library(process)),process_create([],[],[stdin(invalid),process(P)]),process_kill(P,_[..]),halt causes: error(domain_error(stdio_spec,invalid),process_create/3) + +``` diff --git a/tests/scryer/main.rs b/tests/scryer/main.rs index 19c78c59..c46ced24 100644 --- a/tests/scryer/main.rs +++ b/tests/scryer/main.rs @@ -23,7 +23,8 @@ fn cli_tests() { cases .default_bin_name("scryer-prolog") .case("tests/scryer/cli/issues/*.toml") - .case("tests/scryer/cli/src_tests/*.toml"); + .case("tests/scryer/cli/src_tests/*.toml") + .case("tests/scryer/cli/src_tests/*.md"); #[cfg(windows)] { From 409159d68dc6110b80f6668d1b32b429830c476a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sat, 26 Jul 2025 23:59:58 +0200 Subject: [PATCH 116/122] adjust/add tests --- tests/scryer/cli/unix/process.md | 10 ++++++++++ tests/scryer/cli/windows/process.md | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/scryer/cli/unix/process.md b/tests/scryer/cli/unix/process.md index 8a1aef06..6bb174e4 100644 --- a/tests/scryer/cli/unix/process.md +++ b/tests/scryer/cli/unix/process.md @@ -2,3 +2,13 @@ $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("false", [], [process(P)]), process_wait(P, exit(1)), halt' ``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), use_module(library(format)), process_create("sh", [], [process(P), stdout(null), stdin(pipe(S))]), format(S, "exit 1~n", []), process_wait(P, exit(1)), halt' + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("sh", ["-c", "sleep 5"], [process(P), stdout(null)]), process_kill(P), process_wait(P, killed(9)), halt' + +``` \ No newline at end of file diff --git a/tests/scryer/cli/windows/process.md b/tests/scryer/cli/windows/process.md index 2b3fdbf5..da27656b 100644 --- a/tests/scryer/cli/windows/process.md +++ b/tests/scryer/cli/windows/process.md @@ -4,6 +4,6 @@ $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_cr ``` ```trycmd -$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), use_module(library(format)), process_create("cmd", [], [process(P), stdout(null), stdin(pipe(S))]), format(S, "exit 1~n", []), process_wait(P, Status), halt' +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), use_module(library(format)), process_create("cmd", [], [process(P), stdout(null), stdin(pipe(S))]), format(S, "exit 1~n", []), process_wait(P, exit(1)), halt' ``` \ No newline at end of file From 3a6b92d227bf682b41a0380e4d4ef3ec795f5e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Sun, 27 Jul 2025 20:36:07 +0200 Subject: [PATCH 117/122] more tests --- src/lib/process.pl | 6 ++-- tests/scryer/cli/src_tests/process.md | 46 ++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 6f293179..b754c331 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -71,9 +71,7 @@ process_create(Exe, Args, Options) :- % process_id(Process, Pid) :- valid_process(Process, process_id/2), - write(valid), nl, must_be(var, Pid), - write(var), nl, '$process_id'(Process, Pid). %% process_wait(+Process, Status). @@ -143,7 +141,9 @@ must_be_known_options(Valid, Options, Domain, Context) :- must_be_known_options_ must_be_known_options_(_, _, [], _, _). must_be_known_options_(Valid, Found, [X|XS], Domain, Context) :- - functor(X, Option, 1), + ( functor(X, Option, 1) -> true + ; domain_error(Domain, Option , Context) + ) , ( member(Option, Found) -> domain_error(non_duplicate_options, Option , Context) ; member(Option, Valid) -> true ; domain_error(Domain, Option, Context) diff --git a/tests/scryer/cli/src_tests/process.md b/tests/scryer/cli/src_tests/process.md index 76f8b3e4..39a955da 100644 --- a/tests/scryer/cli/src_tests/process.md +++ b/tests/scryer/cli/src_tests/process.md @@ -1,18 +1,24 @@ ```trycmd -$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid(_), process(P)]), process_kill(P, _), halt' -use_module(library(process)),process_create([],[],[invalid(_[..]),process(P)]),process_kill(P,_[..]),halt causes: error(domain_error(process_create_option,invalid),process_create/3) +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid, process(P)]), process_kill(P), halt' +use_module(library(process)),process_create([],[],[invalid,process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,_[..]),process_create/3) ``` ```trycmd -$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(null), stdin(null), process(P)]), process_kill(P, _), halt' -use_module(library(process)),process_create([],[],[stdin(null),stdin(null),process(P)]),process_kill(P,_[..]),halt causes: error(domain_error(non_duplicate_options,stdin),process_create/3) +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid(_), process(P)]), process_kill(P), halt' +use_module(library(process)),process_create([],[],[invalid(_[..]),process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),process_create/3) ``` ```trycmd -$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [env([]), environment([]), process(P)]), process_kill(P, _), halt' -use_module(library(process)),process_create([],[],[env([]),environment([]),process(P)]),process_kill(P,_[..]),halt causes: error(domain_error(non_conflicting_options,[env([]),environment([])]),process_create/3) +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(null), stdin(null), process(P)]), process_kill(P), halt' +use_module(library(process)),process_create([],[],[stdin(null),stdin(null),process(P)]),process_kill(P),halt causes: error(domain_error(non_duplicate_options,stdin),process_create/3) + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [env([]), environment([]), process(P)]), process_kill(P), halt' +use_module(library(process)),process_create([],[],[env([]),environment([]),process(P)]),process_kill(P),halt causes: error(domain_error(non_conflicting_options,[env([]),environment([])]),process_create/3) ``` @@ -23,7 +29,31 @@ use_module(library(process)),process_wait(pid,_[..],[invalid(_[..]),timeout(0)]) ``` ```trycmd -$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(invalid), process(P)]), process_kill(P, _), halt' -use_module(library(process)),process_create([],[],[stdin(invalid),process(P)]),process_kill(P,_[..]),halt causes: error(domain_error(stdio_spec,invalid),process_create/3) +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(invalid), process(P)]), process_kill(P), halt' +use_module(library(process)),process_create([],[],[stdin(invalid),process(P)]),process_kill(P),halt causes: error(domain_error(stdio_spec,invalid),process_create/3) + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(50, _), halt' +use_module(library(process)),process_wait(50,_[..]),halt causes: error(type_error(process,50),process_wait/2) + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_kill(50), halt' +use_module(library(process)),process_kill(50),halt causes: error(type_error(process,50),process_kill/1) + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_id(50,_), halt' +use_module(library(process)),process_id(50,_[..]),halt causes: error(type_error(process,50),process_id/2) + +``` + +```trycmd +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_release(50), halt' +use_module(library(process)),process_release(50),halt causes: error(type_error(process,50),process_wait/2) ``` From b2d639b159dd9bbda24896dce24231206f892700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Wed, 30 Jul 2025 21:22:37 +0200 Subject: [PATCH 118/122] fix arity of prcess_wait builtin errors --- src/machine/system_calls.rs | 2 +- tests/scryer/cli/src_tests/process.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 0fc6e35d..3f367a39 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -8654,7 +8654,7 @@ impl Machine { pub(crate) fn process_wait(&mut self) -> CallResult { fn stub_gen() -> Vec { - functor_stub(atom!("process_wait"), 2) + functor_stub(atom!("process_wait"), 3) } // Process diff --git a/tests/scryer/cli/src_tests/process.md b/tests/scryer/cli/src_tests/process.md index 39a955da..59e8de10 100644 --- a/tests/scryer/cli/src_tests/process.md +++ b/tests/scryer/cli/src_tests/process.md @@ -36,7 +36,7 @@ use_module(library(process)),process_create([],[],[stdin(invalid),process(P)]),p ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(50, _), halt' -use_module(library(process)),process_wait(50,_[..]),halt causes: error(type_error(process,50),process_wait/2) +use_module(library(process)),process_wait(50,_[..]),halt causes: error(type_error(process,50),process_wait/3) ``` @@ -54,6 +54,6 @@ use_module(library(process)),process_id(50,_[..]),halt causes: error(type_error( ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_release(50), halt' -use_module(library(process)),process_release(50),halt causes: error(type_error(process,50),process_wait/2) +use_module(library(process)),process_release(50),halt causes: error(type_error(process,50),process_wait/3) ``` From 45041be336cd052f605cb8dc74d72830cb666dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Wed, 30 Jul 2025 22:14:43 +0200 Subject: [PATCH 119/122] fix culprit --- src/lib/process.pl | 2 +- tests/scryer/cli/src_tests/process.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index b754c331..12650416 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -142,7 +142,7 @@ must_be_known_options(Valid, Options, Domain, Context) :- must_be_known_options_ must_be_known_options_(_, _, [], _, _). must_be_known_options_(Valid, Found, [X|XS], Domain, Context) :- ( functor(X, Option, 1) -> true - ; domain_error(Domain, Option , Context) + ; domain_error(Domain, X , Context) ) , ( member(Option, Found) -> domain_error(non_duplicate_options, Option , Context) ; member(Option, Valid) -> true diff --git a/tests/scryer/cli/src_tests/process.md b/tests/scryer/cli/src_tests/process.md index 59e8de10..bb198d23 100644 --- a/tests/scryer/cli/src_tests/process.md +++ b/tests/scryer/cli/src_tests/process.md @@ -1,6 +1,6 @@ ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid, process(P)]), process_kill(P), halt' -use_module(library(process)),process_create([],[],[invalid,process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,_[..]),process_create/3) +use_module(library(process)),process_create([],[],[invalid,process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),process_create/3) ``` From fadd3a0839ef437c37f8a82e33e436ec2b953787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Wed, 30 Jul 2025 22:19:03 +0200 Subject: [PATCH 120/122] use named vars instead of wildcards makes updating tests easier as globs are sometimes lost when using TRYCMD=overwrite --- tests/scryer/cli/src_tests/process.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/scryer/cli/src_tests/process.md b/tests/scryer/cli/src_tests/process.md index bb198d23..03ba7802 100644 --- a/tests/scryer/cli/src_tests/process.md +++ b/tests/scryer/cli/src_tests/process.md @@ -5,8 +5,8 @@ use_module(library(process)),process_create([],[],[invalid,process(P)]),process_ ``` ```trycmd -$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid(_), process(P)]), process_kill(P), halt' -use_module(library(process)),process_create([],[],[invalid(_[..]),process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),process_create/3) +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid(_Var), process(P)]), process_kill(P), halt' +use_module(library(process)),process_create([],[],[invalid(_Var),process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),process_create/3) ``` @@ -23,8 +23,8 @@ use_module(library(process)),process_create([],[],[env([]),environment([]),proce ``` ```trycmd -$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(pid, _, [invalid(_), timeout(0)]), halt' -use_module(library(process)),process_wait(pid,_[..],[invalid(_[..]),timeout(0)]),halt causes: error(domain_error(process_wait_option,invalid),process_wait/3) +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(pid, _Status, [invalid(_Var), timeout(0)]), halt' +use_module(library(process)),process_wait(pid,_Status,[invalid(_Var),timeout(0)]),halt causes: error(domain_error(process_wait_option,invalid),process_wait/3) ``` @@ -35,8 +35,8 @@ use_module(library(process)),process_create([],[],[stdin(invalid),process(P)]),p ``` ```trycmd -$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(50, _), halt' -use_module(library(process)),process_wait(50,_[..]),halt causes: error(type_error(process,50),process_wait/3) +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(50, _Status), halt' +use_module(library(process)),process_wait(50,_Status),halt causes: error(type_error(process,50),process_wait/3) ``` @@ -47,8 +47,8 @@ use_module(library(process)),process_kill(50),halt causes: error(type_error(proc ``` ```trycmd -$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_id(50,_), halt' -use_module(library(process)),process_id(50,_[..]),halt causes: error(type_error(process,50),process_id/2) +$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_id(50,_Pid), halt' +use_module(library(process)),process_id(50,_Pid),halt causes: error(type_error(process,50),process_id/2) ``` From d907f86c8d3bf5b5429c9f53187b65473fcbfce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Wed, 30 Jul 2025 22:21:00 +0200 Subject: [PATCH 121/122] use call_with_error_context --- src/lib/process.pl | 80 +++++++++++++++------------ tests/scryer/cli/src_tests/process.md | 20 +++---- 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/lib/process.pl b/src/lib/process.pl index 12650416..57c71426 100644 --- a/src/lib/process.pl +++ b/src/lib/process.pl @@ -43,7 +43,9 @@ % - `environment([])` % - `stdin(std)`, `stdout(std)`, `stderr(std)` % -process_create(Exe, Args, Options) :- +process_create(Exe, Args, Options) :- call_with_error_context(process_create_(Exe, Args, Options), predicate-process_create/3). + +process_create_(Exe, Args, Options) :- must_be(chars, Exe), must_be(list, Args), maplist(must_be(chars), Args), @@ -58,8 +60,7 @@ process_create(Exe, Args, Options) :- option([cwd], valid_cwd, cwd("."), cwd(Cwd)) ], Options, - process_create_option, - process_create/3 + process_create_option ), Stdin =.. Stdin1, Stdout =.. Stdout1, @@ -69,8 +70,10 @@ process_create(Exe, Args, Options) :- %% process_id(+Process, -Pid). % -process_id(Process, Pid) :- - valid_process(Process, process_id/2), +process_id(Process, Pid) :- call_with_error_context(process_id_(Process, Pid), predicate-process_id/2). + +process_id_(Process, Pid) :- + valid_process(Process), must_be(var, Pid), '$process_id'(Process, Pid). @@ -78,7 +81,7 @@ process_id(Process, Pid) :- % % See `process_create/3` with `Options = []` % -process_wait(Process, Status) :- process_wait(Process, Status, []). +process_wait(Process, Status) :- call_with_error_context(process_wait(Process, Status, []), predicate-process_wait/2). %% process_wait(+Process, Status, Options). @@ -97,15 +100,16 @@ process_wait(Process, Status) :- process_wait(Process, Status, []). % % - timeout(infinite) % -process_wait(Process, Status, Options) :- - valid_process(Process, process_wait/3), +process_wait(Process, Status, Options) :- call_with_error_context(process_wait_(Process, Status, Options), predicate-process_wait/3). + +process_wait_(Process, Status, Options) :- + valid_process(Process), check_options( [ option([timeout], valid_timeout, timeout(infinite), timeout(Timeout)) ], Options, - process_wait_option, - process_wait/3 + process_wait_option ), '$process_wait'(Process, Exit, Timeout), Exit = Status. @@ -121,8 +125,10 @@ valid_timeout(timeout(0)). % % Only works for processes spawned with `process_create/3` that have not yet been release with `process_release/1` % -process_kill(Process) :- - valid_process(Process, process_kill/1), +process_kill(Process) :- call_with_error_context(process_kill_(Process), predicate-process_kill/1). + +process_kill_(Process) :- + valid_process(Process), '$process_kill'(Process). %% process_release(+Process) @@ -131,51 +137,57 @@ process_kill(Process) :- % % It's an error if `Process` is not a valid process handle % -process_release(Process) :- - valid_process(Process, process_release/1), +process_release(Process) :- call_with_error_context(process_release_(Process), predicate-process_release/1). + +process_release_(Process) :- + valid_process(Process), process_wait(Process, _), '$process_release'(Process). -must_be_known_options(Valid, Options, Domain, Context) :- must_be_known_options_(Valid, [], Options, Domain, Context). +must_be_known_options(Valid, Options, Domain) :- call_with_error_context(must_be_known_options_(Valid, [], Options, Domain),predicate-must_be_known_options/3). -must_be_known_options_(_, _, [], _, _). -must_be_known_options_(Valid, Found, [X|XS], Domain, Context) :- +must_be_known_options_(_, _, [], _). +must_be_known_options_(Valid, Found, [X|XS], Domain) :- ( functor(X, Option, 1) -> true - ; domain_error(Domain, X , Context) + ; domain_error(Domain, X, []) ) , - ( member(Option, Found) -> domain_error(non_duplicate_options, Option , Context) + ( member(Option, Found) -> domain_error(non_duplicate_options, Option , []) ; member(Option, Valid) -> true - ; domain_error(Domain, Option, Context) + ; domain_error(Domain, Option, []) ), - must_be_known_options_(Valid, [Option | Found], XS, Domain, Context). + must_be_known_options_(Valid, [Option | Found], XS, Domain). -check_options(KnownOptions, Options, Domain, Context) :- +check_options(KnownOptions, Options, Domain) :- call_with_error_context(check_options_(KnownOptions, Options, Domain), predicate-check_options/3). + +check_options_(KnownOptions, Options, Domain) :- maplist(option_names, KnownOptions, Namess), append(Namess, Names), - must_be_known_options(Names, Options, Domain, Context), - check_options_(KnownOptions, Options, Context). + must_be_known_options(Names, Options, Domain), + extract_options(KnownOptions, Options). option_names(option(Names,_,_,_), Names). -check_options_([], _, _). -check_options_([X | XS], Options, Context) :- +extract_options(KnownOptions, Options) :- call_with_error_context(extract_options_(KnownOptions, Options), predicate-extract_options/2). + +extract_options_([], _). +extract_options_([X | XS], Options) :- option(Kinds, Pred, Default, Choice) = X, tfilter(find_option(Kinds), Options, Solutions), ( Solutions = [] -> Choice = Default - ; Solutions = [Provided] -> call(Pred, Provided), Choice = Provided - ; domain_error(non_conflicting_options, Solutions, Context) + ; Solutions = [Provided] -> functor(Pred, Name, Arity), ArityP1 is Arity+1, call_with_error_context(call(Pred, Provided),predicate-Name/ArityP1), Choice = Provided + ; domain_error(non_conflicting_options, Solutions, []) ), - check_options_(XS, Options, Context). + extract_options_(XS, Options). find_option(Names, Found, T) :- functor(Found, Name, 1), memberd_t(Name, Names, T). valid_stdio(IO) :- arg(1, IO, Arg), - ( var(Arg) -> instantiation_error(process_create/3) + ( var(Arg) -> instantiation_error([]) ; valid_stdio_(Arg) -> true - ; domain_error(stdio_spec, Arg, process_create/3) + ; domain_error(stdio_spec, Arg, []) ). valid_stdio_(std). @@ -186,12 +198,12 @@ valid_stdio_(file(Path)) :- must_be(chars, Path). valid_env(env(E)) :- must_be(list, E), ( valid_env_(E) -> true - ; domain_error(process_create_option, env(E), process_create/3) + ; domain_error(process_create_option, env(E), []) ). valid_env(environment(E)) :- must_be(list, E), ( valid_env_(E) -> true - ; domain_error(process_create_option, environment(E), process_create/3) + ; domain_error(process_create_option, environment(E), []) ). valid_env_([]). @@ -202,7 +214,7 @@ valid_env_([N=V|ES]) :- valid_uninit_process(process(Process)) :- must_be(var, Process). -valid_process(Process, Context) :- var(Process) -> instantiation_error(Context) ; true. +valid_process(Process) :- var(Process) -> instantiation_error([]) ; true. valid_cwd(cwd(Cwd)) :- must_be(chars, Cwd). diff --git a/tests/scryer/cli/src_tests/process.md b/tests/scryer/cli/src_tests/process.md index 03ba7802..fb0dccd8 100644 --- a/tests/scryer/cli/src_tests/process.md +++ b/tests/scryer/cli/src_tests/process.md @@ -1,59 +1,59 @@ ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid, process(P)]), process_kill(P), halt' -use_module(library(process)),process_create([],[],[invalid,process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),process_create/3) +use_module(library(process)),process_create([],[],[invalid,process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),[predicate-process_create/3,predicate-check_options/3,predicate-must_be_known_options/3]) ``` ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid(_Var), process(P)]), process_kill(P), halt' -use_module(library(process)),process_create([],[],[invalid(_Var),process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),process_create/3) +use_module(library(process)),process_create([],[],[invalid(_Var),process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),[predicate-process_create/3,predicate-check_options/3,predicate-must_be_known_options/3]) ``` ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(null), stdin(null), process(P)]), process_kill(P), halt' -use_module(library(process)),process_create([],[],[stdin(null),stdin(null),process(P)]),process_kill(P),halt causes: error(domain_error(non_duplicate_options,stdin),process_create/3) +use_module(library(process)),process_create([],[],[stdin(null),stdin(null),process(P)]),process_kill(P),halt causes: error(domain_error(non_duplicate_options,stdin),[predicate-process_create/3,predicate-check_options/3,predicate-must_be_known_options/3]) ``` ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [env([]), environment([]), process(P)]), process_kill(P), halt' -use_module(library(process)),process_create([],[],[env([]),environment([]),process(P)]),process_kill(P),halt causes: error(domain_error(non_conflicting_options,[env([]),environment([])]),process_create/3) +use_module(library(process)),process_create([],[],[env([]),environment([]),process(P)]),process_kill(P),halt causes: error(domain_error(non_conflicting_options,[env([]),environment([])]),[predicate-process_create/3,predicate-check_options/3,predicate-extract_options/2]) ``` ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(pid, _Status, [invalid(_Var), timeout(0)]), halt' -use_module(library(process)),process_wait(pid,_Status,[invalid(_Var),timeout(0)]),halt causes: error(domain_error(process_wait_option,invalid),process_wait/3) +use_module(library(process)),process_wait(pid,_Status,[invalid(_Var),timeout(0)]),halt causes: error(domain_error(process_wait_option,invalid),[predicate-process_wait/3,predicate-check_options/3,predicate-must_be_known_options/3]) ``` ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(invalid), process(P)]), process_kill(P), halt' -use_module(library(process)),process_create([],[],[stdin(invalid),process(P)]),process_kill(P),halt causes: error(domain_error(stdio_spec,invalid),process_create/3) +use_module(library(process)),process_create([],[],[stdin(invalid),process(P)]),process_kill(P),halt causes: error(domain_error(stdio_spec,invalid),[predicate-process_create/3,predicate-check_options/3,predicate-extract_options/2,predicate-valid_stdio/1]) ``` ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(50, _Status), halt' -use_module(library(process)),process_wait(50,_Status),halt causes: error(type_error(process,50),process_wait/3) +use_module(library(process)),process_wait(50,_Status),halt causes: error(type_error(process,50),[predicate-process_wait/2,predicate-process_wait/3|process_wait/3]) ``` ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_kill(50), halt' -use_module(library(process)),process_kill(50),halt causes: error(type_error(process,50),process_kill/1) +use_module(library(process)),process_kill(50),halt causes: error(type_error(process,50),[predicate-process_kill/1|process_kill/1]) ``` ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_id(50,_Pid), halt' -use_module(library(process)),process_id(50,_Pid),halt causes: error(type_error(process,50),process_id/2) +use_module(library(process)),process_id(50,_Pid),halt causes: error(type_error(process,50),[predicate-process_id/2|process_id/2]) ``` ```trycmd $ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_release(50), halt' -use_module(library(process)),process_release(50),halt causes: error(type_error(process,50),process_wait/3) +use_module(library(process)),process_release(50),halt causes: error(type_error(process,50),[predicate-process_release/1,predicate-process_wait/2,predicate-process_wait/3|process_wait/3]) ``` From a2e19bd483dd900ba29e2b900bee7f2457623b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= Date: Fri, 1 Aug 2025 21:19:52 +0200 Subject: [PATCH 122/122] add process module to all_modules test --- tests/scryer/cli/src_tests/all_modules.stdin | 1 + tests/scryer/cli/src_tests/all_modules.stdout | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/scryer/cli/src_tests/all_modules.stdin b/tests/scryer/cli/src_tests/all_modules.stdin index c61818fe..24338cf0 100644 --- a/tests/scryer/cli/src_tests/all_modules.stdin +++ b/tests/scryer/cli/src_tests/all_modules.stdin @@ -27,6 +27,7 @@ use_module(library(ordsets)). use_module(library(os)). use_module(library(pairs)). use_module(library(pio)). +use_module(library(process)). use_module(library(queues)). use_module(library(random)). use_module(library(reif)). diff --git a/tests/scryer/cli/src_tests/all_modules.stdout b/tests/scryer/cli/src_tests/all_modules.stdout index 4e32a715..5ae49ac4 100644 --- a/tests/scryer/cli/src_tests/all_modules.stdout +++ b/tests/scryer/cli/src_tests/all_modules.stdout @@ -45,3 +45,4 @@ true. true. true. + true.