From 9e1e99f96188f484fafb3e1ee32bd656eeaaa2ab Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 15 Mar 2025 13:19:26 -0700 Subject: [PATCH] Revert "remove Term" This reverts commit 3b5879841aedecba5057c70c71da0ba23e5cd84a. --- build/instructions_template.rs | 12 +- src/allocator.rs | 17 +- src/arithmetic.rs | 236 +++--- src/atom_table.rs | 60 +- src/codegen.rs | 978 +++++++++++------------- src/debray_allocator.rs | 259 +++---- src/forms.rs | 248 +++--- src/functor_macro.rs | 9 + src/heap_iter.rs | 78 +- src/heap_print.rs | 18 +- src/indexing.rs | 169 ++--- src/iterators.rs | 429 ++++++----- 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 | 998 ++++++++++--------------- src/machine/dispatch.rs | 6 +- src/machine/gc.rs | 31 +- src/machine/heap.rs | 289 +++---- src/machine/lib_machine/mod.rs | 128 ++-- 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 | 738 ++++++++---------- src/machine/raw_block.rs | 16 +- src/machine/stack.rs | 7 - src/machine/streams.rs | 97 +-- 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 | 551 +++++--------- src/parser/lexer.rs | 136 ++-- src/parser/parser.rs | 997 +++++++++--------------- src/raw_block.rs | 2 +- src/read.rs | 275 ++++++- 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, 3684 insertions(+), 4475 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); - - match name { - atom!("pi") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(std::f64::consts::PI)), - )), - atom!("epsilon") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(std::f64::EPSILON)), - )), - atom!("e") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(std::f64::consts::E)), - )), - _ => unreachable!(), - } - } - (HeapCellValueTag::F64, n) => { - interm.push(ArithmeticTerm::Number(Number::Float(*n))); - } - _ => { - return Err(ArithmeticError::NonEvaluableFunctor(c, 0)); - } - ); + fn iter(self) -> Result; +} + +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(); - - while let Some(term) = iter.next() { - read_heap_cell!(term, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { - let lvl = iter.level(); - - let r = match self.marker.var_data.var_locs_to_nums.get(VarPtrIndex { chunk_num, term_loc }) { - VarPtr::Numbered(var_num) => { - let old_r = self.marker.get_var_binding(var_num); - - if lvl == Level::Root { - self.marker.mark_non_callable(var_num, arg, context, &mut code) - } else if context.is_last() || old_r.reg_num() == 0 { - let r = old_r; - - if r.reg_num() == 0 { - self.marker.mark_var::( - 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) + + for term_ref in src.iter()? { + match term_ref? { + ArithTermRef::Literal(c) => push_literal(&mut self.interm, &c)?, + ArithTermRef::Var(lvl, cell, name) => { + let var_num = name.to_var_num().unwrap(); + + let r = if lvl == Level::Shallow { + self.marker + .mark_non_callable(var_num, arg, term_loc, cell, &mut code) + } else if term_loc.is_last() || cell.get().norm().reg_num() == 0 { + let r = self.marker.get_binding(var_num); + + if r.reg_num() == 0 { + self.marker.mark_var::( + var_num, lvl, cell, term_loc, &mut code, + ); + cell.get().norm() + } else { + self.marker.increment_running_count(var_num); + r } + } else { + self.marker.increment_running_count(var_num); + cell.get().norm() }; self.interm.push(ArithmeticTerm::Reg(r)); } - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - push_literal(&mut self.interm, atom_as_cell!(name))?; - } else { - code.push_back(self.instr_from_clause(name, arity)?); - } - } - _ => { - push_literal(&mut self.interm, term)?; + ArithTermRef::Op(name, arity) => { + code.push_back(self.instr_from_clause(name, arity)?); } - ); + } } Ok((code, self.interm.pop())) 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); - } - } - } + + for term in iter { + match term { + TermRef::AnonVar(lvl @ Level::Shallow) => { + if let GenContext::Head = context { + self.marker.advance_arg(); + } else { + self.marker + .mark_anon_var::(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)); - } - } 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); - } + 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() + }; - target.push_back(Target::to_structure(lvl, name, arity, r)); + self.marker + .mark_non_var::(lvl, context, cell, &mut target); + target.push_back(Target::to_structure(lvl, name, terms_range.end, cell.get())); - let free_list_regs: Vec<_> = (heap_loc + 1 ..= heap_loc + arity) - .map(|subterm_loc| { - let (subterm_loc, subterm) = subterm_index(iter.deref(), subterm_loc); + >::add_term_to_free_list( + self, + cell.get(), + ); - self.subterm_to_instr::( - subterm, subterm_loc, context, index_ptrs, &mut target, - ) - }) - .collect(); + for subterm in &terms[terms_range.clone()] { + self.subterm_to_instr::(subterm, context, &mut target); + } - for r_opt in free_list_regs { - if let Some(r) = r_opt { - >::add_subterm_to_free_list( - self, r, - ); - } - } + for subterm in &terms[terms_range] { + >::add_subterm_to_free_list( + self, subterm, + ); } } - (HeapCellValueTag::Lis, l) => { - let heap_loc = iter.focus().value() as usize; - let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); - - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - - target.push_back(Target::to_list(lvl, r)); + TermRef::Cons(lvl, cell, head, tail) => { + self.marker + .mark_non_var::(lvl, context, cell, &mut target); + target.push_back(Target::to_list(lvl, 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); + self.subterm_to_instr::(head, context, &mut target); + self.subterm_to_instr::(tail, context, &mut target); - let head_r_opt = self.subterm_to_instr::( - head, - head_loc, - context, - index_ptrs, - &mut target, + >::add_subterm_to_free_list( + self, head, ); - - let tail_r_opt = self.subterm_to_instr::( - tail, - tail_loc, - context, - index_ptrs, - &mut target, + >::add_subterm_to_free_list( + self, tail, ); - - if let Some(r) = head_r_opt { - >::add_subterm_to_free_list( - self, r, - ); - } - - if let Some(r) = tail_r_opt { - >::add_subterm_to_free_list( - self, r, - ); - } } - (HeapCellValueTag::PStrLoc, pstr_loc) => { - let heap_loc = iter.focus().value() as usize; - let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - let HeapStringScan { string, tail_idx } = iter.scan_slice_to_str(pstr_loc); + TermRef::Literal(lvl @ Level::Shallow, cell, constant) => { + self.marker + .mark_non_var::(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, Rc::new(string.to_owned()), r)); + 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); - let (tail_loc, tail) = subterm_index(iter.deref(), tail_idx); - self.subterm_to_instr::( - tail, tail_loc, context, index_ptrs, &mut target, - ); + target.push_back(Target::to_pstr(lvl, string.clone(), cell.get())); + target.push_back(Target::constant_subterm(Literal::Atom(atom!("[]")))); } - _ if lvl == Level::Shallow => { - if term.is_constant() { - let heap_loc = iter.focus().value() as usize; - let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(Target::to_constant(lvl, term, r)); - } + TermRef::Var(lvl @ Level::Shallow, cell, var) => { + self.marker.mark_var::( + 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!("number", r) - } else if Number::try_from(first_arg).is_ok() { + _ => { + instr!("$fail") + } + }, + InlinedClauseType::IsNumber(..) => match terms[0] { + Term::Literal(_, Literal::Float(_)) + | Term::Literal(_, Literal::Rational(_)) + | Term::Literal(_, Literal::Integer(_)) + | Term::Literal(_, Literal::Fixnum(_)) => { instr!("$succeed") - } else { + } + Term::Var(ref vr, ref name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); + + instr!("number", r) + } + _ => { instr!("$fail") } - } - InlinedClauseType::IsNonVar(..) => { - self.marker.reset_arg(1); + }, + InlinedClauseType::IsNonVar(..) => match terms[0] { + Term::AnonVar => { + instr!("$fail") + } + Term::Var(ref vr, ref name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); - if let Some(r) = variable_marker(&mut self.marker) { instr!("nonvar", r) - } else if first_arg.is_var() { - instr!("$fail") - } else { + } + _ => { instr!("$succeed") } - } - InlinedClauseType::IsInteger(..) => { - self.marker.reset_arg(1); + }, + InlinedClauseType::IsInteger(..) => match &terms[0] { + Term::Literal(_, Literal::Integer(_)) | Term::Literal(_, Literal::Fixnum(_)) => { + instr!("$succeed") + } + Term::Var(ref vr, name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); - if let Some(r) = variable_marker(&mut self.marker) { instr!("integer", r) - } else { - match Number::try_from(first_arg) { - Ok(Number::Integer(_) | Number::Fixnum(_)) => { - instr!("$succeed") - } - _ => { - instr!("$fail") - } - } } - } - InlinedClauseType::IsVar(..) => { - self.marker.reset_arg(1); + _ => { + instr!("$fail") + } + }, + InlinedClauseType::IsVar(..) => match terms[0] { + Term::Literal(..) + | Term::Clause(..) + | Term::Cons(..) + | Term::PartialString(..) + | Term::CompleteString(..) => { + instr!("$fail") + } + Term::AnonVar => { + instr!("$succeed") + } + Term::Var(ref vr, ref name) => { + self.marker.reset_arg(1); + + let r = self.marker.mark_non_callable( + name.to_var_num().unwrap(), + 1, + term_loc, + vr, + code, + ); - if let Some(r) = variable_marker(&mut self.marker) { instr!("var", r) - } else if first_arg.is_var() { - instr!("$succeed") - } else { - instr!("$fail") } - } + }, }; // inlined predicates are never counted, so this overrides nothing. @@ -877,27 +786,25 @@ impl CodeGenerator { fn compile_arith_expr( &mut self, - terms: &mut FocusedHeapRefMut, - term_loc: usize, + term: &Term, target_int: usize, - context: GenContext, + term_loc: GenContext, arg: usize, ) -> Result { let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int); - evaluator.compile_is(terms, term_loc, context, arg) + evaluator.compile_is(term, term_loc, arg) } fn compile_is_call( &mut self, - terms: &mut FocusedHeapRefMut, - term_loc: usize, + terms: &[Term], code: &mut CodeDeque, - context: GenContext, + term_loc: GenContext, call_policy: CallPolicy, ) -> Result<(), CompilationError> { macro_rules! compile_expr { - ($self:expr, $terms:expr, $context:expr, $code:expr) => {{ - let (acode, at) = $self.compile_arith_expr($terms, term_loc + 2, 1, $context, 2)?; + ($self:expr, $terms:expr, $term_loc:expr, $code:expr) => {{ + let (acode, at) = $self.compile_arith_expr($terms, 1, $term_loc, 2)?; $code.extend(acode.into_iter()); at }}; @@ -905,48 +812,70 @@ impl CodeGenerator { self.marker.reset_arg(2); - let var = heap_bound_store( - terms.heap, - heap_bound_deref(terms.heap, heap_loc_as_cell!(term_loc + 1)), - ); + let at = match terms[0] { + Term::Var(ref vr, ref name) => { + let var_num = name.to_var_num().unwrap(); + + if self.marker.var_data.records[var_num].num_occurrences > 1 { + self.marker.mark_var::( + var_num, + Level::Shallow, + vr, + term_loc, + code, + ); + + self.marker.mark_safe_var_unconditionally(var_num); + compile_expr!(self, &terms[1], term_loc, code) + } else { + self.marker + .mark_anon_var::(Level::Shallow, term_loc, code); - let at = read_heap_cell!(var, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { - let chunk_num = context.chunk_num(); + if let Term::Var(ref vr, ref var) = &terms[1] { + let var_num = var.to_var_num().unwrap(); - match self.marker.var_data.var_locs_to_nums.get( - VarPtrIndex { chunk_num, term_loc }, - ) { - VarPtr::Numbered(var_num) => { + // if var is an anonymous variable, insert + // is/2 call so that an instantiation error is + // thrown when the predicate is run. if self.marker.var_data.records[var_num].num_occurrences > 1 { self.marker.mark_var::( var_num, Level::Shallow, - context, + vr, + term_loc, code, ); self.marker.mark_safe_var_unconditionally(var_num); + + let at = ArithmeticTerm::Reg(vr.get().norm()); + self.add_call(code, instr!("$get_number", at), call_policy); + + return Ok(()); } } - VarPtr::Anon => {} - }; - compile_expr!(self, terms, context, code) + compile_expr!(self, &terms[1], term_loc, code) + } + } + Term::Literal( + _, + c @ Literal::Integer(_) + | c @ Literal::Float(_) + | c @ Literal::Rational(_) + | c @ Literal::Fixnum(_), + ) => { + let v = HeapCellValue::from(c); + code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1))); + + self.marker.advance_arg(); + compile_expr!(self, &terms[1], term_loc, code) } _ => { - if Number::try_from(var).is_ok() { - let v = HeapCellValue::from(var); - code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1))); - - self.marker.advance_arg(); - compile_expr!(self, terms, context, code) - } else { - code.push_back(instr!("$fail")); - return Ok(()); - } + code.push_back(instr!("$fail")); + return Ok(()); } - ); + }; let at = at.unwrap_or(interm!(1)); self.add_call(code, instr!("is", temp_v!(1), at), call_policy); @@ -955,18 +884,18 @@ impl CodeGenerator { fn compile_seq( &mut self, - mut focused_heap: FocusedHeapRefMut, clauses: &ChunkedTermVec, code: &mut CodeDeque, ) -> Result<(), CompilationError> { + let mut chunk_num = 0; let mut branch_code_stack = BranchCodeStack::new(); let mut clause_iter = ClauseIterator::new(clauses); while let Some(clause_item) = clause_iter.next() { match clause_item { - ClauseItem::Chunk { chunk_num, terms } => { + ClauseItem::Chunk { terms } => { for (idx, term) in terms.iter().enumerate() { - let context = if idx + 1 < terms.len() { + let term_loc = if idx + 1 < terms.len() { GenContext::Mid(chunk_num) } else { self.marker.in_tail_position = clause_iter.in_tail_position(); @@ -995,7 +924,7 @@ impl CodeGenerator { if chunk_num == 0 { code.push_back(instr!("neck_cut")); } else { - let r = self.marker.get_var_binding(var_num); + let r = self.marker.get_binding(var_num); code.push_back(instr!("cut", r)); } @@ -1009,7 +938,7 @@ impl CodeGenerator { } &QueryTerm::LocalCut { var_num, cut_prev } => { let code = branch_code_stack.code(code); - let r = self.marker.get_var_binding(var_num); + let r = self.marker.get_binding(var_num); code.push_back(if cut_prev { instr!("cut_prev", r) @@ -1028,51 +957,31 @@ impl CodeGenerator { } } &QueryTerm::Clause( - ref clause @ QueryClause { - ct: ClauseType::BuiltIn(BuiltInClauseType::Is(..)), - call_policy, - .. - }, + _, + ClauseType::BuiltIn(BuiltInClauseType::Is(..)), + ref terms, + call_policy, ) => self.compile_is_call( - &mut focused_heap, - clause.term_loc(), + terms, branch_code_stack.code(code), - context, + term_loc, call_policy, )?, - &QueryTerm::Clause( - ref clause @ QueryClause { - ct: ClauseType::Inlined(ref ct), - .. - }, - ) => self.compile_inlined( - ct, - &mut focused_heap, - clause.term_loc(), - context, - branch_code_stack.code(code), - )?, + &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => { + self.compile_inlined( + ct, + terms, + term_loc, + branch_code_stack.code(code), + )? + } &QueryTerm::Fail => { branch_code_stack.code(code).push_back(instr!("$fail")); } - &QueryTerm::Succeed => { - let code = branch_code_stack.code(code); - - if self.marker.in_tail_position && self.marker.var_data.allocates { - code.push_back(instr!("deallocate")); - } - - code.push_back(if self.marker.in_tail_position { - instr!("$succeed").into_execute() - } else { - instr!("$succeed") - }); - } - QueryTerm::Clause(clause) => { + term @ &QueryTerm::Clause(..) => { self.compile_query_line( - &mut focused_heap, - clause, - context, + term, + term_loc, branch_code_stack.code(code), ); @@ -1083,6 +992,7 @@ impl CodeGenerator { } } + chunk_num += 1; self.marker.in_tail_position = false; self.marker.reset_contents(); } @@ -1130,32 +1040,20 @@ impl CodeGenerator { pub(crate) fn compile_rule( &mut self, - heap: &mut Heap, - rule: &mut Rule, + rule: &Rule, var_data: VarData, ) -> Result { - 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())); - - let mut stack = Stack::uninitialized(); - let iter = query_iterator::(&mut term.heap, &mut stack, clause.term_loc()); + fn compile_query_line(&mut self, term: &QueryTerm, term_loc: GenContext, code: &mut CodeDeque) { + self.marker.reset_arg(term.arity()); - let query = self.compile_target::(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))); - - read_heap_cell!(head_cell, - (HeapCellValueTag::Str, s) => { - let arity = cell_as_atom_cell!(heap[s]).get_arity(); - - self.reset_arg(arity); - self.arity = arity; + fn reset_at_head(&mut self, args: &[Term]) { + self.reset_arg(args.len()); + self.arity = args.len(); - for (c_idx, heap_idx) in (s+1 ..= s+arity).enumerate() { - let arg = heap[heap_idx]; - - if arg.is_var() { - let var = heap_bound_store( - heap, - heap_bound_deref(heap, arg), - ); - - if !var.is_var() { - continue; - } + for (idx, arg) in args.iter().enumerate() { + if let Term::Var(_, ref var) = arg { + let var_num = var.to_var_num().unwrap(); + let r = self.get_binding(var_num); - let term_loc = var.get_value() as usize; - - match self.var_data.var_locs_to_nums.get( - VarPtrIndex { chunk_num: 0, term_loc }, - ) { - VarPtr::Numbered(var_num) => { - let r = self.get_var_binding(var_num); - - if !r.is_perm() && r.reg_num() == 0 { - self.in_use.insert(c_idx + 1); - self.shallow_temp_mappings.insert(c_idx + 1, var_num); - self.var_data.records[var_num] - .allocation - .set_register(c_idx + 1); - } - } - VarPtr::Anon => {} - } - } + if !r.is_perm() && r.reg_num() == 0 { + self.in_use.insert(idx + 1); + self.shallow_temp_mappings.insert(idx + 1, var_num); + self.var_data.records[var_num] + .allocation + .set_register(idx + 1); } } - _ => { - self.reset_arg(0); - } - ); + } } fn reset_arg(&mut self, arity: usize) { 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)) +pub trait ClauseInfo { + fn is_consistent(&self, clauses: &PredicateQueue) -> bool { + match clauses.first() { + Some(cl) => { + self.name() == ClauseInfo::name(cl) && self.arity() == ClauseInfo::arity(cl) + } + None => true, } - _ => { - if value.is_ref() { - clause_predicate_key(heap, value.get_value() as usize) - } else { - None + } + + fn name(&self) -> Option; + fn arity(&self) -> usize; +} + +impl ClauseInfo for PredicateKey { + #[inline] + fn name(&self) -> Option { + Some(self.0) + } + + #[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, } - ) + } } -pub fn clause_predicate_key(heap: &impl SizedHeap, term_loc: usize) -> Option { - let key_opt = term_predicate_key(heap, term_loc); +impl ClauseInfo for Rule { + fn name(&self) -> Option { + Some(self.head.0) + } - if Some((atom!(":-"), 2)) == key_opt { - term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| term_predicate_key(heap, arg_loc)) - } else { - key_opt + fn arity(&self) -> usize { + self.head.1.len() + } +} + +impl ClauseInfo for PredicateClause { + fn name(&self) -> Option { + 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() - } - }; - - let arity = clause_predicate_key(heap, focus) - .map(|(_name, arity)| arity) - .unwrap_or(0); - - read_heap_cell!(heap_bound_store(heap, heap_bound_deref(heap, heap[focus])), - (HeapCellValueTag::Str, s) => { - Some(s+1 ..= s+arity) - } - _ => { - None + pub(crate) fn args(&self) -> Option<&[Term]> { + match self { + PredicateClause::Fact(term, ..) => match &term.head { + Term::Clause(_, _, args) => Some(args), + _ => None, + }, + PredicateClause::Rule(rule, ..) => { + if rule.head.1.is_empty() { + None + } else { + Some(&rule.head.1) + } } - ) + } } } @@ -699,7 +725,7 @@ impl ArenaFrom 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![]; - - match Number::try_from(constant) { - Ok(Number::Integer(n)) => { - let result = (&*n).try_into(); - if let Ok(value) = result { - constants.push( - Fixnum::build_with_checked(value) - .map(|n| fixnum_as_cell!(n)) - .unwrap(), - ); - } - } - _ => {} - } +pub(crate) fn constant_key_alternatives(constant: Literal) -> Option { + let n = match &constant { + Literal::Rational(n) if n.denominator().is_one() => n.numerator(), + Literal::Integer(n) => n, + _ => return None, + }; - /* - match constant { - Literal::Atom(ref name) => { - if let Some(c) = name.as_char() { - constants.push(Literal::Char(c)); - } - } - Literal::Char(c) => { - let atom = AtomTable::build_with(atom_tbl, &c.to_string()); - constants.push(Literal::Atom(atom)); - } - /* - // constant_to_literal takes care of the downward conversion from Integer to Fixnum - // if possible. - Literal::Fixnum(ref n) => { - constants.push(Literal::Integer(arena_alloc!(n, arena))); - } - */ - Literal::Integer(ref n) => { - let result = (&**n).try_into(); - if let Ok(value) = result { - Fixnum::build_with_checked(value) - .map(|n| { - constants.push(Literal::Fixnum(n)); - }) - .unwrap(); - } - } - _ => {} + if let Ok(n) = n.try_into() { + Fixnum::build_with_checked(n).map(Literal::Fixnum).ok() + } else { + None } - */ - - constants } #[derive(Debug)] @@ -1464,9 +1423,13 @@ impl 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, - ); + match optimal_arg { + &Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => { + clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); + self.index_list(index); } - (HeapCellValueTag::Lis - // | HeapCellValueTag::CStr - | HeapCellValueTag::PStrLoc) => { + &Term::Cons(..) | &Term::PartialString(..) | &Term::CompleteString(..) => { clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); self.index_list(index); } - _ if optimal_arg.is_constant() => { - let overlapping_constants = self.index_constant(optimal_arg, index); - - clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( - self.optimal_index, - 0, - optimal_arg, - overlapping_constants, - ); + &Term::Clause(_, name, ref terms) => { + clause_index_info.opt_arg_index_key = + OptArgIndexKey::Structure(self.optimal_index, 0, name, terms.len()); + + self.index_structure(name, terms.len(), index); + } + &Term::Literal(_, constant) => { + let overlapping_constants = self.index_constant(constant, index); + + clause_index_info.opt_arg_index_key = + OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants); } _ => {} - ); + } } pub(crate) fn no_indices(&mut self) -> bool { 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) struct TargetIterator { - shallow_terms: IndexMap, FxBuildHasher>, - root_terms: BitSet, - iter: I, - arg_c: usize, +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), } -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); - - read_heap_cell!(cell, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h == root_loc { - break; - } else { - root_loc = h; - } +impl<'a> TermIterState<'a> { + pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> { + match term { + Term::AnonVar => TermIterState::AnonVar(lvl), + Term::Clause(cell, name, subterms) => { + TermIterState::Clause(lvl, 0, cell, *name, subterms) } - (HeapCellValueTag::Lis) => { - root_terms.insert(root_loc); - break; + Term::Cons(cell, head, tail) => { + TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()) } - _ => { - if cell.is_ref() { - root_terms.insert(cell.get_value() as usize); - } - - break; + Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant), + Term::PartialString(cell, string_buf, tail) => { + TermIterState::InitialPartialString(lvl, cell, string_buf.clone(), tail) + } + Term::CompleteString(cell, string) => { + TermIterState::CompleteString(lvl, cell, string.clone()) } - ); + Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()), + } } - - root_loc } -fn find_root_terms(heap: &impl SizedHeap, root_loc: usize) -> (usize, BitSet) { - let mut root_terms = BitSet::::default(); - let root_loc = record_path(heap, &mut root_terms, root_loc); - (root_loc, root_terms) +#[derive(Debug)] +pub(crate) struct QueryIterator<'a> { + state_stack: Vec>, } -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); +impl<'a> QueryIterator<'a> { + fn push_subterm(&mut self, lvl: Level, term: &'a Term) { + self.state_stack + .push(TermIterState::subterm_to_state(lvl, term)); } - shallow_terms_map -} - -impl 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); + /* + 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(); - Self { - shallow_terms, - root_terms, - iter, - arg_c, - } + QueryIterator { state_stack } } + */ + + fn from_term(term: &'a Term) -> Self { + let state = match term { + Term::AnonVar + | Term::Cons(..) + | Term::Literal(..) + | Term::PartialString(..) + | Term::CompleteString(..) => { + return QueryIterator { + state_stack: vec![], + } + } + Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms), + Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()), + }; - fn current_level(&self, arg_c_inc: usize) -> Level { - let current_focus = self.iter.focus().value() as usize; - - if self.root_terms.contains(current_focus) { - return Level::Root; + QueryIterator { + state_stack: vec![state], } + } - if let Some(shallow_terms) = self.shallow_terms.get(&(self.arg_c + arg_c_inc)) { - if shallow_terms.contains(current_focus) { - return Level::Shallow; + fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) { + match term { + QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => { + self.state_stack + .push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms)); + } + QueryTerm::Clause(ref cell, ref ct, ref terms, _) => { + self.state_stack + .push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms)); } + _ => {} } + } - Level::Deep + pub fn new(term: &'a QueryTerm) -> Self { + let mut iter = QueryIterator { + state_stack: vec![], + }; + iter.extend_state(Level::Root, term); + iter } } -impl<'a, const SKIP_ROOT: bool> TermIterator for FactIterator<'a, SKIP_ROOT> { - fn focus(&self) -> IterStackLoc { - self.iter.focus() - } +impl<'a> Iterator for QueryIterator<'a> { + type Item = TermRef<'a>; - fn level(&mut self) -> Level { - let lvl = self.current_level(1); + fn next(&mut self) -> Option { + while let Some(iter_state) = self.state_stack.pop() { + match iter_state { + TermIterState::AnonVar(lvl) => { + return Some(TermRef::AnonVar(lvl)); + } + TermIterState::Clause(lvl, child_num, cell, name, child_terms) => { + if child_num == child_terms.len() { + match name { + atom!("$call") if lvl == Level::Root => { + self.push_subterm(Level::Shallow, &child_terms[0]); + } + _ => { + return match lvl { + Level::Root => None, + lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)), + } + } + }; + } else { + self.state_stack.push(TermIterState::Clause( + lvl, + child_num + 1, + cell, + name, + child_terms, + )); + + self.push_subterm(lvl.child_level(), &child_terms[child_num]); + } + } + TermIterState::InitialCons(lvl, cell, head, tail) => { + self.state_stack + .push(TermIterState::FinalCons(lvl, cell, head, tail)); - if let Level::Shallow = lvl { - self.arg_c += 1; + self.push_subterm(lvl.child_level(), tail); + self.push_subterm(lvl.child_level(), head); + } + TermIterState::InitialPartialString(lvl, cell, string, tail) => { + self.state_stack + .push(TermIterState::FinalPartialString(lvl, cell, string, tail)); + self.push_subterm(lvl.child_level(), tail); + } + TermIterState::FinalPartialString(lvl, cell, string, tail) => { + return Some(TermRef::PartialString(lvl, cell, string, tail)); + } + TermIterState::CompleteString(lvl, cell, string) => { + return Some(TermRef::CompleteString(lvl, cell, string)); + } + TermIterState::FinalCons(lvl, cell, head, tail) => { + return Some(TermRef::Cons(lvl, cell, head, tail)); + } + TermIterState::Literal(lvl, cell, constant) => { + return Some(TermRef::Literal(lvl, cell, constant)); + } + TermIterState::Var(lvl, cell, var_ptr) => { + return Some(TermRef::Var(lvl, cell, var_ptr)); + } + }; } - lvl + None } } -impl<'a, const SKIP_ROOT: bool> TermIterator for QueryIterator<'a, SKIP_ROOT> { - fn focus(&self) -> IterStackLoc { - self.iter.focus() +#[derive(Debug)] +pub(crate) struct FactIterator<'a> { + state_queue: VecDeque>, + iterable_root: RootIterationPolicy, +} + +impl<'a> FactIterator<'a> { + fn push_subterm(&mut self, lvl: Level, term: &'a Term) { + self.state_queue + .push_back(TermIterState::subterm_to_state(lvl, term)); } - fn level(&mut self) -> Level { - let lvl = self.current_level(0); + pub(crate) fn from_rule_head_clause(terms: &'a [Term]) -> Self { + let state_queue = terms + .iter() + .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt)) + .collect(); - if let Level::Shallow = lvl { - self.arg_c += 1; + FactIterator { + state_queue, + iterable_root: RootIterationPolicy::NotIterated, } + } - lvl + fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self { + let states = match term { + Term::AnonVar => { + vec![TermIterState::AnonVar(Level::Root)] + } + Term::Clause(cell, name, terms) => { + vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)] + } + Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons( + Level::Root, + cell, + head.as_ref(), + tail.as_ref(), + )], + Term::PartialString(cell, string, tail) => { + vec![TermIterState::InitialPartialString( + Level::Root, + cell, + string.clone(), + tail, + )] + } + Term::CompleteString(cell, string) => { + vec![TermIterState::CompleteString( + Level::Root, + cell, + string.clone(), + )] + } + Term::Literal(cell, constant) => { + vec![TermIterState::Literal(Level::Root, cell, constant)] + } + Term::Var(cell, var_ptr) => { + vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())] + } + }; + + FactIterator { + state_queue: VecDeque::from(states), + iterable_root, + } } } -impl Iterator for TargetIterator { - type Item = HeapCellValue; +impl<'a> Iterator for FactIterator<'a> { + type Item = TermRef<'a>; fn next(&mut self) -> Option { - loop { - let next_term = self.iter.next(); - - if next_term.is_none() { - return None; - } + while let Some(state) = self.state_queue.pop_front() { + match state { + TermIterState::AnonVar(lvl) => { + return Some(TermRef::AnonVar(lvl)); + } + TermIterState::Clause(lvl, _, cell, name, child_terms) => { + for child_term in child_terms { + self.push_subterm(lvl.child_level(), child_term); + } - let focus = self.iter.focus().value() as usize; + match lvl { + Level::Root if !self.iterable_root.iterable() => continue, + _ => return Some(TermRef::Clause(lvl, cell, name, child_terms)), + }; + } + TermIterState::InitialCons(lvl, cell, head, tail) => { + self.push_subterm(Level::Deep, head); + self.push_subterm(Level::Deep, tail); - if SKIP_ROOT && self.root_terms.contains(focus) { - continue; - } else { - return next_term; + return Some(TermRef::Cons(lvl, cell, head, tail)); + } + TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => { + self.push_subterm(Level::Deep, tail); + return Some(TermRef::PartialString(lvl, cell, string_buf, tail)); + } + TermIterState::CompleteString(lvl, cell, atom) => { + return Some(TermRef::CompleteString(lvl, cell, atom)); + } + TermIterState::Literal(lvl, cell, constant) => { + return Some(TermRef::Literal(lvl, cell, constant)) + } + TermIterState::Var(lvl, cell, var_ptr) => { + return Some(TermRef::Var(lvl, cell, var_ptr)); + } + _ => {} } } - } -} - -impl Deref for TargetIterator { - type Target = Heap; - fn deref(&self) -> &Self::Target { - self.iter.deref() - } -} - -impl FocusedHeapIter for TargetIterator { - fn focus(&self) -> IterStackLoc { - self.iter.focus() + None } } -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) fn post_order_iter(term: &'_ Term) -> QueryIterator { + QueryIterator::from_term(term) } -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); + fn try_set_chunk_at_inlined_boundary(&mut self) -> bool { + if self.current_chunk_type.is_last() { + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; + true + } else { + false + } + } - // second arg is true to iterate the root, which may be a variable - while let Some(subterm) = iter.next() { - if !subterm.is_var() { - lvl = Level::Deep; - continue; - } + fn try_set_chunk_at_call_boundary(&mut self) -> bool { + if self.current_chunk_type.is_last() { + self.current_chunk_num += 1; + true + } else { + self.current_chunk_type = ChunkType::Last; + false + } + } - let var_loc = subterm.get_value() as usize; - let var = to_classified_var(inverse_var_locs, var_loc); + fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) { + let classify_info = ClassifyInfo { arg_c, arity }; - self.probe_body_var( - context, - VarInfo { - var, + // second arg is true to iterate the root, which may be a variable + for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) { + if let TermRef::Var(lvl, _, var_ptr) = term_ref { + // root terms are shallow here (since we're iterating a + // body term) so take the child level. + let lvl = lvl.child_level(); + self.probe_body_var(VarInfo { + var_ptr, lvl, classify_info, - chunk_type: context.chunk_type(), - }, - ); + chunk_type: self.current_chunk_type, + }); + } } } - fn probe_body_var(&mut self, context: GenContext, var_info: VarInfo) { - let chunk_num = context.chunk_num(); - let branch_info_v = self.branch_map.entry(var_info.var).or_default(); + fn probe_body_var(&mut self, var_info: VarInfo) { + let term_loc = self + .current_chunk_type + .to_gen_context(self.current_chunk_num); + + let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone()).or_default(); let needs_new_branch = if let Some(last_bi) = branch_info_v.last() { !self.root_set.contains(&last_bi.branch_num) @@ -439,14 +373,15 @@ impl VariableClassifier { let branch_info = branch_info_v.last_mut().unwrap(); let needs_new_chunk = if let Some(last_ci) = branch_info.chunks.last() { - last_ci.term_loc.chunk_num() != chunk_num + last_ci.chunk_num != self.current_chunk_num } else { true }; if needs_new_chunk { branch_info.chunks.push(ChunkInfo { - term_loc: context, + chunk_num: self.current_chunk_num, + term_loc, vars: vec![], }); } @@ -455,81 +390,68 @@ impl VariableClassifier { chunk_info.vars.push(var_info); } - fn probe_in_situ_var(&mut self, context: GenContext, var_num: usize) { + fn probe_in_situ_var(&mut self, var_num: usize) { let classify_info = ClassifyInfo { arg_c: 1, arity: 1 }; let var_info = VarInfo { - var: ClassifiedVar::InSitu { var_num }, + var_ptr: VarPtr::from(Var::InSitu(var_num)), classify_info, - chunk_type: context.chunk_type(), + chunk_type: self.current_chunk_type, lvl: Level::Shallow, }; - self.probe_body_var(context, var_info); + self.probe_body_var(var_info); } - fn classify_head_variables<'a, LS: LoadState<'a>>( - &mut self, - loader: &mut Loader<'a, LS>, - term: &TermWriteResult, - head_loc: usize, - ) -> Result<(), CompilationError> { - let heap = &mut LS::machine_st(&mut loader.payload).heap; - let arity = term_predicate_key(heap, head_loc) - .and_then(|(_, arity)| Some(arity)) - .ok_or(CompilationError::InvalidRuleHead)?; - - let mut classify_info = ClassifyInfo { arg_c: 1, arity }; - - if arity > 0 { - let (_term_loc, value) = subterm_index(heap, head_loc); - let str_offset = value.get_value() as usize; - - debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str); - - for idx in str_offset + 1..=str_offset + arity { - let mut lvl = Level::Shallow; - let mut stack = Stack::uninitialized(); - let mut iter = fact_iterator::(heap, &mut stack, idx); - - while let Some(subterm) = iter.next() { - if !subterm.is_var() { - lvl = Level::Deep; - continue; - } - - let term_loc = subterm.get_value() as usize; - let var = to_classified_var(&term.inverse_var_locs, term_loc); + fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> { + match term { + Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {} + _ => return Err(CompilationError::InvalidRuleHead), + } - // the body of the if let here is an inlined - // "probe_head_var". note the difference between it - // and "probe_body_var". - let branch_info_v = self.branch_map.entry(var).or_default(); - let needs_new_branch = branch_info_v.is_empty(); + let mut classify_info = ClassifyInfo { + arg_c: 1, + arity: term.arity(), + }; - if needs_new_branch { - branch_info_v.push(BranchInfo::new(self.current_branch_num.clone())); - } + if let Term::Clause(_, _, terms) = term { + for term in terms.iter() { + for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) { + if let TermRef::Var(lvl, _, var_ptr) = term_ref { + // a body term, so we need the child level here. + let lvl = lvl.child_level(); + + // the body of the if let here is an inlined + // "probe_head_var". note the difference between it + // and "probe_body_var". + let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default(); + let needs_new_branch = branch_info_v.is_empty(); + + if needs_new_branch { + branch_info_v.push(BranchInfo::new(self.current_branch_num.clone())); + } - let branch_info = branch_info_v.last_mut().unwrap(); - let needs_new_chunk = branch_info.chunks.is_empty(); + let branch_info = branch_info_v.last_mut().unwrap(); + let needs_new_chunk = branch_info.chunks.is_empty(); - if needs_new_chunk { - branch_info.chunks.push(ChunkInfo { - term_loc: GenContext::Head, - vars: vec![], - }); - } + if needs_new_chunk { + branch_info.chunks.push(ChunkInfo { + chunk_num: self.current_chunk_num, + term_loc: GenContext::Head, + vars: vec![], + }); + } - let chunk_info = branch_info.chunks.last_mut().unwrap(); - let var_info = VarInfo { - var, - classify_info, - chunk_type: ChunkType::Head, - lvl, - }; + let chunk_info = branch_info.chunks.last_mut().unwrap(); + let var_info = VarInfo { + var_ptr, + classify_info, + chunk_type: self.current_chunk_type, + lvl, + }; - chunk_info.vars.push(var_info); + chunk_info.vars.push(var_info); + } } classify_info.arg_c += 1; @@ -539,38 +461,17 @@ impl VariableClassifier { Ok(()) } - fn new_cut_state(&mut self, context: GenContext) -> TraversalState { - let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override { - (var_num, false) - } else if let Some(var_num) = self.global_cut_var_num { - (var_num, true) - } else { - let var_num = self.var_num; - - self.global_cut_var_num = Some(var_num); - self.var_num += 1; - - (var_num, true) - }; - - self.probe_in_situ_var(context, var_num); - - TraversalState::Cut { var_num, is_global } - } - fn classify_body_variables<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - terms: &TermWriteResult, - term_loc: usize, + term: Term, ) -> Result { - 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(); + } + + for (arg_c, term) in terms.iter().enumerate() { + classifier.probe_body_term(arg_c + 1, terms.len(), term); + } - let context = build_stack.current_gen_context(); + build_stack.push_chunk_term(clause_to_query_term( + loader, + name, + terms, + classifier.call_policy, + )); + }; - for (arg_c, term_loc) in - ($term_loc + 1..=$term_loc + $key.1).enumerate() - { - let mut term = - FocusedHeapRefMut::from(loader.machine_heap(), term_loc); - - self.probe_body_term( - arg_c + 1, - $key.1, - &mut term, - &terms.inverse_var_locs, - context, - ); + match term { + Term::Clause( + _, + name @ (atom!("->") | atom!(";") | atom!(",")), + mut terms, + ) if terms.len() == 3 => { + if let Some(last_arg) = terms.last() { + if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg { + terms.pop(); + state_stack.push(TraversalState::Term(Term::Clause( + Cell::default(), + name, + terms, + ))); + } else { + add_chunk(self, name, terms); + } } + } + Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => { + let tail = terms.pop().unwrap(); + let head = terms.pop().unwrap(); - build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( - loader, - $key, - &terms, - HeapCellValue::build_with($tag, $term_loc as u64), - self.call_policy, - ))); - }}; - } + let iter = unfold_by_str(tail, atom!(",")) + .into_iter() + .rev() + .chain(std::iter::once(head)) + .map(TraversalState::Term); - macro_rules! add_qualified_chunk { - ($module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{ - if update_chunk_data(&mut build_stack, $key) { - build_stack.add_chunk(); - } + state_stack.extend(iter); + } + Term::Clause(_, atom!(";"), mut terms) if terms.len() == 2 => { + let tail = terms.pop().unwrap(); + let head = terms.pop().unwrap(); - let context = build_stack.current_gen_context(); + let first_branch_num = self.current_branch_num.split(); + let branches: Vec<_> = std::iter::once(head) + .chain(unfold_by_str(tail, atom!(";")).into_iter()) + .collect(); - for (arg_c, term_loc) in - ($term_loc + 1..=$term_loc + $key.1).enumerate() - { - let mut term = - FocusedHeapRefMut::from(loader.machine_heap(), term_loc); - - self.probe_body_term( - arg_c + 1, - $key.1, - &mut term, - &terms.inverse_var_locs, - context, - ); + let mut branch_numbers = vec![first_branch_num]; + + for idx in 1..branches.len() { + let succ_branch_number = branch_numbers[idx - 1].incr_by_delta(); + + branch_numbers.push(if idx + 1 < branches.len() { + succ_branch_number.split() + } else { + succ_branch_number + }); } - build_stack.push_chunk_term(QueryTerm::Clause( - qualified_clause_to_query_term( - loader, - $key, - $module_name, - &terms, - HeapCellValue::build_with($tag, $term_loc as u64), - self.call_policy, - ), + let build_stack_len = build_stack.len(); + build_stack.reserve_branch(branches.len()); + + state_stack.push(TraversalState::RepBranchNum( + self.current_branch_num.halve_delta(), )); - }}; - } - loop { - let heap = loader.machine_heap(); + let iter = branches.into_iter().zip(branch_numbers.into_iter()); + let final_disjunct_loc = state_stack.len(); - read_heap_cell!(subterm, - (HeapCellValueTag::Str, subterm_loc) => { - let (name, arity) = cell_as_atom_cell!(heap[subterm_loc]) - .get_name_and_arity(); + for (term, branch_num) in iter.rev() { + state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); + state_stack.push(TraversalState::RemoveBranchNum); + state_stack.push(TraversalState::Term(term)); + state_stack.push(TraversalState::AddBranchNum(branch_num)); + } - match (name, arity) { - (atom!("->") | atom!(";") | atom!(","), 3) => { - if blunt_index_ptr(heap, (name, 2), subterm_loc) { - subterm = heap[subterm_loc]; - continue; - } + if let TraversalState::BuildDisjunct(build_stack_len) = + state_stack[final_disjunct_loc] + { + state_stack[final_disjunct_loc] = + TraversalState::BuildFinalDisjunct(build_stack_len); + } - add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc); - } - (atom!(","), 2) => { - let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - let head = heap[head_loc]; - - let iter = unfold_by_str_locs(heap, tail_loc, atom!(",")) - .into_iter() - .rev() - .chain(std::iter::once((head, head_loc))) - .map(|(subterm, term_loc)| { - TraversalState::Term { subterm, term_loc } - }); - state_stack.extend(iter); - } - (atom!(";"), 2) => { - let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - - let head = heap[head_loc]; - - let first_branch_num = self.current_branch_num.split(); - let branches: Vec<_> = std::iter::once((head, head_loc)) - .chain( - unfold_by_str_locs(heap, tail_loc, atom!(";")) - .into_iter(), - ) - .collect(); - - let mut branch_numbers = vec![first_branch_num]; - - for idx in 1..branches.len() { - let succ_branch_number = branch_numbers[idx - 1].incr_by_delta(); - - branch_numbers.push(if idx + 1 < branches.len() { - succ_branch_number.split() - } else { - succ_branch_number - }); - } - - let build_stack_len = build_stack.len(); - build_stack.reserve_branch(branches.len()); - - state_stack.push(TraversalState::RepBranchNum( - self.current_branch_num.halve_delta(), - )); - - let iter = branches.into_iter().zip(branch_numbers.into_iter()); - let final_disjunct_loc = state_stack.len(); - - for ((subterm, term_loc), branch_num) in iter.rev() { - state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); - state_stack.push(TraversalState::RemoveBranchNum); - state_stack.push(TraversalState::Term { subterm, term_loc }); - state_stack.push(TraversalState::AddBranchNum(branch_num)); - } - - if let TraversalState::BuildDisjunct(build_stack_len) = - state_stack[final_disjunct_loc] - { - state_stack[final_disjunct_loc] = - TraversalState::BuildFinalDisjunct(build_stack_len); - } - - build_stack.current_chunk_type = ChunkType::Mid; - build_stack.current_chunk_num += 1; - } - (atom!("->"), 2) => { - let if_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let then_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - - let if_term = heap[if_term_loc]; - let then_term = heap[then_term_loc]; - - let prev_b = if matches!( - state_stack.last(), - Some(TraversalState::RemoveBranchNum) - ) { - // check if the second-to-last element - // is a regular BuildDisjunct, as we - // don't want to add GetPrevLevel in - // case of a TrustMe. - match state_stack.iter().rev().nth(1) { - Some(&TraversalState::BuildDisjunct(preceding_len)) => { - preceding_len + 1 == build_stack.len() - } - _ => false, - } - } else { - false - }; - - state_stack.push(TraversalState::Term { - subterm: then_term, - term_loc: then_term_loc, - }); - state_stack.push(TraversalState::Cut { - var_num: self.var_num, - is_global: false, - }); - state_stack.push(TraversalState::Term { - subterm: if_term, - term_loc: if_term_loc, - }); - state_stack.push(TraversalState::GetCutPoint { - var_num: self.var_num, - prev_b, - }); - - self.var_num += 1; - } - (atom!("\\+"), 1) => { - let not_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let not_term = heap[not_term_loc]; - let build_stack_len = build_stack.len(); - - build_stack.reserve_branch(2); - - let branch_num = self.current_branch_num.split(); - let succ_branch_num = branch_num.incr_by_delta(); - - state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len)); - state_stack.push(TraversalState::Succeed); - state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); - state_stack.push(TraversalState::RepBranchNum(succ_branch_num)); - state_stack.push(TraversalState::Fail); - state_stack.push(TraversalState::CutPrev(self.var_num)); - state_stack.push(TraversalState::ResetGlobalCutVarOverride( - self.global_cut_var_num_override, - )); - state_stack.push(TraversalState::Term { - subterm: not_term, - term_loc: not_term_loc, - }); - state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num)); - state_stack.push(TraversalState::GetCutPoint { - var_num: self.var_num, - prev_b: false, - }); - state_stack.push(TraversalState::AddBranchNum(branch_num)); - - build_stack.current_chunk_type = ChunkType::Mid; - build_stack.current_chunk_num += 1; - - self.var_num += 1; + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; + } + Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => { + let then_term = terms.pop().unwrap(); + let if_term = terms.pop().unwrap(); + + let prev_b = if matches!( + state_stack.last(), + Some(TraversalState::RemoveBranchNum) + ) { + // check if the second-to-last element + // is a regular BuildDisjunct, as we + // don't want to add GetPrevLevel in + // case of a TrustMe. + match state_stack.iter().rev().nth(1) { + Some(&TraversalState::BuildDisjunct(preceding_len)) => { + preceding_len + 1 == build_stack.len() } - (atom!(":"), 2) => { - let module_name_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let predicate_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - let mut focused = FocusedHeapRefMut::from(heap, module_name_loc); - - let module_name = focused.deref_loc(module_name_loc); - let predicate_term = focused.deref_loc(predicate_term_loc); - - read_heap_cell!(module_name, - (HeapCellValueTag::Atom, (module_name, arity)) => { - if arity == 0 { - read_heap_cell!(predicate_term, - (HeapCellValueTag::Str, s) => { - let key = cell_as_atom_cell!(heap[s]) - .get_name_and_arity(); - - add_qualified_chunk!( - module_name, - key, - HeapCellValueTag::Str, - s - ); - } - (HeapCellValueTag::Atom, (predicate_name, predicate_arity)) => { - debug_assert_eq!(predicate_arity, 0); - let key = (predicate_name, predicate_arity); - - add_qualified_chunk!( - module_name, - key, - HeapCellValueTag::Str, - predicate_term_loc - ); - } - _ => {} - ); - - continue 'outer; - } - } - _ => {} - ); - - if update_chunk_data(&mut build_stack, (atom!("call"), 2)) { - build_stack.add_chunk(); - } - - let context = build_stack.current_gen_context(); - - focused.focus = module_name_loc; - - self.probe_body_term( - 1, 0, &mut focused, &terms.inverse_var_locs, context, - ); - - focused.focus = predicate_term_loc; - - self.probe_body_term( - 2, 0, &mut focused, &terms.inverse_var_locs, context, - ); - - let h = heap.cell_len(); - - heap.push_cell(atom_as_cell!(atom!("call"), 1)) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - heap.push_cell(str_loc_as_cell!(subterm_loc)) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - - build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( - loader, - (atom!("call"), 1), - terms, - str_loc_as_cell!(h), - self.call_policy, - ))); + _ => false, + } + } else { + false + }; + + state_stack.push(TraversalState::Term(then_term)); + state_stack.push(TraversalState::Cut { + var_num: self.var_num, + is_global: false, + }); + state_stack.push(TraversalState::Term(if_term)); + state_stack.push(TraversalState::GetCutPoint { + var_num: self.var_num, + prev_b, + }); + + self.var_num += 1; + } + Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => { + let not_term = terms.pop().unwrap(); + let build_stack_len = build_stack.len(); + + build_stack.reserve_branch(2); + + state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len)); + state_stack.push(TraversalState::Term(Term::Clause( + Cell::default(), + atom!("$succeed"), + vec![], + ))); + state_stack.push(TraversalState::BuildDisjunct(build_stack_len)); + state_stack.push(TraversalState::Fail); + state_stack.push(TraversalState::CutPrev(self.var_num)); + state_stack.push(TraversalState::ResetGlobalCutVarOverride( + self.global_cut_var_num_override, + )); + state_stack.push(TraversalState::Term(not_term)); + state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num)); + state_stack.push(TraversalState::GetCutPoint { + var_num: self.var_num, + prev_b: false, + }); + + self.current_chunk_type = ChunkType::Mid; + self.current_chunk_num += 1; + + self.var_num += 1; + } + Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => { + let predicate_name = terms.pop().unwrap(); + let module_name = terms.pop().unwrap(); + + match (module_name, predicate_name) { + ( + Term::Literal(_, Literal::Atom(module_name)), + Term::Literal(_, Literal::Atom(predicate_name)), + ) => { + if update_chunk_data(self, predicate_name, 0) { + build_stack.add_chunk(); } - (atom!("$call_with_inference_counting"), 1) => { - let term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); - let heap = loader.machine_heap(); - let subterm = heap_bound_store( - heap, - heap_bound_deref(heap, heap[term_loc]), - ); - - state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); - state_stack.push(TraversalState::Term { subterm, term_loc }); - - self.call_policy = CallPolicy::Counted; + + build_stack.push_chunk_term(qualified_clause_to_query_term( + loader, + module_name, + predicate_name, + vec![], + self.call_policy, + )); + } + ( + Term::Literal(_, Literal::Atom(module_name)), + Term::Clause(_, name, terms), + ) => { + if update_chunk_data(self, name, terms.len()) { + build_stack.add_chunk(); } - (name, arity) => { - add_chunk!((name, arity), HeapCellValueTag::Str, subterm_loc); + + for (arg_c, term) in terms.iter().enumerate() { + self.probe_body_term(arg_c + 1, terms.len(), term); } + + build_stack.push_chunk_term(qualified_clause_to_query_term( + loader, + module_name, + name, + terms, + self.call_policy, + )); } - } - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); + (module_name, predicate_name) => { + if update_chunk_data(self, atom!("call"), 2) { + build_stack.add_chunk(); + } - if name == atom!("!") { - let context = build_stack.current_gen_context(); - state_stack.push(self.new_cut_state(context)); - } else { - add_chunk!((name, 0), HeapCellValueTag::Var, term_loc); + self.probe_body_term(1, 0, &module_name); + self.probe_body_term(2, 0, &predicate_name); + + terms.push(module_name); + terms.push(predicate_name); + + build_stack.push_chunk_term(clause_to_query_term( + loader, + atom!("call"), + vec![Term::Clause(Cell::default(), atom!(":"), terms)], + self.call_policy, + )); } } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h != term_loc { - subterm = heap[h]; - term_loc = h; - continue; - } + } + Term::Clause(_, atom!("$call_with_inference_counting"), mut terms) + if terms.len() == 1 => + { + state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); + state_stack.push(TraversalState::Term(terms.pop().unwrap())); - add_chunk!((atom!("call"), 1), HeapCellValueTag::Var, h); + self.call_policy = CallPolicy::Counted; + } + Term::Clause(_, name, terms) => { + add_chunk(self, name, terms); + } + var @ Term::Var(..) => { + if update_chunk_data(self, atom!("call"), 1) { + build_stack.add_chunk(); } - _ => { - return Err(CompilationError::InadmissibleQueryTerm); + + self.probe_body_term(1, 1, &var); + + build_stack.push_chunk_term(clause_to_query_term( + loader, + atom!("call"), + vec![var], + self.call_policy, + )); + } + Term::Literal(_, Literal::Atom(atom!("!"))) => { + let (var_num, is_global) = + if let Some(var_num) = self.global_cut_var_num_override { + (var_num, false) + } else if let Some(var_num) = self.global_cut_var_num { + (var_num, true) + } else { + let var_num = self.var_num; + + self.global_cut_var_num = Some(var_num); + self.var_num += 1; + + (var_num, true) + }; + + self.probe_in_situ_var(var_num); + + state_stack.push(TraversalState::Cut { var_num, is_global }); + } + Term::Literal(_, Literal::Atom(name)) => { + if update_chunk_data(self, name, 0) { + build_stack.add_chunk(); } - ); - break; + build_stack.push_chunk_term(clause_to_query_term( + loader, + name, + vec![], + self.call_policy, + )); + } + _ => { + return Err(CompilationError::InadmissibleQueryTerm); + } } } } @@ -1035,13 +856,13 @@ impl BranchMap { records: VariableRecords::new(var_num), global_cut_var_num, allocates: current_chunk_num > 0, - var_locs_to_nums: VarLocsToNums::default(), }; for (var, branches) in self.iter_mut() { - let (mut var_num, var_num_incr) = match var { - &ClassifiedVar::InSitu { var_num } => (var_num, false), - _ => (var_data.records.len(), true), + let (mut var_num, var_num_incr) = if let Var::InSitu(var_num) = *var.borrow() { + (var_num, false) + } else { + (var_data.records.len(), true) }; for branch in branches.iter_mut() { @@ -1059,10 +880,7 @@ impl BranchMap { for var_info in chunk.vars.iter_mut() { if var_info.lvl == Level::Shallow { - let context = var_info - .chunk_type - .to_gen_context(chunk.term_loc.chunk_num()); - + let context = var_info.chunk_type.to_gen_context(chunk.chunk_num); temp_var_data .use_set .insert((context, var_info.classify_info.arg_c)); @@ -1081,16 +899,8 @@ impl BranchMap { for chunk in branch.chunks.iter_mut() { var_data.records[var_num].num_occurrences += chunk.vars.len(); - if let Some(term_loc) = var.term_loc() { - let chunk_num = chunk.term_loc.chunk_num(); - - var_data.var_locs_to_nums.insert( - VarPtrIndex { - chunk_num, - term_loc, - }, - var_num, - ); + for var_info in chunk.vars.iter_mut() { + var_info.var_ptr.set(Var::Generated(var_num)); } } } 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,23 +1,19 @@ #[cfg(test)] -use crate::atom_table::*; -#[cfg(test)] -use crate::machine::heap::*; +use fxhash::FxBuildHasher; #[cfg(test)] -use crate::types::*; - +use indexmap::IndexMap; #[cfg(test)] -use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc}; +use std::collections::BTreeMap; #[cfg(test)] -use std::collections::BTreeMap; +use crate::atom_table::*; #[cfg(test)] -use std::ops::Deref; - +use crate::machine::heap::*; #[cfg(test)] -use fxhash::FxBuildHasher; +use crate::types::*; #[cfg(test)] -use indexmap::IndexMap; +use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc}; #[cfg(test)] pub(crate) trait UnmarkPolicy { @@ -185,15 +181,6 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> { pstr_loc_values: PStrLocValuesMap, } -#[cfg(test)] -impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> { - type Target = Heap; - - fn deref(&self) -> &Self::Target { - self.heap - } -} - #[cfg(test)] impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> { #[inline] @@ -778,7 +765,7 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap(); + let pstr_cell = wam.machine_st.heap.allocate_pstr("abc ").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); @@ -812,7 +799,7 @@ mod tests { wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.allocate_pstr("abcdef ").unwrap(); + wam.machine_st.heap.allocate_pstr("abcdef ").unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap(); mark_cells(&mut wam.machine_st.heap, 2); 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 find_tail = |null_idx: usize| -> usize { self.scan_slice_to_str(null_idx).tail_idx }; + + match slice1 + .iter() + .zip(slice2.iter()) + .position(|(b1, b2)| b1 != b2 || *b1 == 0 || *b2 == 0) + { + Some(pos) => { + if slice1[pos] == 0 { + // subtract 1 from pos to offset the increment of scan_slice_to_str if the + // string is "\0\". + let tail1_idx = find_tail(pstr_loc1 + pos); + + if slice2[pos] == 0 { + let tail2_idx = find_tail(pstr_loc2 + pos); + + PStrSegmentCmpResult::Continue( + heap_loc_as_cell!(tail1_idx), + heap_loc_as_cell!(tail2_idx), + ) + } else { + PStrSegmentCmpResult::Continue( + heap_loc_as_cell!(tail1_idx), + pstr_loc_as_cell!(pstr_loc2 + pos), + ) + } + } else if slice2[pos] == 0 { + let tail2_idx = find_tail(pstr_loc2 + pos); - let slice2 = std::slice::from_raw_parts( - self.inner.ptr.add(pstr_loc2), - self.inner.byte_len - pstr_loc2, - ); + PStrSegmentCmpResult::Continue( + pstr_loc_as_cell!(pstr_loc1 + pos), + heap_loc_as_cell!(tail2_idx), + ) + } else { + // Compute 7-byte chunks with the mismatching character at pos in the middle of + // each. This way, the character of which the byte at pos is a part will be + // validated and reached eventually by the utf8_chunks() iterator. - let str1 = std::str::from_utf8_unchecked(&slice1); - let str2 = std::str::from_utf8_unchecked(&slice2); + let slice1_range = pos.saturating_sub(3)..(pos + 4).min(slice1.len()); + let slice2_range = pos.saturating_sub(3)..(pos + 4).min(slice2.len()); - debug_assert!(!str1.is_empty()); - debug_assert!(!str2.is_empty()); + let chars1_iter = slice1[slice1_range].utf8_chunks(); + let chars2_iter = slice2[slice2_range].utf8_chunks(); - for ((idx, c1), c2) in str1.char_indices().zip(str2.chars()) { - if c1 == '\u{0}' && c2 == '\u{0}' { - return PStrSegmentCmpResult::BothMatch { - pstr_loc1, - pstr_loc2, - null_offset: idx, - }; - } else if c1 == '\u{0}' { - return PStrSegmentCmpResult::FirstMatch { - pstr_loc1, - pstr_loc2, - l1_offset: idx, - }; - } else if c2 == '\u{0}' { - return PStrSegmentCmpResult::SecondMatch { - pstr_loc1, - pstr_loc2, - l2_offset: idx, - }; - } else if c1 != c2 { - return PStrSegmentCmpResult::Mismatch { c1, c2 }; + for (chunk1, chunk2) in chars1_iter.zip(chars2_iter) { + let result = chunk1.valid().cmp(chunk2.valid()); + + if result == Ordering::Greater { + return PStrSegmentCmpResult::Greater; + } else if result == Ordering::Less { + return PStrSegmentCmpResult::Less; + } + } + + unreachable!() } } - - unreachable!() // PStrSegmentCmpResult::Match(std::cmp::min(str1.len(), str2.len())) + None => { + unreachable!() + } } } @@ -833,43 +752,34 @@ impl Heap { Range { start, end } } - /* - pub(crate) fn splice>( - &self, - range: R, - ) -> HeapView { - let range = self.slice_range(range); - - HeapView { - slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, - cell_offset: range.start, - slice_cell_len: range.end - range.start, - // pstr_slice: &self.pstr_vec.as_bitslice()[range], - } - } + pub fn allocate_pstr(&mut self, src: &str) -> Result { + let size_in_heap = Self::compute_pstr_size(src); + let mut writer = self.reserve(size_in_heap)?; + let HeapSectionWriteResult { result, .. } = + writer.write_with(|section| match section.push_pstr(src) { + None => empty_list_as_cell!(), + Some(cell) => cell, + }); - pub(crate) fn splice_mut>( - &self, - range: R, - ) -> HeapViewMut { - let range = self.slice_range(range); - - HeapViewMut { - slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, - cell_offset: range.start, - slice_cell_len: range.end - range.start, - // pstr_slice: &self.pstr_vec.as_bitslice()[range], - } + Ok(result) } - */ - pub fn allocate_pstr(&mut self, src: &str) -> Result, usize> { + // note that allocate_cstr emits a tail cell to the string (completing it with the empty list) + // unlike any version of allocate_pstr. + + pub fn allocate_cstr(&mut self, src: &str) -> Result { let size_in_heap = Self::compute_pstr_size(src); - let mut writer = self.reserve(size_in_heap)?; + let mut writer = self.reserve(size_in_heap + 1)?; let HeapSectionWriteResult { result, .. } = - writer.write_with(|section| section.push_pstr(src)); + writer.write_with(|section| match section.push_pstr(src) { + None => empty_list_as_cell!(), + Some(cell) => { + section.push_cell(empty_list_as_cell!()); + cell + } + }); - Ok(result.map(|cell| PStrWriteInfo { cell })) + Ok(result) } pub const fn heap_cell_alignment() -> usize { @@ -1007,7 +917,7 @@ impl Heap { // by at least two null bytes so one of them may be used // to mark partial strings e.g. during iteration - if (null_idx + 1) % ALIGN == 0 { + if (null_idx + 1).next_multiple_of(ALIGN) == null_idx + 1 { byte_size += 2 * size_of::(); } 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 parsed term to heap + let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap) + .expect("couldn't write term to heap"); + + let var_names: IndexMap<_, _> = term_write_result + .var_dict + .iter() + .map(|(var_key, cell)| match var_key { + // NOTE: not the intention behind Var::InSitu here but + // we can hijack it to store anonymous variables + // without creating problems. + VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))), + VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()), + }) + .collect(); + // Write term to heap - self.machine_st.registers[1] = self.machine_st.heap[term.focus]; - self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC; + self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc]; + self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC; let call_index_p = self .indices .code_dir @@ -587,22 +625,12 @@ impl Machine { .local() .unwrap(); - let var_names: IndexMap<_, _> = term - .inverse_var_locs - .iter() - .map(|(var_loc, var)| { - let cell = self.machine_st.heap[*var_loc]; - (cell, var.clone()) - }) - .collect(); - self.machine_st.execute_at_index(1, call_index_p); let stub_b = self.machine_st.b; - QueryState { machine: self, - term, + term: term_write_result, stub_b, var_names, called: false, 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 machine_st = LS::machine_st(&mut self.payload); - let term_key_opt = clause_predicate_key(&machine_st.heap, term.focus); - - if let Some(predicate_focus) = predicate_focus_opt { - let predicate_key_opt = clause_predicate_key(&machine_st.heap, predicate_focus); - - debug_assert!(predicate_key_opt.is_some()); + let term = load_state.term_stream.next(&composite_op_dir)?; - if term_key_opt != predicate_key_opt { - self.compile_and_submit()?; - } + if !term.is_consistent(&load_state.predicates) { + self.compile_and_submit()?; } - if Some((atom!(":-"), 1)) == term_key_opt { - let machine_st = LS::machine_st(&mut self.payload); - term.focus = term_nth_arg(&machine_st.heap, term.focus, 1).unwrap(); - return Ok(Some(setup_declaration(self, term)?)); - } + let term = match term { + Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => { + return Ok(Some(setup_declaration(self, terms)?)); + } + term => term, + }; self.payload.predicates.push(term); } @@ -788,7 +762,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ) => { remove_constant_indices( constant, - &overlapping_constants, + overlapping_constants, indexing_code, clause_loc - index_loc, // WAS: &inner_index_locs, ); @@ -1071,73 +1045,30 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let machine_st = LS::machine_st(&mut self.payload); let cell = machine_st[r]; - let focus = machine_st.heap.cell_len(); - machine_st - .heap - .push_cell(cell) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - - let export_list = FocusedHeapRefMut { - heap: &mut machine_st.heap, - focus, - }; + let export_list = machine_st.read_term_from_heap(cell); let export_list = setup_module_export_list(export_list)?; Ok(export_list.into_iter().collect()) } - fn clause_clause(&mut self, cell: HeapCellValue) -> Result { - let machine_st = LS::machine_st(&mut self.payload); - let focus = machine_st.heap.cell_len(); - - read_heap_cell!(cell, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) - .get_name_and_arity(); - - let mut writer = machine_st.heap.reserve(4) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> { + match term { + Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => { + let body = terms.pop().unwrap(); + let head = terms.pop().unwrap(); - writer.write_with(|section| { - section.push_cell(str_loc_as_cell!(focus+1)); - section.push_cell(atom_as_cell!(atom!("clause"), 2)); - - match (name, arity) { - (atom!(":-"), 2) => { - section.push_cell(heap_loc_as_cell!(s+1)); - section.push_cell(heap_loc_as_cell!(s+2)); - } - _ => { - section.push_cell(str_loc_as_cell!(s)); - section.push_cell(atom_as_cell!(atom!("true"))); - } - } - }); + self.payload.clause_clauses.push((head, body)); } - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - let mut writer = machine_st.heap.reserve(4) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - - writer.write_with(|section| { - section.push_cell(str_loc_as_cell!(focus+1)); - section.push_cell(atom_as_cell!(atom!("clause"), 2)); - section.push_cell(atom_as_cell!(name)); - section.push_cell(atom_as_cell!(atom!("true"))); - }); - } else { - return Err(CompilationError::InadmissibleFact); - } + head @ (Term::Clause(..) | Term::Literal(_, Literal::Atom(_))) => { + let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true"))); + self.payload.clause_clauses.push((head, body)); } _ => { return Err(CompilationError::InadmissibleFact); } - ); + } - Ok( - TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus)) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?, - ) + Ok(()) } fn add_extensible_predicate_declaration( @@ -1355,11 +1286,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ) } - fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> { - let machine_st = LS::machine_st(&mut self.payload); - let key_opt = clause_predicate_key_from_heap(&machine_st.heap, value); - - if let Some((predicate_name, predicate_arity)) = key_opt { + fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> { + if let Some(predicate_name) = ClauseInfo::name(term) { + let predicate_arity = ClauseInfo::arity(term); let predicates_compilation_target = self.payload.predicates.compilation_target; let is_dynamic = self @@ -1373,8 +1302,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .unwrap_or(false); if is_dynamic { - let clause_clause_term = self.clause_clause(value)?; - self.payload.clause_clauses.push(clause_clause_term); + self.add_clause_clause(term.clone())?; } } @@ -1440,6 +1368,90 @@ impl<'a> MachinePreludeView<'a> { } } +impl MachineState { + pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term { + let mut term_stack = vec![]; + self.heap[0] = term_addr; + let mut iter = + stackful_post_order_iter::(&mut self.heap, &mut self.stack, 0); + + while let Some(addr) = iter.next() { + let addr = unmark_cell_bits!(addr); + + if let Ok(literal) = Literal::try_from(addr) { + term_stack.push(Term::Literal(Cell::default(), literal)); + } else { + read_heap_cell!(addr, + (HeapCellValueTag::Lis) => { + use crate::parser::parser::as_partial_string; + + let tail = term_stack.pop().unwrap(); + let head = term_stack.pop().unwrap(); + + match as_partial_string(head, tail) { + Ok((string, Some(tail))) => { + term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail)); + } + Ok((string, None)) => { + term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string))); + } + Err(cons_term) => term_stack.push(cons_term), + } + } + (HeapCellValueTag::StackVar, h) => { + term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h)))); + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { + term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h)))); + } + (HeapCellValueTag::Atom, (name, arity)) => { + let h = iter.focus().value() as usize; + let mut arity = arity; + let value = iter.heap[h.saturating_sub(1)]; + + if let Some(idx) = get_structure_index(value) { + term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx))); + arity += 1; + } + + if arity == 0 { + term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); + } else { + let subterms = term_stack + .drain(term_stack.len() - arity ..) + .collect(); + + term_stack.push(Term::Clause(Cell::default(), name, subterms)); + } + } + (HeapCellValueTag::PStrLoc, h) => { + let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h); + let tail = term_stack.pop().unwrap(); + + term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) { + Term::CompleteString( + Cell::default(), + Rc::new(string.to_owned()), + ) + } else { + Term::PartialString( + Cell::default(), + Rc::new(string.to_owned()), + Box::new(tail), + ) + }); + } + _ => { + } + ); + } + } + + debug_assert!(term_stack.len() == 1); + term_stack.pop().unwrap() + } +} + impl Machine { pub(crate) fn use_module(&mut self) -> CallResult { let subevacuable_addr = self @@ -1600,15 +1612,11 @@ impl Machine { } pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult { - let value = self.machine_st.registers[1]; - let term = resource_error_call_result!( - self.machine_st, - TermWriteResult::from(&mut self.machine_st.heap, value) - ); - let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let add_clause = || { + let term = loader.read_term_from_heap(temp_v!(1)); + loader.incremental_compile_clause( (atom!("term_expansion"), 2), term, @@ -1629,37 +1637,30 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st.registers[1]))); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); + let compilation_target = match target_module_name { atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(target_module_name), }; - let value = self.machine_st.registers[2]; - let term = resource_error_call_result!( - self.machine_st, - TermWriteResult::from(&mut self.machine_st.heap, value) - ); - let add_clause = || { - let indexing_arg_opt = match term_predicate_key(&self.machine_st.heap, term.focus) { - Some((atom!(":-"), _)) => term_nth_arg(&self.machine_st.heap, term.focus, 1) - .and_then(|h| term_nth_arg(&self.machine_st.heap, h, 1)), - Some(_) => term_nth_arg(&self.machine_st.heap, term.focus, 1), + let term = loader.read_term_from_heap(temp_v!(2)); + + let indexing_arg = match term.name() { + Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg), + Some(_) => term.first_arg(), None => None, }; - let key_opt = indexing_arg_opt.and_then(|indexing_term_loc| { - term_predicate_key(&self.machine_st.heap, indexing_term_loc) - }); - - let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); - - if let Some((name, arity)) = key_opt { - loader - .wam_prelude - .indices - .goal_expansion_indices - .insert((name, arity)); + if let Some(indexing_term) = indexing_arg { + if let Some(indexing_name) = indexing_term.name() { + loader + .wam_prelude + .indices + .goal_expansion_indices + .insert((indexing_name, indexing_term.arity())); + } } loader.incremental_compile_clause( @@ -1964,21 +1965,29 @@ impl Machine { }; let stub_gen = || functor_stub(key.0, key.1); - let assert_clause = self.machine_st.registers[2]; - let key_opt = clause_predicate_key_from_heap(&self.machine_st.heap, assert_clause); + let head = self.deref_register(2); + + if head.is_var() { + let err = self.machine_st.instantiation_error(); + return Err(self.machine_st.error_form(err, stub_gen())); + } - let mut compile_assert = |assert_clause, key_opt| { + let mut compile_assert = || { let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = Loader::new(self, LiveTermStream::new(ListingSource::User)); loader.payload.compilation_target = compilation_target; - let (name, arity) = if let Some(key) = key_opt { - key + let head = + LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head); + + let name = if let Some(name) = head.name() { + name } else { return Err(SessionError::from(CompilationError::InvalidRuleHead)); }; + let arity = head.arity(); let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity)); let is_dynamic_predicate = loader @@ -2010,39 +2019,39 @@ impl Machine { return LiveLoadAndMachineState::evacuate(loader); } - // if a new predicate was just created, make it dynamic. - loader.add_dynamic_predicate(compilation_target, name, arity)?; + let body = loader.read_term_from_heap(temp_v!(3)); - let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload); - // let asserted_clause = loader.copy_term_from_heap(assert_clause); + let asserted_clause = Term::Clause( + Cell::default(), + atom!(":-"), + vec![head.clone(), body.clone()], + ); - let term = TermWriteResult::from(&mut machine_st.heap, assert_clause) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + // if a new predicate was just created, make it dynamic. + loader.add_dynamic_predicate(compilation_target, name, arity)?; loader.incremental_compile_clause( (name, arity), - term, + asserted_clause, compilation_target, false, append_or_prepend, )?; - let clause_clause_term = loader.clause_clause(assert_clause)?; - // the global clock is incremented after each assertion. LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; loader.compile_clause_clauses( (name, arity), compilation_target, - vec![clause_clause_term], + std::iter::once((head, body)), append_or_prepend, )?; LiveLoadAndMachineState::evacuate(loader) }; - match compile_assert(assert_clause, key_opt) { + match compile_assert() { Ok(_) => Ok(()), Err(SessionError::CompilationError( CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact, @@ -2244,23 +2253,11 @@ impl Machine { }; let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); - let predicate_focus_opt = loader - .payload - .predicates - .first() - .map(|term_write_result| term_write_result.focus); - - let is_consistent = if let Some(predicate_focus) = predicate_focus_opt { - let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload); - clause_predicate_key(&machine_st.heap, predicate_focus) == Some(key) - } else { - true - }; LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = (!loader.payload.predicates.is_empty() && loader.payload.predicates.compilation_target != compilation_target) - || !is_consistent; + || !key.is_consistent(&loader.payload.predicates); let result = LiveLoadAndMachineState::evacuate(loader); self.restore_load_state_payload(result) @@ -2467,17 +2464,11 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> { self.payload.predicates.compilation_target = compilation_target; } - let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); - let value = machine_st.store(MachineState::deref(machine_st, machine_st[term_reg])); - - self.add_clause_clause_if_dynamic(value)?; - - let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); - - let term = TermWriteResult::from(&mut machine_st.heap, value) - .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + let term = self.read_term_from_heap(term_reg); + self.add_clause_clause_if_dynamic(&term)?; self.payload.term_stream.term_queue.push_back(term); + self.load() } } 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; + } + + for idx in 0..size { + section.push_cell(list_loc_as_cell!(section.cell_len() + 1)); + section.push_cell(str_loc_as_cell!(src_h + 3 * idx)); + } + + if size > 0 { + section.push_cell(empty_list_as_cell!()); + } - Ok(heap_loc_as_cell!(src_h + 3 * size)) + size + }) + .result } else { - Ok(empty_list_as_cell!()) - } -} + size + }; -/* -pub(crate) fn copy_and_align_iter>( - iter: 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, ) ); - let mut var_list = Vec::with_capacity(singleton_var_set.len()); + for var in term_write_result.var_dict.values_mut() { + *var = heap_bound_deref(&self.heap, *var); + } - for (var_loc, var_name) in term.inverse_var_locs { - let r = Ref::heap_cell(var_loc); - let cell = self.heap[var_loc]; + let mut var_list = Vec::with_capacity(singleton_var_set.len()); - if let Some(idx) = singleton_var_set.get_index_of(&r) { - var_list.push((var_name, cell, idx)); + for (var_name, addr) in term_write_result.var_dict { + if let Some(var) = addr.as_var() { + if let Some(idx) = singleton_var_set.get_index_of(&var) { + var_list.push((var_name, addr, idx)); + } } } @@ -851,8 +824,8 @@ impl MachineState { } loop { - match self.read_to_heap(stream, &indices.op_dir) { - Ok(term) => return self.read_term_body(term), + match self.read(stream, &indices.op_dir) { + Ok(term_write_result) => return self.read_term_body(term_write_result), Err(err) => { match &err { CompilationError::ParserError(e) if e.is_unexpected_eof() => { @@ -891,7 +864,7 @@ impl MachineState { let printer = match self.try_from_list(self.registers[6], stub_gen) { Ok(addrs) => { - let mut var_names: IndexMap = 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); - - if let Some((atom!("/") | atom!("//"), 2)) = key_opt { - let arity_loc = term.nth_arg(term.focus, 2).unwrap(); - - let arity = match Number::try_from(term.deref_loc(arity_loc)) { - Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), - Ok(Number::Integer(n)) => (&*n).try_into().ok(), - _ => None, - } - .ok_or(CompilationError::InvalidModuleExport)?; +fn setup_predicate_indicator(term: &mut Term) -> Result { + match term { + Term::Clause(_, slash, ref mut terms) + if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 => + { + let arity = terms.pop().unwrap(); + let name = terms.pop().unwrap(); + + let arity = match arity { + Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(), + Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + _ => None, + } + .ok_or(CompilationError::InvalidModuleExport)?; - let name_loc = term.nth_arg(term.focus, 1).unwrap(); - let name = term_predicate_key(term.heap, name_loc) - .map(|(name, _)| name) + let name = match name { + Term::Literal(_, Literal::Atom(name)) => Some(name), + _ => None, + } .ok_or(CompilationError::InvalidModuleExport)?; - if matches!(key_opt, Some((atom!("/"), _))) { - Ok((name, arity)) - } else { - Ok((name, arity + 2)) + if *slash == atom!("/") { + Ok((name, arity)) + } else { + Ok((name, arity + 2)) + } } - } else { - Err(CompilationError::InvalidModuleExport) + _ => Err(CompilationError::InvalidModuleExport), } } -fn setup_module_export(term: &FocusedHeapRefMut) -> Result { - 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, - }; - - exports.push(setup_module_export(&term)?); - focus = l + 1; - } - (HeapCellValueTag::Atom, (name, _arity)) => { - if name == atom!("[]") { - return Ok(exports); - } else { - break; - } - } - _ => { - break; - } - ); + + while let Term::Cons(_, t1, t2) = export_list { + let module_export = setup_module_export(*t1)?; + + exports.push(module_export); + export_list = *t2; } - Err(CompilationError::InvalidModuleDecl) + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { + Ok(exports) + } else { + Err(CompilationError::InvalidModuleDecl) + } } -fn setup_module_decl(mut term: FocusedHeapRefMut) -> Result { - 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)?; - let mut exports = IndexSet::new(); - - let mut focus = term.focus + 2; - - while let HeapCellValueTag::Lis = term.heap[focus].get_tag() { - focus = term.heap[focus].get_value() as usize; +fn setup_qualified_import(mut terms: Vec) -> 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 term = FocusedHeapRefMut { - heap: term.heap, - focus, - }; + let mut exports = IndexSet::new(); - exports.insert(setup_module_export(&term)?); - focus = focus + 1; + while let Term::Cons(_, t1, t2) = export_list { + exports.insert(setup_module_export(*t1)?); + export_list = *t2; } - if term.heap[focus] == empty_list_as_cell!() { + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { Ok((module_src, exports)) } else { Err(CompilationError::InvalidModuleDecl) @@ -290,20 +249,18 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result>( - 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])); - - read_heap_cell!(cell, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); - - match (name, arity) { - (atom!(":"), 2) => { - let module_name = heap[s+1]; - let spec = heap[s+2]; - - read_heap_cell!(module_name, - (HeapCellValueTag::Atom, (module_name, arity)) => { - if arity == 0 { - read_heap_cell!(spec, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(heap[s]) - .get_name_and_arity(); - - let term = FocusedHeapRefMut { heap, focus: s }; - return Ok((module_name, name, get_meta_specs(term, arity)?)); - } - _ => { - } - ); - } else { - return Err(CompilationError::InvalidMetaPredicateDecl); - } - } - _ => { - } - ); - } - _ => { - let term = FocusedHeapRefMut { heap, focus: s }; - let specs = get_meta_specs(term, arity)?; - let module_name = loader.payload.compilation_target.module_name(); + match terms.pop().unwrap() { + Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => { + let spec = terms.pop().unwrap(); + let module_name = terms.pop().unwrap(); - return Ok((module_name, name, specs)); - } + match module_name { + Term::Literal(_, Literal::Atom(module_name)) => match spec { + Term::Clause(_, name, mut terms) => { + let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; + Ok((module_name, name, meta_specs)) + } + _ => Err(CompilationError::InvalidMetaPredicateDecl), + }, + _ => Err(CompilationError::InvalidMetaPredicateDecl), } - - Err(CompilationError::InvalidMetaPredicateDecl) } - _ => { - Err(CompilationError::InvalidMetaPredicateDecl) + Term::Clause(_, name, mut terms) => { + let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; + Ok(( + loader.payload.compilation_target.module_name(), + name, + meta_specs, + )) } - ) + _ => Err(CompilationError::InvalidMetaPredicateDecl), + } } pub(super) fn setup_declaration<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, - mut term: TermWriteResult, + mut terms: Vec, ) -> Result { - let mut focus = term.focus; - let machine_st = LS::machine_st(&mut loader.payload); - - loop { - let decl = machine_st.heap[focus]; + let term = terms.pop().unwrap(); - read_heap_cell!(decl, - (HeapCellValueTag::Atom, (name, arity)) => { - let mut focused = FocusedHeapRefMut::from(&mut machine_st.heap, focus); - - return match (name, arity) { - (atom!("dynamic"), 1) => { - let (name, arity) = setup_predicate_indicator(&focused)?; - Ok(Declaration::Dynamic(name, arity)) - } - (atom!("module"), 2) => { - Ok(Declaration::Module(setup_module_decl(focused)?)) - } - (atom!("op"), 3) => { - Ok(Declaration::Op(setup_op_decl(&focused)?)) - } - (atom!("non_counted_backtracking"), 1) => { - focused.focus = focused.nth_arg(focused.focus, 1).unwrap(); - let (name, arity) = setup_predicate_indicator(&focused)?; - Ok(Declaration::NonCountedBacktracking(name, arity)) - } - (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&focused)?)), - (atom!("use_module"), 2) => { - let (name, exports) = setup_qualified_import(focused)?; - Ok(Declaration::UseQualifiedModule(name, exports)) - } - (atom!("meta_predicate"), 1) => { - term.focus = focus; - let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?; - Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) - } - _ => Err(CompilationError::InvalidDirective( - DirectiveError::InvalidDirective(name, arity) - )) - }; + match term { + Term::Clause(_, name, mut terms) => match (name, terms.len()) { + (atom!("dynamic"), 1) => { + let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; + Ok(Declaration::Dynamic(name, arity)) } - (HeapCellValueTag::Str, s) => { - focus = s; + (atom!("module"), 2) => Ok(Declaration::Module(setup_module_decl(terms)?)), + (atom!("op"), 3) => Ok(Declaration::Op(setup_op_decl(terms)?)), + (atom!("non_counted_backtracking"), 1) => { + let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; + Ok(Declaration::NonCountedBacktracking(name, arity)) } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if focus != h { - focus = h; - } else { - return Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(decl), - )); - } + (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)), + (atom!("use_module"), 2) => { + let (name, exports) = setup_qualified_import(terms)?; + Ok(Declaration::UseQualifiedModule(name, exports)) } - _ => { - return Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(decl), - )); + (atom!("meta_predicate"), 1) => { + let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?; + Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) } - ); + _ => Err(CompilationError::InvalidDirective( + DirectiveError::InvalidDirective(name, terms.len()), + )), + }, + other => Err(CompilationError::InvalidDirective( + DirectiveError::ExpectedDirective(other), + )), } } fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, module_name: Atom, - arity: usize, - term: &TermWriteResult, + terms: Vec, meta_specs: Vec, -) -> IndexMap { - use crate::machine::heap::Heap; - let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default()); - - let focus = { - let heap = loader.machine_heap(); - let focus_cell = - heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(term.focus))); - - if focus_cell.get_tag() == HeapCellValueTag::Str { - focus_cell.get_value() as usize - } else { - return index_ptrs; - } - }; +) -> Vec { + let mut arg_terms = Vec::with_capacity(terms.len()); - for (subterm_loc, meta_spec) in (focus + 1..focus + arity + 1).zip(meta_specs) { + for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) { if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec { - let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); - - if let Some((name, arity)) = predicate_key_opt { + if let Some(name) = term.name() { if name == atom!("$call") { + arg_terms.push(term); continue; } - struct QualifiedNameInfo { - module_name: Atom, - name: Atom, - arity: usize, - qualified_term_loc: usize, - } + let arity = term.arity(); fn get_qualified_name( - heap: &Heap, - module_term_loc: usize, - qualified_term_loc: usize, - ) -> Option { - let (module_term_loc, _) = subterm_index(heap, module_term_loc); - let (qualified_term_loc, _) = subterm_index(heap, qualified_term_loc); - - read_heap_cell!(heap[module_term_loc], - (HeapCellValueTag::Atom, (module_name, arity)) => { - if arity == 0 { - if let Some((name, arity)) = term_predicate_key(heap, qualified_term_loc) { - return Some(QualifiedNameInfo { - module_name, - name, - arity, - qualified_term_loc, - }); - } - } + module_term: &Term, + qualified_term: &Term, + ) -> Option<(Atom, Atom)> { + if let Term::Literal(_, Literal::Atom(module_name)) = module_term { + if let Some(name) = qualified_term.name() { + return Some((*module_name, name)); } - _ => {} - ); + } None } - let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc); - let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); + fn identity_fn(_module_name: Atom, term: Term) -> Term { + term + } - let (module_name, key, term_loc) = if subterm_key_opt == Some((atom!(":"), 2)) { - match get_qualified_name( - loader.machine_heap(), - subterm_loc + 1, - subterm_loc + 2, - ) { - Some(QualifiedNameInfo { - module_name, - name, - arity, - qualified_term_loc, - }) => (module_name, (name, arity + supp_args), qualified_term_loc), - None => { + fn tag_with_module_name(module_name: Atom, term: Term) -> Term { + Term::Clause( + Cell::default(), + atom!(":"), + vec![ + Term::Literal(Cell::default(), Literal::Atom(module_name)), + term, + ], + ) + } + + let process_term: fn(Atom, Term) -> Term; + + let (module_name, key, term) = match term { + Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => { + if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1]) + { + process_term = tag_with_module_name; + ( + module_name, + (name, terms[1].arity() + supp_args), + terms.pop().unwrap(), + ) + } else { + arg_terms.push(Term::Clause(cell, atom!(":"), terms)); continue; } } - } else { - (module_name, (name, arity + supp_args), subterm_loc) + term => { + process_term = identity_fn; + (module_name, (name, arity + supp_args), term) + } }; - if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), term_loc) { - index_ptrs.insert(term_loc, index_ptr); - continue; - } + let term = match term { + Term::Clause(cell, name, mut terms) => { + if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() { + arg_terms + .push(process_term(module_name, Term::Clause(cell, name, terms))); + + continue; + } + + let idx = loader.get_or_insert_qualified_code_index(module_name, key); - index_ptrs.insert( - term_loc, - loader.get_or_insert_qualified_code_index(module_name, key), - ); + terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx))); + process_term(module_name, Term::Clause(cell, name, terms)) + } + Term::Literal(cell, Literal::Atom(name)) => { + let idx = loader.get_or_insert_qualified_code_index(module_name, key); + + process_term( + module_name, + Term::Clause( + cell, + name, + vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))], + ), + ) + } + term => term, + }; + + arg_terms.push(term); + continue; } } + + arg_terms.push(term); } - index_ptrs + arg_terms } #[inline] pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, - key: PredicateKey, - terms: &TermWriteResult, - term: HeapCellValue, + name: Atom, + mut terms: Vec, 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); - - let existence_error = self.existence_error(ExistenceError::Stream(addr)); + return match indices.get_stream(name) { + Some(stream) => Ok(stream), + _ => { + let stub = functor_stub(caller, arity); + let addr = atom_as_cell!(name); - Err(self.error_form(existence_error, stub)) - } - }; - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.heap[s]) - .get_name_and_arity(); + let existence_error = self.existence_error(ExistenceError::Stream(addr)); - debug_assert_eq!(arity, 0); + Err(self.error_form(existence_error, stub)) + } + }; + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); - return match indices.get_stream(name) { - Some(stream) => Ok(stream), - _ => { - let stub = functor_stub(caller, arity); - let addr = atom_as_cell!(name); + debug_assert_eq!(arity, 0); - let existence_error = self.existence_error(ExistenceError::Stream(addr)); + return match indices.get_stream(name) { + Some(stream) => Ok(stream), + _ => { + let stub = functor_stub(caller, arity); + let addr = atom_as_cell!(name); - Err(self.error_form(existence_error, stub)) - } - }; - } - (HeapCellValueTag::Cons, ptr) => { - match_untyped_arena_ptr!(ptr, - (ArenaHeaderTag::Stream, stream) => { - if stream.is_null_stream() { - unreachable!("Null streams have no Cons representation"); - } - return Ok(stream); - } - (ArenaHeaderTag::Dropped, _value) => { - let stub = functor_stub(caller, arity); - let err = self.existence_error(ExistenceError::Stream(addr)); + let existence_error = self.existence_error(ExistenceError::Stream(addr)); - return Err(self.error_form(err, stub)); - } - _ => { - } - ); - } - _ => { - } + Err(self.error_form(existence_error, stub)) + } + }; + } + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Stream, stream) => { + return if stream.is_null_stream() { + Err(self.open_permission_error(stream_as_cell!(stream), caller, arity)) + } else { + Ok(stream) + }; + } + (ArenaHeaderTag::Dropped, _value) => { + let stub = functor_stub(caller, arity); + let err = self.existence_error(ExistenceError::Stream(addr)); + + return Err(self.error_form(err, stub)); + } + _ => { + } + ); + } + _ => { + } ); let stub = functor_stub(caller, arity); @@ -1880,7 +1881,7 @@ impl MachineState { ) -> Result { 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(); - - let string = match atom_or_string { - AtomOrString::Atom(atom!("[]")) => "".to_owned(), - _ => atom_or_string.into(), - }; - - let chars = CharReader::new(ByteStream::from_string(string)); - let term = self - .machine_st - .read(chars, &self.indices.op_dir) - .map(|(term, _)| term) - .map_err(|e| { - let e = self.machine_st.session_error(SessionError::from(e)); - let stub = functor_stub(atom!("read_term_from_chars"), 3); - - self.machine_st.error_form(e, stub) - })?; + { + if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? { + self.machine_st.read_term_body(term_write_result) + } else { + if !self.machine_st.fail { + // wrote end_of_file term in this case. + self.machine_st + .write_read_term_options(vec![], empty_list_as_cell!())?; + } - self.machine_st.read_term_body(term) + Ok(()) + } + } else { + unreachable!() + } } #[inline(always)] @@ -7542,8 +7515,10 @@ impl Machine { }; let result = printer.print().result(); - let chars = - resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&result)); + let chars = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.allocate_cstr(&result) + ); let result_addr = self.deref_register(1); let var = result_addr.as_var().unwrap(); @@ -7559,7 +7534,7 @@ impl Machine { let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); let cstr_cell = - step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer)); + step_or_resource_error!(self.machine_st, self.machine_st.heap.allocate_cstr(&buffer)); unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]); } @@ -8010,7 +7985,10 @@ impl Machine { if buffer.is_empty() { empty_list_as_cell!() } else { - step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer)) + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.allocate_cstr(&buffer) + ) } }; @@ -8197,7 +8175,7 @@ impl Machine { Ok(value) => { let cstr = step_or_resource_error!( self.machine_st, - self.machine_st.allocate_cstr(&value) + self.machine_st.heap.allocate_cstr(&value) ); unify!(self.machine_st, self.machine_st.registers[2], cstr); @@ -8410,20 +8388,15 @@ impl Machine { 1, )?; - let mut lexer_parser = LexerParser::new(stream, &mut self.machine_st); + let mut parser = Parser::new(stream, &mut self.machine_st); - match devour_whitespace(&mut lexer_parser) { + match devour_whitespace(&mut parser.lexer) { Ok(false) => { - // not at EOF ... - stream.add_lines_read(lexer_parser.line_num()); - - // ... unless we are. - if stream.at_end_of_stream() { - self.machine_st.fail = true; - } + // not at EOF. + stream.add_lines_read(parser.lines_read()); } Ok(true) => { - stream.add_lines_read(lexer_parser.line_num()); + stream.add_lines_read(parser.lexer.line_num); self.machine_st.fail = true; } Err(err) => { @@ -8483,8 +8456,10 @@ impl Machine { if path.is_dir() { if let Some(path) = path.to_str() { - let path_string = - step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(path)); + let path_string = step_or_resource_error!( + self.machine_st, + self.machine_st.heap.allocate_cstr(path) + ); unify!(self.machine_st, self.machine_st.registers[1], path_string); return; @@ -8557,13 +8532,13 @@ impl Machine { node: roxmltree::Node, ) -> Result { 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>); + +impl Hash for VarPtr { + #[inline(always)] + fn hash(&self, hasher: &mut H) { + self.borrow().hash(hasher) + } +} -pub(crate) fn subterm_index(heap: &impl SizedHeap, subterm_loc: usize) -> (usize, HeapCellValue) { - let subterm = heap[subterm_loc]; +impl Deref for VarPtr { + type Target = RefCell; - if subterm.is_ref() { - let subterm = heap_bound_deref(heap, subterm); - let subterm_loc = subterm.get_value() as usize; - let subterm = heap_bound_store(heap, subterm); + #[inline(always)] + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} - let subterm_loc = if subterm.is_ref() { - subterm.get_value() as usize - } else { - subterm_loc - }; +impl VarPtr { + #[inline(always)] + pub(crate) fn borrow(&self) -> Ref<'_, Var> { + self.0.borrow() + } - (subterm_loc, subterm) - } else { - (subterm_loc, subterm) + #[inline(always)] + pub(crate) fn borrow_mut(&self) -> RefMut<'_, Var> { + self.0.borrow_mut() + } + + pub(crate) fn to_var_num(&self) -> Option { + 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) +} - Ok((tokens, term_size)) +fn atomize_term(term: &Term) -> Option { + match term { + &Term::Literal(_, Literal::Atom(c)) => Some(c), + _ => None, + } } -pub(crate) fn as_partial_string( - heap: &impl SizedHeap, - head: HeapCellValue, - tail: HeapCellValue, -) -> Option<(String, Option)> { - let head = heap_bound_store(heap, heap_bound_deref(heap, head)); - let mut tail = heap_bound_store(heap, heap_bound_deref(heap, tail)); - - let mut string = read_heap_cell!(head, - (HeapCellValueTag::Atom, (atom, arity)) => { - if arity == 0 { - if let Some(c) = atom.as_char() { - c.to_string() - } else { - return None; - } - } else { - return None; - } - } - _ => { - return None; - } - ); +impl TokenType { + fn sep_to_atom(&mut self) -> Option { + 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!(); - - self.terms.write_with(|section| { - for c in s.as_str().chars().rev() { - let h = section.cell_len(); - - section.push_cell(fixnum_as_cell!(Fixnum::build_with(c as i64))); - section.push_cell(list); - - list = list_loc_as_cell!(h); - } - - section.push_cell(list); - }); + Token::String(s) if self.lexer.machine_st.flags.double_quotes.is_codes() => { + let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); + + for c in s.as_str().chars().rev() { + list = Term::Cons( + Cell::default(), + Box::new(Term::Literal( + Cell::default(), + Literal::Fixnum(Fixnum::build_with(c as i64)), + )), + Box::new(list), + ); + } - TokenType::Term { heap_loc: list } + self.terms.push(list); + TokenType::Term } Token::String(s) => { - debug_assert!(self.flags.double_quotes.is_chars()); - let mut pstr_cell = heap_loc; - - if s == "\u{0}" { - let h = self.terms.cell_len(); - - self.terms.write_with(|section| { - section.push_cell(char_as_cell!('\u{0}')); - section.push_cell(empty_list_as_cell!()); - section.push_cell(list_loc_as_cell!(h)); - }); - - TokenType::Term { - heap_loc: heap_loc_as_cell!(h + 2), - } - } else { - self.terms - .write_with(|section| match section.push_pstr(&s) { - Some(pstr_loc_cell) => { - section.push_cell(empty_list_as_cell!()); - let h = section.cell_len(); - section.push_cell(pstr_loc_cell); - pstr_cell = heap_loc_as_cell!(h); - } - None => { - section.push_cell(empty_list_as_cell!()); - } - }); - - TokenType::Term { - heap_loc: pstr_cell, - } - } + debug_assert!(self.lexer.machine_st.flags.double_quotes.is_chars()); + self.terms + .push(Term::CompleteString(Cell::default(), Rc::new(s))); + TokenType::Term } Token::Literal(c) => { - self.terms.write_with(|section| section.push_cell(c)); - TokenType::Term { heap_loc } + self.terms.push(Term::Literal(Cell::default(), c)); + TokenType::Term } - Token::Var(var_string) => { - let var = Rc::new(var_string); - - match self.var_locs.get(&var).cloned() { - Some(heap_loc) => { - self.terms.write_with(|section| section.push_cell(heap_loc)); - TokenType::Term { heap_loc } - } - None => { - self.terms.write_with(|section| section.push_cell(heap_loc)); - - // if var_string == "_", it not being present - // as a key of self.var_locs means it is - // anonymous. - - if var.trim() != "_" { - self.var_locs.insert(var.clone(), heap_loc); - self.inverse_var_locs - .insert(heap_loc.get_value() as usize, var); - } - - TokenType::Term { heap_loc } - } + Token::Var(v) => { + if v.trim() == "_" { + self.terms.push(Term::AnonVar); + } else { + self.terms.push(Term::Var(Cell::default(), VarPtr::from(v))); } + + TokenType::Term } Token::Comma => TokenType::Comma, Token::Open => TokenType::Open, @@ -519,10 +443,10 @@ impl<'a> Parser<'a> { if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1) || is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1) { - self.push_binary_op(desc2, desc3, desc1, LTERM); + self.push_binary_op(desc2, LTERM); continue; } else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) { - self.push_binary_op(desc2, desc3, desc1, TERM); + self.push_binary_op(desc2, TERM); continue; } else { self.stack.push(desc3); @@ -530,16 +454,16 @@ impl<'a> Parser<'a> { } if is_yf!(desc1.spec) && affirm_yf(desc1, desc2) { - self.push_unary_op(desc1, desc2, LTERM); + self.push_unary_op(desc1, LTERM, YF); continue; } else if is_xf!(desc1.spec) && affirm_xf(desc1, desc2) { - self.push_unary_op(desc1, desc2, LTERM); + self.push_unary_op(desc1, LTERM, XF); continue; } else if is_fy!(desc2.spec) && affirm_fy(priority, desc1, desc2) { - self.push_unary_op(desc2, desc1, TERM); + self.push_unary_op(desc2, TERM, FY); continue; } else if is_fx!(desc2.spec) && affirm_fx(priority, desc1, desc2) { - self.push_unary_op(desc2, desc1, TERM); + self.push_unary_op(desc2, TERM, FX); continue; } else { self.stack.push(desc2); @@ -583,14 +507,6 @@ impl<'a> Parser<'a> { None } - fn term_from_stack(&self, idx: usize) -> Option { - if let TokenType::Term { heap_loc } = self.stack[idx].tt { - Some(heap_loc) - } else { - None - } - } - fn reduce_term(&mut self) -> bool { if self.stack.is_empty() { return false; @@ -617,94 +533,39 @@ impl<'a> Parser<'a> { return false; } - if self.terms.cell_len() < arity { + if self.terms.len() < 1 + arity { return false; } let stack_len = self.stack.len() - 2 * arity - 1; - let term_idx = self.terms.cell_len(); - - let push_structure = |parser: &mut Self, name: Atom| -> TokenType { - parser - .terms - .write_with(|section| section.push_cell(atom_as_cell!(name, arity))); - - for idx in (stack_len + 2..parser.stack.len()).step_by(2) { - let subterm = parser.term_from_stack(idx).unwrap(); - parser - .terms - .write_with(|section| section.push_cell(subterm)); - } - - let str_loc_idx = parser.terms.cell_len(); - parser - .terms - .write_with(|section| section.push_cell(str_loc_as_cell!(term_idx))); + let idx = self.terms.len() - arity; - TokenType::Term { - heap_loc: heap_loc_as_cell!(str_loc_idx), - } - }; - - if let TokenDesc { - tt: TokenType::Term { heap_loc }, - .. - } = self.stack[stack_len] + if TokenType::Term == self.stack[stack_len].tt + && atomize_term(&self.terms[idx - 1]).is_some() { - let idx = heap_loc.get_value() as usize; + self.stack.truncate(stack_len + 1); + + let mut subterms: Vec<_> = self.terms.drain(idx..).collect(); - if let Some((name, arity)) = term_predicate_key(&self.terms, idx) { + if let Some(name) = self.terms.pop().and_then(|t| atomize_term(&t)) { // reduce the '.' functor to a cons cell if it applies. - let new_tt = if name == atom!(".") && arity == 2 { - let head = self.term_from_stack(stack_len + 2).unwrap(); - let tail = self.term_from_stack(stack_len + 4).unwrap(); - let cell_len = self.terms.cell_len(); - - match as_partial_string(&self.terms, head, tail) { - Some((string_buf, tail_opt)) => { - let HeapSectionWriteResult { bytes_written, .. } = - self.terms.write_with(|section| { - if let Some(pstr_cell) = section.push_pstr(&string_buf) { - section - .push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); - section.push_cell(pstr_cell); - } else { - section.push_cell(empty_list_as_cell!()); - } - }); - - if cell_index!(bytes_written) > 1 { - TokenType::Term { - heap_loc: heap_loc_as_cell!( - cell_index!(bytes_written) - 1 + cell_len - ), - } - } else { - TokenType::Term { - heap_loc: heap_loc_as_cell!(cell_len), - } - } + if name == atom!(".") && subterms.len() == 2 { + let tail = subterms.pop().unwrap(); + let head = subterms.pop().unwrap(); + + self.terms.push(match as_partial_string(head, tail) { + Ok((string_buf, Some(tail))) => { + Term::PartialString(Cell::default(), Rc::new(string_buf), tail) } - None => { - let HeapSectionWriteResult { bytes_written, .. } = - self.terms.write_with(|section| { - section.push_cell(head); - section.push_cell(tail); - section.push_cell(list_loc_as_cell!(term_idx)); - }); - - TokenType::Term { - heap_loc: heap_loc_as_cell!( - cell_len + cell_index!(bytes_written) - 1 - ), - } + Ok((string_buf, None)) => { + Term::CompleteString(Cell::default(), Rc::new(string_buf)) } - } + Err(term) => term, + }); } else { - push_structure(self, name) - }; - - self.stack.truncate(stack_len + 1); + self.terms + .push(Term::Clause(Cell::default(), name, subterms)); + } if let Some(&mut TokenDesc { ref mut tt, @@ -717,56 +578,38 @@ impl<'a> Parser<'a> { return false; } - *tt = new_tt; + *tt = TokenType::Term; *priority = 0; *spec = TERM; *unfold_bounds = 0; } - } else { - return false; - }; - return true; + return true; + } } false } - fn loc_to_err_src(&self) -> ParserErrorSrc { - ParserErrorSrc { - line_num: *self.line_num, - col_num: *self.col_num, - } + pub fn reset(&mut self) { + self.stack.clear() } fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { - if let Some(term) = self.term_from_stack(index - 1) { + if let Some(mut term) = self.terms.pop() { let mut op_desc = self.stack[index - 1]; - let mut term = heap_bound_store(&self.terms, heap_bound_deref(&self.terms, term)); - if term.is_ref() - && 0 < op_desc.priority - && op_desc.priority < self.stack[index].priority - { + if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority { /* '|' is a head-tail separator here, not * an operator, so expand the * terms it compacted out again. */ - - let focus = term.get_value() as usize; - let key_opt = term_predicate_key(&self.terms, focus); - - if key_opt == Some((atom!(","), 2)) { + if let (Some(atom!(",")), 2) = (term.name(), term.arity()) { let terms = if op_desc.unfold_bounds == 0 { - unfold_by_str(&mut self.terms, term, atom!(",")) + unfold_by_str(term, atom!(",")) } else { let mut terms = vec![]; - while let Some(fst_loc) = - unfold_by_str_once(&mut self.terms, term, atom!(",")) - { - let (_, snd) = subterm_index(&self.terms, fst_loc + 1); - let (_, fst) = subterm_index(&self.terms, fst_loc); - + while let Some((fst, snd)) = unfold_by_str_once(&mut term, atom!(",")) { terms.push(fst); term = snd; @@ -782,16 +625,13 @@ impl<'a> Parser<'a> { }; let arity = terms.len() - 1; - self.stack - .extend(terms.into_iter().map(|heap_loc| TokenDesc { - tt: TokenType::Term { heap_loc }, - priority: 0, - spec: 0, - unfold_bounds: 0, - })); + + self.terms.extend(terms); return arity; } } + + self.terms.push(term); } 0 @@ -831,18 +671,13 @@ impl<'a> Parser<'a> { } if let Some(ref mut td) = self.stack.last_mut() { - // parsed an empty list token if td.tt == TokenType::OpenList { - let h = self.terms.cell_len(); - self.terms - .write_with(|section| section.push_cell(empty_list_as_cell!())); - td.spec = TERM; - td.tt = TokenType::Term { - heap_loc: heap_loc_as_cell!(h), - }; + td.tt = TokenType::Term; td.priority = 0; + self.terms + .push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))); return Ok(true); } } @@ -856,99 +691,65 @@ impl<'a> Parser<'a> { // we know that self.stack.len() >= 2 by this point. let idx = self.stack.len() - 2; - let list_start_idx = self.stack.len() - 2 * arity; + let list_len = self.stack.len() - 2 * arity; - let mut tail_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { - empty_list_as_cell!() + let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { + Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))) } else { - let tail_term = match self.term_from_stack(idx + 1) { + let term = match self.terms.pop() { Some(term) => term, - None => { - return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); + _ => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) } }; - self.stack.pop(); - if self.stack[idx].priority > 1000 { arity += self.expand_comma_compacted_terms(idx); } - // decrement for the removal of tail term. - arity -= 1; - tail_term - }; - - if arity > self.terms.cell_len() { - return Err(ParserError::IncompleteReduction(self.loc_to_err_src())); - } - - let pre_terms_len = self.terms.cell_len(); - - while let Some(token_desc) = self.stack.pop() { - let subterm = match token_desc.tt { - TokenType::Term { heap_loc } => heap_loc, - _ => { - continue; - } - }; - arity -= 1; - let link_cell = list_loc_as_cell!(self.terms.cell_len() + 1); - - self.terms.write_with(|section| { - section.push_cell(link_cell); - section.push_cell(subterm); - section.push_cell(tail_term); - }); - - tail_term = link_cell; + term + }; - if arity == 0 { - break; - } + if arity > self.terms.len() { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); } - debug_assert_eq!(arity, 0); - - self.stack.truncate(list_start_idx); - - let list_loc = self.terms.cell_len() - 3; - - let head_term = self.terms[list_loc + 1]; - let tail_term = self.terms[list_loc + 2]; - - let heap_loc = match as_partial_string(&self.terms, head_term, tail_term) { - Some((string_buf, tail_opt)) => { - self.terms.truncate(pre_terms_len); + let idx = self.terms.len() - arity; - let HeapSectionWriteResult { bytes_written, .. } = - self.terms.write_with(|section| { - if let Some(pstr_cell) = section.push_pstr(&string_buf) { - section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); - section.push_cell(pstr_cell); - } - }); + let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| { + Term::Cons(Cell::default(), Box::new(t), Box::new(acc)) + }); - if bytes_written > 0 { - heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1) - } else { - empty_list_as_cell!() - } - } - None => { - heap_loc_as_cell!(list_loc) // head_term - } - }; + self.stack.truncate(list_len); self.stack.push(TokenDesc { - tt: TokenType::Term { heap_loc }, + tt: TokenType::Term, priority: 0, spec: TERM, unfold_bounds: 0, }); + self.terms.push(match list { + Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) { + Ok((string_buf, Some(tail))) => { + Term::PartialString(Cell::default(), Rc::new(string_buf), tail) + } + Ok((string_buf, None)) => { + Term::CompleteString(Cell::default(), Rc::new(string_buf)) + } + Err(term) => term, + }, + term => term, + }); + Ok(true) } @@ -959,17 +760,13 @@ impl<'a> Parser<'a> { if let Some(ref mut td) = self.stack.last_mut() { if td.tt == TokenType::OpenCurly { - let h = self.terms.cell_len(); - - self.terms - .write_with(|section| section.push_cell(atom_as_cell!(atom!("{}")))); - - td.tt = TokenType::Term { - heap_loc: heap_loc_as_cell!(h), - }; + td.tt = TokenType::Term; td.priority = 0; td.spec = TERM; + let term = Term::Literal(Cell::default(), Literal::Atom(atom!("{}"))); + + self.terms.push(term); return Ok(true); } } @@ -979,43 +776,29 @@ impl<'a> Parser<'a> { if self.stack.len() > 1 { if let Some(td) = self.stack.pop() { if let Some(ref mut oc) = self.stack.last_mut() { - if !matches!(td.tt, TokenType::Term { .. }) { + if td.tt != TokenType::Term { return Ok(false); } if oc.tt == TokenType::OpenCurly { - if let TokenType::Term { heap_loc } = td.tt { - let curly_idx = self.terms.cell_len(); - - oc.tt = TokenType::Term { - heap_loc: heap_loc_as_cell!(curly_idx + 2), - }; - oc.priority = 0; - oc.spec = TERM; - - self.terms.write_with(|section| { - section.push_cell(atom_as_cell!(atom!("{}"), 1)); - section.push_cell(heap_loc); - section.push_cell(str_loc_as_cell!(curly_idx)); - }); - - /* - let term = match self.terms.pop() { - Some(term) => term, - _ => { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )) - } - }; - - self.terms - .push(Term::Clause(Cell::default(), atom!("{}"), vec![term])); - */ - - return Ok(true); - } + oc.tt = TokenType::Term; + oc.priority = 0; + oc.spec = TERM; + + let term = match self.terms.pop() { + Some(term) => term, + _ => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } + }; + + self.terms + .push(Term::Clause(Cell::default(), atom!("{}"), vec![term])); + + return Ok(true); } } } @@ -1035,9 +818,8 @@ impl<'a> Parser<'a> { return false; } - match self.stack.last().map(|token| token.tt) { - Some(TokenType::Open | TokenType::OpenCT) => return false, - _ => {} + if let Some(TokenType::Open | TokenType::OpenCT) = self.stack.last().map(|token| token.tt) { + return false; } let idx = self.stack.len() - 2; @@ -1049,14 +831,13 @@ impl<'a> Parser<'a> { return false; } - let term = if self.stack[idx].tt.sep_to_atom().is_some() { - atom_as_cell!(atom!("|")) - } else { - self.term_from_stack(idx).unwrap() - }; + if let Some(atom) = self.stack[idx].tt.sep_to_atom() { + self.terms + .push(Term::Literal(Cell::default(), Literal::Atom(atom))); + } self.stack[idx].spec = BTERM; - self.stack[idx].tt = TokenType::Term { heap_loc: term }; + self.stack[idx].tt = TokenType::Term; self.stack[idx].priority = 0; true @@ -1074,11 +855,7 @@ impl<'a> Parser<'a> { }) = get_op_desc(name, op_dir) { if (pre > 0 && inf + post > 0) || is_negate!(spec) { - match self - .tokens - .last() - .ok_or(ParserError::unexpected_eof(self.loc_to_err_src()))? - { + match self.tokens.last().ok_or(ParserError::unexpected_eof())? { // do this when layout hasn't been inserted, // ie. why we don't match on Token::Open. Token::OpenCT => { @@ -1133,33 +910,31 @@ impl<'a> Parser<'a> { fn negate_number(&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); - - let after_len = parser_impl.terms.cell_len(); - - debug_assert!(after_len - before_len <= cell_index!(4 * term_byte_size)); + self.reduce_op(1400); - if parser_impl.stack.len() > 1 || parser_impl.terms.is_empty() { + if self.terms.len() > 1 || self.stack.len() > 1 { return Err(ParserError::IncompleteReduction( - parser_impl.loc_to_err_src(), + self.lexer.line_num, + self.lexer.col_num, )); } - match parser_impl.stack.pop() { - Some(TokenDesc { - tt: TokenType::Term { heap_loc }, - .. - }) => Ok(TermWriteResult { - focus: heap_loc.get_value() as usize, - inverse_var_locs: parser_impl.inverse_var_locs, - }), + match self.terms.pop() { + Some(term) => { + if self.terms.is_empty() { + Ok(term) + } else { + Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } + } _ => Err(ParserError::IncompleteReduction( - parser_impl.loc_to_err_src(), + self.lexer.line_num, + self.lexer.col_num, )), } } 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( + pub(crate) fn read( &mut self, - inner: R, + mut inner: Stream, op_dir: &OpDir, - ) -> Result<(TermWriteResult, usize), ParserError> { - let mut lexer_parser = LexerParser::new(inner, self); - let op_dir = CompositeOpDir::new(op_dir, None); + ) -> Result { + let (term, num_lines_read) = { + let prior_num_lines_read = inner.lines_read(); + let mut parser = Parser::new(inner, self); + let op_dir = CompositeOpDir::new(op_dir, None); - let term_result = lexer_parser.read_term(&op_dir, Tokens::Default); - let lines_read = lexer_parser.line_num(); + parser.add_lines_read(prior_num_lines_read); - term_result.map(|term| (term, lines_read)) - } + let term = parser + .read_term(&op_dir, Tokens::Default) + .map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from - pub(crate) fn read_to_heap( - &mut self, - mut inner: Stream, - op_dir: &OpDir, - ) -> Result { - let prior_num_lines_read = inner.lines_read(); - let term = match self.read(inner, op_dir) { - Ok((term, num_lines_read)) => { - inner.add_lines_read(num_lines_read); - term - } - Err(e) => { - return Err(error_after_read_term(e, prior_num_lines_read)); - } + (term, parser.lines_read() - prior_num_lines_read) }; - Ok(term) + inner.add_lines_read(num_lines_read); + write_term_to_heap(&term, &mut self.heap) } } @@ -278,6 +280,7 @@ impl CharRead for ReadlineStream { } } } + #[inline] fn consume(&mut self, nread: usize) { self.pending_input.consume(nread); @@ -288,3 +291,217 @@ impl CharRead for ReadlineStream { self.pending_input.put_back_char(c); } } + +#[inline] +pub(crate) fn write_term_to_heap( + term: &Term, + heap: &mut Heap, +) -> Result { + 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", ); } -- 2.54.0