DynamicProperty,
#[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
AbolishClause,
- #[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))]
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$asserta")))]
Asserta,
- #[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))]
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$assertz")))]
Assertz,
#[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
Retract,
use crate::instructions::*;
use crate::targets::*;
-use std::cell::Cell;
-
pub(crate) trait Allocator {
fn new() -> Self;
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
+ heap_loc: usize,
context: GenContext,
- cell: &'a Cell<RegType>,
code: &mut CodeDeque,
- );
+ ) -> RegType;
#[allow(clippy::too_many_arguments)]
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
- cell: &Cell<VarReg>,
- term_loc: GenContext,
+ context: GenContext,
code: &mut CodeDeque,
r: RegType,
is_new_var: bool,
- );
+ ) -> RegType;
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType;
&mut self,
var_num: usize,
lvl: Level,
- cell: &Cell<VarReg>,
context: GenContext,
code: &mut CodeDeque,
- );
+ ) -> RegType;
fn reset(&mut self);
fn reset_arg(&mut self, arg_num: usize);
- fn reset_at_head(&mut self, args: &[Term]);
+ fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize);
fn reset_contents(&mut self);
fn advance_arg(&mut self);
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
+use crate::machine::stack::Stack;
+use crate::parser::ast::FocusedHeap;
use crate::targets::QueryInstruction;
use crate::types::*;
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;
}
}
+pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
+
+/*
#[derive(Debug)]
pub(crate) struct ArithInstructionIterator<'a> {
state_stack: Vec<TermIterState<'a>>,
}
-pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
-
impl<'a> ArithInstructionIterator<'a> {
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
self.state_stack
}
}
-#[derive(Debug)]
-pub(crate) struct ArithmeticEvaluator<'a> {
- marker: &'a mut DebrayAllocator,
- interm: Vec<ArithmeticTerm>,
- interm_c: usize,
-}
-
pub(crate) trait ArithmeticTermIter<'a> {
type Iter: Iterator<Item = Result<ArithTermRef<'a>, ArithmeticError>>;
ArithInstructionIterator::from(self)
}
}
+*/
+
+#[derive(Debug)]
+pub(crate) struct ArithmeticEvaluator<'a> {
+ marker: &'a mut DebrayAllocator,
+ interm: Vec<ArithmeticTerm>,
+ interm_c: usize,
+}
-fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
+fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: Literal) -> Result<(), ArithmeticError> {
match c {
- Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
- Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
+ Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(n))),
+ Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(n))),
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))),
- Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
- Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
+ Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(n))),
+ Literal::Atom(name) if name == atom!("e") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(std::f64::consts::E)),
)),
- Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
+ Literal::Atom(name) if name == atom!("pi") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(std::f64::consts::PI)),
)),
- Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
+ Literal::Atom(name) if name == atom!("epsilon") => interm.push(ArithmeticTerm::Number(
Number::Float(OrderedFloat(f64::EPSILON)),
)),
- _ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
+ _ => return Err(ArithmeticError::NonEvaluableFunctor(c, 0)),
}
Ok(())
pub(crate) fn compile_is(
&mut self,
- src: &'a Term,
- term_loc: GenContext,
+ src: &mut FocusedHeap,
+ term_loc: usize,
+ context: GenContext,
arg: usize,
) -> Result<ArithCont, ArithmeticError> {
let mut code = CodeDeque::new();
-
- for term_ref in src.iter()? {
- match term_ref? {
- ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
- ArithTermRef::Var(lvl, cell, name) => {
- let var_num = name.to_var_num().unwrap();
-
- let r = if lvl == Level::Shallow {
- self.marker
- .mark_non_callable(var_num, arg, term_loc, cell, &mut code)
- } else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
- let r = self.marker.get_binding(var_num);
+ let mut stack = Stack::uninitialized();
+ let mut iter = query_iterator::<false>(&mut src.heap, &mut stack, term_loc);
+
+ while let Some(term) = iter.next() {
+ read_heap_cell!(term,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let lvl = iter.level();
+ let var_ptr = src.var_locs.read_next_var_ptr_at_key(h).unwrap();
+ let var_num = var_ptr.to_var_num().unwrap();
+ let old_r = self.marker.get_var_binding(var_num);
+
+ let r = if lvl == Level::Root {
+ self.marker.mark_non_callable(var_num, arg, context, &mut code)
+ } else if context.is_last() || old_r.reg_num() == 0 {
+ let r = old_r;
if r.reg_num() == 0 {
self.marker.mark_var::<QueryInstruction>(
- var_num, lvl, cell, term_loc, &mut code,
- );
- cell.get().norm()
+ var_num, lvl, context, &mut code,
+ )
} else {
self.marker.increment_running_count(var_num);
r
}
} else {
self.marker.increment_running_count(var_num);
- cell.get().norm()
+ old_r
};
self.interm.push(ArithmeticTerm::Reg(r));
}
- ArithTermRef::Op(name, arity) => {
- code.push_back(self.instr_from_clause(name, arity)?);
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ push_literal(&mut self.interm, Literal::Atom(name))?;
+ } else {
+ code.push_back(self.instr_from_clause(name, arity)?);
+ }
}
- }
+ _ => {
+ match Literal::try_from(term) {
+ Ok(lit) => push_literal(&mut self.interm, lit)?,
+ _ => unreachable!()
+ }
+ }
+ );
}
Ok((code, self.interm.pop()))
use crate::allocator::*;
+use crate::arena::ArenaHeaderTag;
use crate::arithmetic::*;
use crate::atom_table::*;
use crate::debray_allocator::*;
use crate::indexing::*;
use crate::instructions::*;
use crate::iterators::*;
+use crate::machine::heap::{heap_bound_deref, heap_bound_store};
use crate::parser::ast::*;
use crate::targets::*;
use crate::types::*;
use crate::machine::disjuncts::*;
use crate::machine::machine_errors::*;
+use crate::machine::machine_indices::CodeIndex;
+use crate::machine::machine_state::pstr_loc_and_offset;
+use crate::machine::stack::Stack;
use fxhash::FxBuildHasher;
+use indexmap::IndexMap;
use indexmap::IndexSet;
-use std::cell::Cell;
use std::collections::VecDeque;
#[derive(Debug)]
pub(crate) skeleton: PredicateSkeleton,
}
-impl DebrayAllocator {
- fn mark_var_in_non_callable(
- &mut self,
- var_num: usize,
- term_loc: GenContext,
- vr: &Cell<VarReg>,
- code: &mut CodeDeque,
- ) -> RegType {
- self.mark_var::<QueryInstruction>(var_num, Level::Shallow, vr, term_loc, code);
- vr.get().norm()
+fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) {
+ let subterm = heap[subterm_loc];
+
+ if subterm.is_ref() {
+ let subterm = heap_bound_deref(heap, subterm);
+ let subterm_loc = subterm.get_value() as usize;
+ let subterm = heap_bound_store(heap, subterm);
+
+ let subterm_loc = if subterm.is_ref() {
+ subterm.get_value() as usize
+ } else {
+ subterm_loc
+ };
+
+ (subterm_loc, subterm)
+ } else {
+ (subterm_loc, subterm)
}
+}
+impl DebrayAllocator {
pub(crate) fn mark_non_callable(
&mut self,
var_num: usize,
arg: usize,
- term_loc: GenContext,
- vr: &Cell<VarReg>,
+ context: GenContext,
code: &mut CodeDeque,
) -> RegType {
- match self.get_binding(var_num) {
+ match self.get_var_binding(var_num) {
RegType::Temp(t) if t != 0 => RegType::Temp(t),
RegType::Perm(p) if p != 0 => {
- if let GenContext::Last(_) = term_loc {
- self.mark_var_in_non_callable(var_num, term_loc, vr, code);
+ if let GenContext::Last(_) = context {
+ self.mark_var::<QueryInstruction>(var_num, Level::Shallow, context, code);
temp_v!(arg)
} else {
- if let VarAlloc::Perm(_, PermVarAllocation::Pending) =
+ if let VarAlloc::Perm { allocation: PermVarAllocation::Pending, .. } =
&self.var_data.records[var_num].allocation
{
- self.mark_var_in_non_callable(var_num, term_loc, vr, code);
+ self.mark_var::<QueryInstruction>(var_num, Level::Shallow, context, code);
} else {
self.increment_running_count(var_num);
}
RegType::Perm(p)
}
}
- _ => self.mark_var_in_non_callable(var_num, term_loc, vr, code),
- }
- }
-}
-
-// if the final argument of the structure is a Literal::Index,
-// decrement the arity of the PutStructure instruction by 1.
-fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) {
- match instr {
- Instruction::PutStructure(_, ref mut arity, _)
- | Instruction::GetStructure(.., ref mut arity, _) => {
- if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
- // it is acceptable if arity == 0 is the result of
- // this decrement. call/N will have to read the index
- // constant for '$call_inline' to succeed. to find it,
- // it must know the heap location of the index.
- // self.store must stop before reading the atom into a
- // register.
-
- *arity -= 1;
- }
+ _ => self.mark_var::<QueryInstruction>(var_num, Level::Shallow, context, code),
}
- _ => {}
}
}
trait AddToFreeList<'a, Target: CompilationTarget<'a>> {
fn add_term_to_free_list(&mut self, r: RegType);
- fn add_subterm_to_free_list(&mut self, term: &Term);
+ fn add_subterm_to_free_list(&mut self, r: RegType);
}
impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> {
self.marker.add_reg_to_free_list(r);
}
- fn add_subterm_to_free_list(&mut self, _term: &Term) {}
+ fn add_subterm_to_free_list(&mut self, _r: RegType) {}
}
impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> {
fn add_term_to_free_list(&mut self, _r: RegType) {}
#[inline(always)]
- fn add_subterm_to_free_list(&mut self, term: &Term) {
- if let Some(cell) = structure_cell(term) {
- self.marker.add_reg_to_free_list(cell.get());
- }
+ fn add_subterm_to_free_list(&mut self, r: RegType) {
+ self.marker.add_reg_to_free_list(r);
}
}
-fn structure_cell(term: &Term) -> Option<&Cell<RegType>> {
- match term {
- &Term::Cons(ref cell, ..)
- | &Term::Clause(ref cell, ..)
- | Term::PartialString(ref cell, ..)
- | Term::CompleteString(ref cell, ..) => Some(cell),
- _ => None,
+fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>(
+ index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
+ heap: &[HeapCellValue],
+ arity: usize,
+ heap_loc: usize,
+) -> Option<Instruction> {
+ match fetch_index_ptr(heap, arity, heap_loc) {
+ Some(index_ptr) => {
+ let subterm = Literal::CodeIndex(index_ptr);
+ return Some(Target::constant_subterm(subterm));
+ }
+ None => {
+ // if Level::Shallow == lvl {
+ if let Some(index_ptr) = index_ptrs.get(&heap_loc) {
+ let subterm = Literal::CodeIndex(*index_ptr);
+ return Some(Target::constant_subterm(subterm));
+ }
+ // }
+ }
}
+
+ None
}
impl<'b> CodeGenerator<'b> {
fn deep_var_instr<'a, Target: crate::targets::CompilationTarget<'a>>(
&mut self,
- cell: &'a Cell<VarReg>,
var_num: usize,
- term_loc: GenContext,
+ context: GenContext,
target: &mut CodeDeque,
) {
if self.marker.var_data.records[var_num].num_occurrences > 1 {
self.marker
- .mark_var::<Target>(var_num, Level::Deep, cell, term_loc, target);
+ .mark_var::<Target>(var_num, Level::Deep, context, target);
} else {
Self::add_or_increment_void_instr::<Target>(target);
}
fn subterm_to_instr<'a, Target: crate::targets::CompilationTarget<'a>>(
&mut self,
- subterm: &'a Term,
- term_loc: GenContext,
+ subterm: HeapCellValue,
+ var_locs: &mut VarLocs,
+ heap_loc: usize,
+ context: GenContext,
+ index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
target: &mut CodeDeque,
- ) {
- match subterm {
- &Term::AnonVar => {
- Self::add_or_increment_void_instr::<Target>(target);
+ ) -> Option<RegType> {
+ let subterm = unmark_cell_bits!(subterm);
+
+ read_heap_cell!(subterm,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = var_locs.read_next_var_ptr_at_key(h).unwrap();
+
+ if var_ptr.is_anon() {
+ Self::add_or_increment_void_instr::<Target>(target);
+ } else {
+ let var_num = var_ptr.to_var_num().unwrap();
+
+ self.deep_var_instr::<Target>(
+ var_num,
+ context,
+ target,
+ );
+ }
+
+ None
}
- &Term::Cons(ref cell, ..)
- | &Term::Clause(ref cell, ..)
- | Term::PartialString(ref cell, ..)
- | Term::CompleteString(ref cell, ..) => {
- self.marker
- .mark_non_var::<Target>(Level::Deep, term_loc, cell, target);
- target.push_back(Target::clause_arg_to_instr(cell.get()));
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+
+ if index_ptrs.contains_key(&heap_loc) {
+ let r = self.marker.mark_non_var::<Target>(Level::Deep, heap_loc, context, target);
+ target.push_back(Target::clause_arg_to_instr(r));
+ return Some(r);
+ } else {
+ target.push_back(Target::constant_subterm(Literal::Atom(name)));
+ }
+
+ None
}
- Term::Literal(_, ref constant) => {
- target.push_back(Target::constant_subterm(*constant));
+ (HeapCellValueTag::Str
+ | HeapCellValueTag::Lis
+ | HeapCellValueTag::PStrLoc
+ | HeapCellValueTag::CStr) => {
+ let r = self.marker.mark_non_var::<Target>(Level::Deep, heap_loc, context, target);
+ target.push_back(Target::clause_arg_to_instr(r));
+ return Some(r);
}
- Term::Var(ref cell, ref var_ptr) => {
- self.deep_var_instr::<Target>(
- cell,
- var_ptr.to_var_num().unwrap(),
- term_loc,
- target,
- );
+ _ => {
+ match Literal::try_from(subterm) {
+ Ok(lit) => target.push_back(Target::constant_subterm(lit)),
+ Err(_) => unreachable!(),
+ }
+
+ None
}
- };
+ )
}
- fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, term_loc: GenContext) -> CodeDeque
+ fn compile_target<'a, Target, Iter>(
+ &mut self,
+ mut iter: Iter,
+ index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
+ var_locs: &mut VarLocs,
+ context: GenContext,
+ ) -> CodeDeque
where
Target: crate::targets::CompilationTarget<'a>,
- Iter: Iterator<Item = TermRef<'a>>,
+ Iter: TermIterator,
CodeGenerator<'b>: AddToFreeList<'a, Target>,
{
let mut target = CodeDeque::new();
- for term in iter {
- match term {
- TermRef::AnonVar(lvl @ Level::Shallow) => {
- if let GenContext::Head = term_loc {
- self.marker.advance_arg();
+ while let Some(term) = iter.next() {
+ let lvl = iter.level();
+ let term = unmark_cell_bits!(term);
+
+ read_heap_cell!(term,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if lvl == Level::Shallow {
+ let var_ptr = var_locs.read_next_var_ptr_at_key(h).unwrap();
+
+ if var_ptr.is_anon() {
+ if let GenContext::Head = context {
+ self.marker.advance_arg();
+ } else {
+ self.marker.mark_anon_var::<Target>(lvl, context, &mut target);
+ }
+ } else {
+ self.marker.mark_var::<Target>(
+ var_ptr.to_var_num().unwrap(),
+ lvl,
+ context,
+ &mut target,
+ );
+ }
+ }
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ let heap_loc = iter.focus().value() as usize;
+ let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
+
+ if arity == 0 {
+ if let Some(instr) = add_index_ptr::<Target>(index_ptrs, &iter, arity, heap_loc) {
+ let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
+ target.push_back(Target::to_structure(lvl, name, 0, r));
+ target.push_back(instr);
+ } else if lvl == Level::Shallow {
+ let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
+ target.push_back(Target::to_constant(lvl, Literal::Atom(name), r));
+ }
} else {
- self.marker
- .mark_anon_var::<Target>(lvl, term_loc, &mut target);
+ let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
+ target.push_back(Target::to_structure(lvl, name, arity, r));
+
+ <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
+ self,
+ r,
+ );
+
+ let free_list_regs: Vec<_> = (heap_loc + 1 ..= heap_loc + arity)
+ .map(|subterm_loc| {
+ let (subterm_loc, subterm) = subterm_index(iter.deref(), subterm_loc);
+
+ self.subterm_to_instr::<Target>(
+ subterm, var_locs, subterm_loc, context, index_ptrs, &mut target,
+ )
+ })
+ .collect();
+
+ if let Some(instr) = add_index_ptr::<Target>(index_ptrs, &iter, arity, heap_loc) {
+ target.push_back(instr);
+ }
+
+ for r_opt in free_list_regs {
+ if let Some(r) = r_opt {
+ <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+ self, r,
+ );
+ }
+ }
}
}
- TermRef::Clause(lvl, cell, name, terms) => {
- self.marker
- .mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
- target.push_back(Target::to_structure(lvl, name, terms.len(), cell.get()));
+ (HeapCellValueTag::Lis, l) => {
+ let heap_loc = iter.focus().value() as usize;
+ let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
+
+ let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
+
+ target.push_back(Target::to_list(lvl, r));
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
self,
- cell.get(),
+ r,
);
- if let Some(instr) = target.back_mut() {
- if let Some(term) = terms.last() {
- trim_structure_by_last_arg(instr, term);
- }
- }
+ let (head_loc, head) = subterm_index(iter.deref(), l);
+ let (tail_loc, tail) = subterm_index(iter.deref(), l+1);
+
+ let head_r_opt = self.subterm_to_instr::<Target>(
+ head,
+ var_locs,
+ head_loc,
+ context,
+ index_ptrs,
+ &mut target,
+ );
- for subterm in terms {
- self.subterm_to_instr::<Target>(subterm, term_loc, &mut target);
+ let tail_r_opt = self.subterm_to_instr::<Target>(
+ tail,
+ var_locs,
+ tail_loc,
+ context,
+ index_ptrs,
+ &mut target,
+ );
+
+ if let Some(r) = head_r_opt {
+ <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+ self, r,
+ );
}
- for subterm in terms {
+ if let Some(r) = tail_r_opt {
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
- self, subterm,
+ self, r,
);
}
}
- TermRef::Cons(lvl, cell, head, tail) => {
- self.marker
- .mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
- target.push_back(Target::to_list(lvl, cell.get()));
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ let heap_loc = iter.focus().value() as usize;
+ let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
- <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
- self,
- cell.get(),
- );
+ target.push_back(Target::to_pstr(lvl, cstr_atom, r, false));
+ }
+ (HeapCellValueTag::PStr, pstr_atom) => {
+ let heap_loc = iter.focus().value() as usize;
+ let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
+ let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
- self.subterm_to_instr::<Target>(head, term_loc, &mut target);
- self.subterm_to_instr::<Target>(tail, term_loc, &mut target);
+ target.push_back(Target::to_pstr(lvl, pstr_atom, r, true));
- <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
- self, head,
- );
- <CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
- self, tail,
+ let (tail_loc, tail) = subterm_index(iter.deref(), heap_loc + 1);
+ self.subterm_to_instr::<Target>(
+ tail, var_locs, tail_loc, context, index_ptrs, &mut target,
);
}
- TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => {
- self.marker
- .mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
- target.push_back(Target::to_pstr(lvl, *string, cell.get(), false));
- }
- TermRef::Literal(lvl @ Level::Shallow, cell, constant) => {
- self.marker
- .mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
- target.push_back(Target::to_constant(lvl, *constant, cell.get()));
- }
- TermRef::PartialString(lvl, cell, string, tail) => {
- self.marker
- .mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
- let atom = AtomTable::build_with(self.atom_tbl, string);
+ (HeapCellValueTag::PStrOffset, l) => {
+ let heap_loc = iter.focus().value() as usize;
+ let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
- target.push_back(Target::to_pstr(lvl, atom, cell.get(), true));
- self.subterm_to_instr::<Target>(tail, term_loc, &mut target);
- }
- TermRef::CompleteString(lvl, cell, atom) => {
- self.marker
- .mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
- target.push_back(Target::to_pstr(lvl, atom, cell.get(), false));
- }
- TermRef::Var(lvl @ Level::Shallow, cell, var) => {
- self.marker.mark_var::<Target>(
- var.to_var_num().unwrap(),
- lvl,
- cell,
- term_loc,
- &mut target,
+ let (index, n) = pstr_loc_and_offset(&iter, l);
+ let n = n.get_num() as usize;
+
+ let pstr_atom = cell_as_atom!(iter[index]);
+ let pstr_offset_atom = if n == 0 {
+ pstr_atom
+ } else {
+ AtomTable::build_with(self.atom_tbl, &pstr_atom.as_str()[n ..])
+ };
+
+ let (tail_loc, tail) = subterm_index(iter.deref(), l+1);
+ target.push_back(Target::to_pstr(lvl, pstr_offset_atom, r, true));
+
+ self.subterm_to_instr::<Target>(
+ tail, var_locs, tail_loc, context, index_ptrs, &mut target,
);
}
+ _ if lvl == Level::Shallow => {
+ if let Ok(lit) = Literal::try_from(term) {
+ let heap_loc = iter.focus().value() as usize;
+ let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
+ let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
+ target.push_back(Target::to_constant(lvl, lit, r));
+ }
+ }
_ => {}
- };
+ );
}
target
fn compile_inlined(
&mut self,
ct: &InlinedClauseType,
- terms: &'_ [Term],
- term_loc: GenContext,
+ terms: &mut FocusedHeap,
+ term_loc: usize,
+ context: GenContext,
code: &mut CodeDeque,
) -> Result<(), CompilationError> {
+ let term = terms.heap[terms.nth_arg(term_loc, 1).unwrap()];
+
let call_instr = match ct {
&InlinedClauseType::CompareNumber(mut cmp) => {
self.marker.reset_arg(2);
- let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc, 1)?;
+ let (mut lcode, at_1) =
+ self.compile_arith_expr(terms, term_loc + 1, 1, context, 1)?;
- if !matches!(terms[0], Term::Var(..)) {
+ if !terms.deref_loc(term_loc + 1).is_var() {
self.marker.advance_arg();
}
- let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc, 2)?;
+ let (mut rcode, at_2) =
+ self.compile_arith_expr(terms, term_loc + 2, 2, context, 2)?;
code.append(&mut lcode);
code.append(&mut rcode);
compare_number_instr!(cmp, at_1, at_2)
}
- InlinedClauseType::IsAtom(..) => match &terms[0] {
- Term::Literal(_, Literal::Char(_))
- | Term::Literal(_, Literal::Atom(atom!("[]")))
- | Term::Literal(_, Literal::Atom(..)) => {
+ InlinedClauseType::IsAtom(..) => read_heap_cell!(term,
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ if arity == 0 {
+ instr!("$succeed")
+ } else {
+ instr!("$fail")
+ }
+ }
+ (HeapCellValueTag::Char) => {
instr!("$succeed")
}
- Term::Var(ref vr, ref name) => {
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
self.marker.reset_arg(1);
- let r = self.marker.mark_non_callable(
- name.to_var_num().unwrap(),
- 1,
- term_loc,
- vr,
- code,
- );
+ if var_ptr.is_anon() {
+ instr!("$fail")
+ } else {
+ let r = self.marker.mark_non_callable(
+ var_ptr.to_var_num().unwrap(),
+ 1,
+ context,
+ code,
+ );
- instr!("atom", r)
+ instr!("atom", r)
+ }
}
_ => {
instr!("$fail")
}
- },
- InlinedClauseType::IsAtomic(..) => match &terms[0] {
- Term::AnonVar
- | Term::Clause(..)
- | Term::Cons(..)
- | Term::PartialString(..)
- | Term::CompleteString(..) => {
- instr!("$fail")
- }
- Term::Literal(_, Literal::String(_)) => {
- instr!("$fail")
- }
- Term::Literal(..) => {
- instr!("$succeed")
- }
- Term::Var(ref vr, ref name) => {
- self.marker.reset_arg(1);
+ ),
+ InlinedClauseType::IsAtomic(..) => read_heap_cell!(term,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
- let r = self.marker.mark_non_callable(
- name.to_var_num().unwrap(),
- 1,
- term_loc,
- vr,
- code,
- );
+ if var_ptr.is_anon() {
+ instr!("$fail")
+ } else {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ var_ptr.to_var_num().unwrap(),
+ 1,
+ context,
+ code,
+ );
- instr!("atomic", r)
+ instr!("atomic", r)
+ }
}
- },
- InlinedClauseType::IsCompound(..) => match &terms[0] {
- Term::Clause(..)
- | Term::Cons(..)
- | Term::PartialString(..)
- | Term::CompleteString(..)
- | Term::Literal(_, Literal::String(..)) => {
+ (HeapCellValueTag::Fixnum |
+ HeapCellValueTag::Char |
+ HeapCellValueTag::F64) => {
instr!("$succeed")
}
- Term::Var(ref vr, ref name) => {
- self.marker.reset_arg(1);
-
- let r = self.marker.mark_non_callable(
- name.to_var_num().unwrap(),
- 1,
- term_loc,
- vr,
- code,
- );
-
- instr!("compound", r)
- }
- _ => {
- instr!("$fail")
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match cons_ptr.get_tag() {
+ ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => {
+ instr!("$succeed")
+ }
+ _ => {
+ instr!("$fail")
+ }
+ }
}
- },
- InlinedClauseType::IsRational(..) => match terms[0] {
- Term::Literal(_, Literal::Rational(_)) => {
- instr!("$succeed")
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ if arity == 0 {
+ instr!("$succeed")
+ } else {
+ instr!("$fail")
+ }
}
- Term::Var(ref vr, ref name) => {
- self.marker.reset_arg(1);
- let r = self.marker.mark_non_callable(
- name.to_var_num().unwrap(),
- 1,
- term_loc,
- vr,
- code,
- );
- instr!("rational", r)
+ (HeapCellValueTag::Lis
+ | HeapCellValueTag::Str
+ | HeapCellValueTag::PStrLoc
+ | HeapCellValueTag::CStr) => {
+ instr!("$fail")
}
_ => {
- instr!("$fail")
+ if Literal::try_from(term).is_ok() {
+ instr!("$succeed")
+ } else {
+ instr!("$fail")
+ }
}
- },
- InlinedClauseType::IsFloat(..) => match terms[0] {
- Term::Literal(_, Literal::Float(_)) => {
+ ),
+ InlinedClauseType::IsCompound(..) => {
+ read_heap_cell!(term,
+ (HeapCellValueTag::Atom, (_, arity)) => {
+ if arity > 0 {
+ instr!("$succeed")
+ } else {
+ instr!("$fail")
+ }
+ }
+ (HeapCellValueTag::Lis
+ | HeapCellValueTag::Str
+ | HeapCellValueTag::PStrLoc
+ | HeapCellValueTag::CStr) => {
+ instr!("$succeed")
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
+
+ if var_ptr.is_anon() {
+ instr!("$fail")
+ } else {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ var_ptr.to_var_num().unwrap(),
+ 1,
+ context,
+ code,
+ );
+
+ instr!("compound", r)
+ }
+ }
+ _ => {
+ instr!("$fail")
+ }
+ )
+ }
+ InlinedClauseType::IsRational(..) => {
+ read_heap_cell!(term,
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match cons_ptr.get_tag() {
+ ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => {
+ instr!("$succeed")
+ }
+ _ => {
+ instr!("$fail")
+ }
+ }
+ }
+ (HeapCellValueTag::Fixnum) => {
+ instr!("$succeed")
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
+ self.marker.reset_arg(1);
+
+ if var_ptr.is_anon() {
+ instr!("$fail")
+ } else {
+ let r = self.marker.mark_non_callable(
+ var_ptr.to_var_num().unwrap(),
+ 1,
+ context,
+ code,
+ );
+
+ instr!("rational", r)
+ }
+ }
+ _ => {
+ instr!("$fail")
+ }
+ )
+ }
+ InlinedClauseType::IsFloat(..) => read_heap_cell!(term,
+ (HeapCellValueTag::F64) => {
instr!("$succeed")
}
- Term::Var(ref vr, ref name) => {
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
self.marker.reset_arg(1);
- let r = self.marker.mark_non_callable(
- name.to_var_num().unwrap(),
- 1,
- term_loc,
- vr,
- code,
- );
+ if var_ptr.is_anon() {
+ instr!("$fail")
+ } else {
+ let r = self.marker.mark_non_callable(
+ var_ptr.to_var_num().unwrap(),
+ 1,
+ context,
+ code,
+ );
- instr!("float", r)
+ instr!("float", r)
+ }
}
_ => {
instr!("$fail")
}
- },
- InlinedClauseType::IsNumber(..) => match terms[0] {
- Term::Literal(_, Literal::Float(_))
- | Term::Literal(_, Literal::Rational(_))
- | Term::Literal(_, Literal::Integer(_))
- | Term::Literal(_, Literal::Fixnum(_)) => {
- instr!("$succeed")
- }
- Term::Var(ref vr, ref name) => {
+ ),
+ InlinedClauseType::IsNumber(..) => read_heap_cell!(term,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
self.marker.reset_arg(1);
- let r = self.marker.mark_non_callable(
- name.to_var_num().unwrap(),
- 1,
- term_loc,
- vr,
- code,
- );
+ if var_ptr.is_anon() {
+ instr!("$fail")
+ } else {
+ let r = self.marker.mark_non_callable(
+ var_ptr.to_var_num().unwrap(),
+ 1,
+ context,
+ code,
+ );
- instr!("number", r)
+ instr!("number", r)
+ }
}
_ => {
- instr!("$fail")
- }
- },
- InlinedClauseType::IsNonVar(..) => match terms[0] {
- Term::AnonVar => {
- instr!("$fail")
+ if Number::try_from(term).is_ok() {
+ instr!("$succeed")
+ } else {
+ instr!("$fail")
+ }
}
- Term::Var(ref vr, ref name) => {
+ ),
+ InlinedClauseType::IsNonVar(..) => read_heap_cell!(term,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
self.marker.reset_arg(1);
- let r = self.marker.mark_non_callable(
- name.to_var_num().unwrap(),
- 1,
- term_loc,
- vr,
- code,
- );
+ if var_ptr.is_anon() {
+ instr!("$fail")
+ } else {
+ let r = self.marker.mark_non_callable(
+ var_ptr.to_var_num().unwrap(),
+ 1,
+ context,
+ code,
+ );
- instr!("nonvar", r)
+ instr!("nonvar", r)
+ }
}
_ => {
instr!("$succeed")
}
- },
- InlinedClauseType::IsInteger(..) => match &terms[0] {
- Term::Literal(_, Literal::Integer(_)) | Term::Literal(_, Literal::Fixnum(_)) => {
- instr!("$succeed")
- }
- Term::Var(ref vr, name) => {
+ ),
+ InlinedClauseType::IsInteger(..) => {
+ read_heap_cell!(term,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
+ self.marker.reset_arg(1);
+
+ if var_ptr.is_anon() {
+ instr!("$fail")
+ } else {
+ let r = self.marker.mark_non_callable(
+ var_ptr.to_var_num().unwrap(),
+ 1,
+ context,
+ code,
+ );
+
+ instr!("integer", r)
+ }
+ }
+ _ => {
+ match Number::try_from(term) {
+ Ok(Number::Integer(_) | Number::Fixnum(_)) => {
+ instr!("$succeed")
+ }
+ _ => {
+ instr!("$fail")
+ }
+ }
+ }
+ )
+ }
+ InlinedClauseType::IsVar(..) => read_heap_cell!(term,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
self.marker.reset_arg(1);
- let r = self.marker.mark_non_callable(
- name.to_var_num().unwrap(),
- 1,
- term_loc,
- vr,
- code,
- );
+ if var_ptr.is_anon() {
+ instr!("$succeed")
+ } else {
+ let r = self.marker.mark_non_callable(
+ var_ptr.to_var_num().unwrap(),
+ 1,
+ context,
+ code,
+ );
- instr!("integer", r)
+ instr!("var", r)
+ }
}
_ => {
instr!("$fail")
}
- },
- InlinedClauseType::IsVar(..) => match terms[0] {
- Term::Literal(..)
- | Term::Clause(..)
- | Term::Cons(..)
- | Term::PartialString(..)
- | Term::CompleteString(..) => {
- instr!("$fail")
- }
- Term::AnonVar => {
- instr!("$succeed")
- }
- Term::Var(ref vr, ref name) => {
- self.marker.reset_arg(1);
-
- let r = self.marker.mark_non_callable(
- name.to_var_num().unwrap(),
- 1,
- term_loc,
- vr,
- code,
- );
-
- instr!("var", r)
- }
- },
+ ),
};
// inlined predicates are never counted, so this overrides nothing.
fn compile_arith_expr(
&mut self,
- term: &Term,
+ terms: &mut FocusedHeap,
+ term_loc: usize,
target_int: usize,
- term_loc: GenContext,
+ context: GenContext,
arg: usize,
) -> Result<ArithCont, ArithmeticError> {
let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int);
- evaluator.compile_is(term, term_loc, arg)
+ evaluator.compile_is(terms, term_loc, context, arg)
}
fn compile_is_call(
&mut self,
- terms: &[Term],
+ terms: &mut FocusedHeap,
+ term_loc: usize,
code: &mut CodeDeque,
- term_loc: GenContext,
+ context: GenContext,
call_policy: CallPolicy,
) -> Result<(), CompilationError> {
macro_rules! compile_expr {
- ($self:expr, $terms:expr, $term_loc:expr, $code:expr) => {{
- let (acode, at) = $self.compile_arith_expr($terms, 1, $term_loc, 2)?;
+ ($self:expr, $terms:expr, $context:expr, $code:expr) => {{
+ let (acode, at) =
+ $self.compile_arith_expr($terms, term_loc + 2, 1, $context, 2)?;
$code.extend(acode.into_iter());
at
}};
self.marker.reset_arg(2);
- let at = match terms[0] {
- Term::Var(ref vr, ref name) => {
- let var_num = name.to_var_num().unwrap();
+ let var = {
+ let var_cell = terms.heap[term_loc + 1];
+ let terms = FocusedHeapRefMut::from_cell(&mut terms.heap, var_cell);
+
+ terms.deref_loc(term_loc + 1)
+ };
+
+ let at = read_heap_cell!(var,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
+ let var_num = var_ptr.to_var_num().unwrap();
if self.marker.var_data.records[var_num].num_occurrences > 1 {
self.marker.mark_var::<QueryInstruction>(
var_num,
Level::Shallow,
- vr,
- term_loc,
+ context,
code,
);
self.marker.mark_safe_var_unconditionally(var_num);
- compile_expr!(self, &terms[1], term_loc, code)
+ compile_expr!(self, terms, context, code)
} else {
- self.marker
- .mark_anon_var::<QueryInstruction>(Level::Shallow, term_loc, code);
+ /*
+ if var.is_var() {
+ let h = var.get_value() as usize;
- if let Term::Var(ref vr, ref var) = &terms[1] {
- let var_num = var.to_var_num().unwrap();
+ let var_ptr = terms.var_locs.read_next_var_ptr_at_key(h).unwrap();
+ let var_num = var_ptr.to_var_num().unwrap();
// if var is an anonymous variable, insert
// is/2 call so that an instantiation error is
// thrown when the predicate is run.
+
if self.marker.var_data.records[var_num].num_occurrences > 1 {
- self.marker.mark_var::<QueryInstruction>(
+ let r = self.marker.mark_var::<QueryInstruction>(
var_num,
Level::Shallow,
- vr,
- term_loc,
+ context,
code,
);
self.marker.mark_safe_var_unconditionally(var_num);
- let at = ArithmeticTerm::Reg(vr.get().norm());
+ let at = ArithmeticTerm::Reg(r);
self.add_call(code, instr!("$get_number", at), call_policy);
return Ok(());
}
}
+ */
- compile_expr!(self, &terms[1], term_loc, code)
+ compile_expr!(self, terms, context, code)
}
}
- Term::Literal(
- _,
- c @ Literal::Integer(_)
- | c @ Literal::Float(_)
- | c @ Literal::Rational(_)
- | c @ Literal::Fixnum(_),
- ) => {
- let v = HeapCellValue::from(c);
- code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
-
- self.marker.advance_arg();
- compile_expr!(self, &terms[1], term_loc, code)
- }
_ => {
- code.push_back(instr!("$fail"));
- return Ok(());
+ if Number::try_from(var).is_ok() {
+ let v = HeapCellValue::from(var);
+ code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
+
+ self.marker.advance_arg();
+ compile_expr!(self, terms, context, code)
+ } else {
+ code.push_back(instr!("$fail"));
+ return Ok(());
+ }
}
- };
+ );
let at = at.unwrap_or(interm!(1));
self.add_call(code, instr!("is", temp_v!(1), at), call_policy);
fn compile_seq(
&mut self,
+ terms: &mut FocusedHeap,
clauses: &ChunkedTermVec,
code: &mut CodeDeque,
) -> Result<(), CompilationError> {
match clause_item {
ClauseItem::Chunk(chunk) => {
for (idx, term) in chunk.iter().enumerate() {
- let term_loc = if idx + 1 < chunk.len() {
+ let context = if idx + 1 < chunk.len() {
GenContext::Mid(chunk_num)
} else {
self.marker.in_tail_position = clause_iter.in_tail_position();
if chunk_num == 0 {
code.push_back(instr!("neck_cut"));
} else {
- let r = self.marker.get_binding(var_num);
+ let r = self.marker.get_var_binding(var_num);
code.push_back(instr!("cut", r));
}
}
&QueryTerm::LocalCut { var_num, cut_prev } => {
let code = branch_code_stack.code(code);
- let r = self.marker.get_binding(var_num);
+ let r = self.marker.get_var_binding(var_num);
code.push_back(if cut_prev {
instr!("cut_prev", r)
}
}
&QueryTerm::Clause(
- _,
- ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
- ref terms,
- call_policy,
+ ref clause @ QueryClause {
+ ct: ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
+ call_policy,
+ ..
+ },
) => self.compile_is_call(
terms,
+ clause.term_loc(),
branch_code_stack.code(code),
- term_loc,
+ context,
call_policy,
)?,
- &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => {
- self.compile_inlined(
- ct,
- terms,
- term_loc,
- branch_code_stack.code(code),
- )?
- }
+ &QueryTerm::Clause(
+ ref clause @ QueryClause {
+ ct: ClauseType::Inlined(ref ct),
+ ..
+ },
+ ) => self.compile_inlined(
+ ct,
+ terms,
+ clause.term_loc(),
+ context,
+ branch_code_stack.code(code),
+ )?,
&QueryTerm::Fail => {
branch_code_stack.code(code).push_back(instr!("$fail"));
}
- term @ &QueryTerm::Clause(..) => {
+ &QueryTerm::Succeed => {
+ let code = branch_code_stack.code(code);
+
+ if self.marker.in_tail_position {
+ if self.marker.var_data.allocates {
+ code.push_back(instr!("deallocate"));
+ }
+ }
+
+ code.push_back(
+ if self.marker.in_tail_position {
+ instr!("$succeed").to_execute()
+ } else {
+ instr!("$succeed")
+ },
+ );
+ }
+ QueryTerm::Clause(clause) => {
self.compile_query_line(
- term,
- term_loc,
+ terms,
+ clause,
+ context,
branch_code_stack.code(code),
);
pub(crate) fn compile_rule(
&mut self,
- rule: &Rule,
+ rule: &mut Rule,
var_data: VarData,
) -> Result<Code, CompilationError> {
let Rule {
- head: (_, args),
+ ref mut term,
clauses,
} = rule;
self.marker.var_data = var_data;
+
let mut code = VecDeque::new();
+ let head_loc = term.nth_arg(term.focus, 1).unwrap();
- self.marker.reset_at_head(args);
+ self.marker.reset_at_head(term, head_loc);
- let iter = FactIterator::from_rule_head_clause(args);
- let fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head);
+ let mut stack = Stack::uninitialized();
+ let iter = fact_iterator::<true>(
+ &mut term.heap, &mut stack, head_loc,
+ );
+
+ let fact = self.compile_target::<FactInstruction, _>(
+ iter,
+ &IndexMap::with_hasher(FxBuildHasher::default()),
+ &mut term.var_locs,
+ GenContext::Head,
+ );
if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity);
self.marker.reset_free_list();
code.extend(fact);
- self.compile_seq(clauses, &mut code)?;
+ self.compile_seq(term, &clauses, &mut code)?;
Ok(Vec::from(code))
}
pub(crate) fn compile_fact(
&mut self,
- fact: &Fact,
+ fact: &mut Fact,
var_data: VarData,
) -> Result<Code, CompilationError> {
let mut code = Vec::new();
- self.marker.var_data = var_data;
- if let Term::Clause(_, _, args) = &fact.head {
- self.marker.reset_at_head(args);
+ let fact_focus = fact.term.focus;
+ let mut stack = Stack::uninitialized();
- let iter = FactInstruction::iter(&fact.head);
- let compiled_fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head);
+ self.marker.var_data = var_data;
+ self.marker.reset_at_head(&mut fact.term, fact_focus);
- if self.marker.max_reg_allocated() > MAX_ARITY {
- return Err(CompilationError::ExceededMaxArity);
- }
+ let iter = fact_iterator::<true>(
+ &mut fact.term.heap, &mut stack, fact_focus,
+ );
- code.extend(compiled_fact);
+ let compiled_fact = self.compile_target::<FactInstruction, _>(
+ iter,
+ &IndexMap::with_hasher(FxBuildHasher::default()),
+ &mut fact.term.var_locs,
+ GenContext::Head,
+ );
+
+ if self.marker.max_reg_allocated() > MAX_ARITY {
+ return Err(CompilationError::ExceededMaxArity);
}
+ code.extend(compiled_fact);
code.push(instr!("proceed"));
+
Ok(code)
}
- fn compile_query_line(&mut self, term: &QueryTerm, term_loc: GenContext, code: &mut CodeDeque) {
- self.marker.reset_arg(term.arity());
+ fn compile_query_line(
+ &mut self,
+ term: &mut FocusedHeap,
+ clause: &QueryClause,
+ context: GenContext,
+ code: &mut CodeDeque,
+ ) {
+ self.marker.reset_arg(term.arity(clause.term_loc()));
- let iter = QueryIterator::new(term);
- let query = self.compile_target::<QueryInstruction, _>(iter, term_loc);
+ let mut stack = Stack::uninitialized();
+ let iter = query_iterator::<true>(&mut term.heap, &mut stack, clause.term_loc());
- code.extend(query);
+ let query = self.compile_target::<QueryInstruction, _>(
+ iter,
+ &clause.code_indices,
+ &mut term.var_locs,
+ context,
+ );
- match term {
- &QueryTerm::Clause(_, ref ct, _, call_policy) => {
- self.add_call(code, ct.to_instr(), call_policy);
- }
- _ => unreachable!(),
- };
+ code.extend(query);
+ self.add_call(code, clause.ct.to_instr(), clause.call_policy);
}
fn split_predicate(clauses: &[PredicateClause]) -> Vec<ClauseSpan> {
'outer: for (right, clause) in clauses.iter().enumerate() {
if let Some(args) = clause.args() {
- for (instantiated_arg_index, arg) in args.iter().enumerate() {
- match arg {
- Term::Var(..) | Term::AnonVar => {}
- _ => {
- if optimal_index != instantiated_arg_index {
- if left >= right {
- optimal_index = instantiated_arg_index;
- continue 'outer;
- }
-
- subseqs.push(ClauseSpan {
- left,
- right,
- instantiated_arg_index: optimal_index,
- });
+ for (instantiated_arg_index, arg) in args.iter().cloned().enumerate() {
+ let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg));
+ if !arg.is_var() {
+ if optimal_index != instantiated_arg_index {
+ if left >= right {
optimal_index = instantiated_arg_index;
- left = right;
+ continue 'outer;
}
- continue 'outer;
+ subseqs.push(ClauseSpan {
+ left,
+ right,
+ instantiated_arg_index: optimal_index,
+ });
+
+ optimal_index = instantiated_arg_index;
+ left = right;
}
+
+ continue 'outer;
}
}
}
let arg = clause.args().and_then(|args| args.get(optimal_index));
- if let Some(arg) = arg {
+ if let Some(arg) = arg.cloned() {
let index = code.len();
if clauses_len > 1 || self.settings.is_extensible {
- code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl);
+ let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg));
+ code_offsets.index_term(
+ clause.heap(),
+ arg,
+ index,
+ &mut clause_index_info,
+ self.atom_tbl,
+ );
}
}
use crate::allocator::*;
+use crate::atom_table::*;
use crate::codegen::SubsumedBranchHits;
use crate::forms::Level;
use crate::instructions::*;
use crate::machine::disjuncts::VarData;
+use crate::machine::heap::{heap_bound_deref, heap_bound_store};
use crate::parser::ast::*;
use crate::targets::*;
+use crate::types::*;
use crate::variable_records::*;
use bit_set::*;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
-use std::cell::Cell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
in_use: BitSet<usize>, // deep and non-var allocations
temp_free_list: Vec<usize>,
perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num
+ non_var_registers: IndexMap<usize, usize, FxBuildHasher>,
+ non_var_register_heap_locs: IndexMap<usize, usize, FxBuildHasher>,
}
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,
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,
&mut self,
chunk_num: usize,
code: &mut CodeDeque,
- ) {
+ ) -> Option<RegType> {
if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) {
let k = self.arg_c;
.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>>(
}
self.temp_lb = final_index + 1;
+
final_index
}
p
};
- self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done());
+ self.var_data.records[var_num].allocation = VarAlloc::Perm {
+ reg: p,
+ allocation: PermVarAllocation::done(),
+ };
+
p
}
}
#[inline(always)]
- pub fn get_binding(&self, var_num: usize) -> RegType {
+ pub fn get_var_binding(&self, var_num: usize) -> RegType {
self.var_data.records[var_num].allocation.as_reg_type()
}
+ #[inline(always)]
+ pub fn get_non_var_binding(&self, heap_loc: usize) -> RegType {
+ RegType::Temp(self.non_var_registers.get(&heap_loc).cloned().unwrap_or(0))
+ }
+
pub fn num_perm_vars(&self) -> usize {
self.perm_lb - 1
}
}
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));
}
}
self.perm_free_list.pop_front();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => {
- return Some(std::mem::replace(p, 0));
- }
+ VarAlloc::Perm { reg: p, allocation: PermVarAllocation::Pending }
+ if *p > 0 => {
+ return Some(std::mem::replace(p, 0));
+ }
_ => {}
}
} else {
}
pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) {
- if let VarAlloc::Perm(_, allocation) = &mut self.var_data.records[var_num].allocation {
- *allocation = PermVarAllocation::Pending;
- self.add_perm_to_free_list(chunk_num, var_num);
+ match &mut self.var_data.records[var_num].allocation {
+ VarAlloc::Perm { allocation, .. } => {
+ *allocation = PermVarAllocation::Pending;
+ self.add_perm_to_free_list(chunk_num, var_num);
+ }
+ _ => {}
}
}
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm(
- _,
- PermVarAllocation::Done {
+ VarAlloc::Perm {
+ allocation: PermVarAllocation::Done {
deep_safety,
shallow_safety,
..
},
- ) => {
+ ..
+ } => {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
}
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm(
- _,
- PermVarAllocation::Done {
+ VarAlloc::Perm {
+ allocation: PermVarAllocation::Done {
deep_safety,
shallow_safety,
..
},
- ) => {
+ ..
+ } => {
// GetVariable in head chunk is considered safe.
if lvl == Level::Deep {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm(
- _,
- PermVarAllocation::Done {
+ VarAlloc::Perm {
+ allocation: PermVarAllocation::Done {
ref mut shallow_safety,
..
},
- ) => {
+ ..
+ } => {
if !self.in_tail_position
|| self
.branch_stack
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm(
- _,
- PermVarAllocation::Done {
+ VarAlloc::Perm {
+ allocation: PermVarAllocation::Done {
ref mut deep_safety,
..
},
- ) => {
+ ..
+ } => {
if self
.branch_stack
.safety_unneeded_in_branch(deep_safety, &branch_designator)
temp_free_list: vec![],
perm_free_list: VecDeque::new(),
branch_stack: BranchStack { stack: vec![] },
+ non_var_registers: IndexMap::with_hasher(FxBuildHasher::default()),
+ non_var_register_heap_locs: IndexMap::with_hasher(FxBuildHasher::default()),
}
}
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
- term_loc: GenContext,
+ context: GenContext,
code: &mut CodeDeque,
) {
let r = RegType::Temp(self.alloc_reg_to_non_var());
Level::Root | Level::Shallow => {
let k = self.arg_c;
- if let GenContext::Last(chunk_num) = term_loc {
+ if let GenContext::Last(chunk_num) = context {
self.evacuate_arg::<Target>(chunk_num, code);
}
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
- term_loc: GenContext,
- cell: &'a Cell<RegType>,
+ heap_loc: usize,
+ context: GenContext,
code: &mut CodeDeque,
- ) {
- let r = cell.get();
+ ) -> RegType {
+ let r = self.get_non_var_binding(heap_loc);
let r = match lvl {
Level::Shallow => {
let k = self.arg_c;
- if let GenContext::Last(chunk_num) = term_loc {
- self.evacuate_arg::<Target>(chunk_num, code);
+ if let GenContext::Last(chunk_num) = context {
+ if let Some(new_r) = self.evacuate_arg::<Target>(chunk_num, code) {
+ self.non_var_register_heap_locs
+ .swap_remove(&k)
+ .map(|old_heap_loc| {
+ self.non_var_registers.insert(old_heap_loc, new_r.reg_num());
+ self.non_var_register_heap_locs
+ .insert(new_r.reg_num(), old_heap_loc);
+ });
+
+ self.non_var_registers.insert(heap_loc, k);
+ self.non_var_register_heap_locs.insert(k, heap_loc);
+ }
}
self.arg_c += 1;
RegType::Temp(k)
}
- _ if r.reg_num() == 0 => RegType::Temp(self.alloc_reg_to_non_var()),
+ _ if r.reg_num() == 0 => {
+ let r = RegType::Temp(self.alloc_reg_to_non_var());
+ self.non_var_registers.insert(heap_loc, r.reg_num());
+ self.non_var_register_heap_locs
+ .insert(r.reg_num(), heap_loc);
+ r
+ }
_ => {
self.in_use.insert(r.reg_num());
r
}
};
- cell.set(r);
+ r
}
fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
- cell: &Cell<VarReg>,
- term_loc: GenContext,
+ context: GenContext,
code: &mut CodeDeque,
- ) {
- let (r, is_new_var) = match self.get_binding(var_num) {
+ ) -> RegType {
+ let (r, is_new_var) = match self.get_var_binding(var_num) {
RegType::Temp(0) => {
- let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
- cell.set(VarReg::Norm(RegType::Temp(o)));
+ let o = self.alloc_reg_to_var::<Target>(var_num, lvl, context, code);
(RegType::Temp(o), true)
}
RegType::Perm(0) => {
- let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
- cell.set(VarReg::Norm(RegType::Perm(p)));
+ let p = self.alloc_perm_var(var_num, context.chunk_num());
(RegType::Perm(p), true)
}
r @ RegType::Perm(_) => {
let is_new_var = match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm(_, allocation) => {
+ VarAlloc::Perm { allocation, .. } => {
if allocation.pending() {
*allocation = PermVarAllocation::done();
true
r => (r, false),
};
- self.mark_reserved_var::<Target>(var_num, lvl, cell, term_loc, code, r, is_new_var);
+ self.mark_reserved_var::<Target>(var_num, lvl, context, code, r, is_new_var)
}
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
- cell: &Cell<VarReg>,
- term_loc: GenContext,
+ context: GenContext,
code: &mut CodeDeque,
r: RegType,
is_new_var: bool,
- ) {
+ ) -> RegType {
match lvl {
Level::Root | Level::Shallow => {
let k = self.arg_c;
if self.is_curr_arg_distinct_from(var_num) {
- self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
+ self.evacuate_arg::<Target>(context.chunk_num(), code);
}
- cell.set(VarReg::ArgAndNorm(r, k));
-
- if !self.in_place(var_num, term_loc, r, k) {
+ if !self.in_place(var_num, context, r, k) {
if is_new_var {
- self.mark_safe_var(var_num, lvl, term_loc);
+ self.mark_safe_var(var_num, lvl, context);
code.push_back(Target::argument_to_variable(r, k));
} else {
code.push_back(self.argument_to_value::<Target>(var_num, r, k));
self.arg_c += 1;
}
Level::Deep if is_new_var => {
- if let GenContext::Head = term_loc {
+ if let GenContext::Head = context {
if self.occurs_shallowly_in_head(var_num, r.reg_num()) {
code.push_back(self.subterm_to_value::<Target>(var_num, r));
} else {
- self.mark_safe_var(var_num, lvl, term_loc);
+ self.mark_safe_var(var_num, lvl, context);
code.push_back(Target::subterm_to_variable(r));
}
} else {
- self.mark_safe_var(var_num, lvl, term_loc);
+ self.mark_safe_var(var_num, lvl, context);
code.push_back(Target::subterm_to_variable(r));
}
}
if record.running_count < record.num_occurrences {
record.running_count += 1;
} else {
- self.free_var(term_loc.chunk_num(), var_num);
+ self.free_var(context.chunk_num(), var_num);
}
self.in_use.insert(o);
+ r
}
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
- match self.get_binding(var_num) {
+ match self.get_var_binding(var_num) {
RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)),
RegType::Temp(0) => {
let t = self.alloc_reg_to_non_var();
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();
}
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();
}
self.arg_c += 1;
}
- fn reset_at_head(&mut self, args: &[Term]) {
- self.reset_arg(args.len());
- self.arity = args.len();
+ fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize) {
+ read_heap_cell!(term.deref_loc(head_loc),
+ (HeapCellValueTag::Str, s) => {
+ let arity = cell_as_atom_cell!(term.heap[s]).get_arity();
- for (idx, arg) in args.iter().enumerate() {
- if let Term::Var(_, ref var) = arg {
- let var_num = var.to_var_num().unwrap();
- let r = self.get_binding(var_num);
+ self.reset_arg(arity);
+ self.arity = arity;
- if !r.is_perm() && r.reg_num() == 0 {
- self.in_use.insert(idx + 1);
- self.shallow_temp_mappings.insert(idx + 1, var_num);
- self.var_data.records[var_num]
- .allocation
- .set_register(idx + 1);
+ for (idx, arg) in term.heap[s+1 .. s+arity+1].iter().cloned().enumerate() {
+ if arg.is_var() {
+ let var = heap_bound_store(
+ &term.heap,
+ heap_bound_deref(&term.heap, arg),
+ );
+
+ if !var.is_var() {
+ continue;
+ }
+
+ let h = var.get_value() as usize;
+ let var_ptr = term.var_locs.peek_next_var_ptr_at_key(h).unwrap();
+ let var_num = var_ptr.to_var_num().unwrap();
+ let r = self.get_var_binding(var_num);
+
+ if !r.is_perm() && r.reg_num() == 0 {
+ self.in_use.insert(idx + 1);
+ self.shallow_temp_mappings.insert(idx + 1, var_num);
+ self.var_data.records[var_num]
+ .allocation
+ .set_register(idx + 1);
+ }
+ }
}
}
- }
+ _ => {
+ self.reset_arg(0);
+ }
+ );
}
fn reset_arg(&mut self, arity: usize) {
use indexmap::{IndexMap, IndexSet};
use ordered_float::OrderedFloat;
-use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fmt;
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,
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 {
}
}
+#[derive(Debug)]
+pub struct QueryClause {
+ pub ct: ClauseType,
+ pub arity: usize,
+ pub term: HeapCellValue,
+ pub code_indices: IndexMap<usize, CodeIndex, FxBuildHasher>,
+ pub call_policy: CallPolicy,
+}
+
+impl QueryClause {
+ pub fn term_loc(&self) -> usize {
+ self.term.get_value() as usize
+ }
+}
+
#[derive(Debug)]
pub enum QueryTerm {
- // register, clause type, subterms, clause call policy.
- Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
+ Clause(QueryClause),
Fail,
- LocalCut { var_num: usize, cut_prev: bool }, // var_num
- GlobalCut(usize), // var_num
+ Succeed,
+ LocalCut { var_num: usize, cut_prev: bool },
+ GlobalCut(usize), // var_num
GetCutPoint { var_num: usize, prev_b: bool },
GetLevel(usize), // var_num
}
-impl QueryTerm {
- pub(crate) fn arity(&self) -> usize {
- match self {
- QueryTerm::Clause(_, _, subterms, ..) => subterms.len(),
- &QueryTerm::GetLevel(_) | &QueryTerm::GetCutPoint { .. } => 1,
- _ => 0,
- }
- }
-}
-
#[derive(Debug)]
pub struct Fact {
- pub(crate) head: Term,
+ pub(crate) term: FocusedHeap,
}
#[derive(Debug)]
pub struct Rule {
- pub(crate) head: (Atom, Vec<Term>),
+ pub(crate) term: FocusedHeap,
pub(crate) clauses: ChunkedTermVec,
}
}
}
+fn clause_name(heap: &[HeapCellValue], term_loc: usize) -> Option<Atom> {
+ let name = term_name(heap, term_loc);
+
+ if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) {
+ term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| term_name(heap, arg_loc))
+ } else {
+ name
+ }
+}
+
+fn clause_arity(heap: &[HeapCellValue], term_loc: usize) -> usize {
+ let name = term_name(heap, term_loc);
+
+ if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) {
+ term_nth_arg(heap, term_loc, 1)
+ .map(|arg_loc| term_arity(heap, arg_loc))
+ .unwrap_or(0)
+ } else {
+ term_arity(heap, term_loc)
+ }
+}
+
+impl ClauseInfo for FocusedHeap {
+ #[inline]
+ fn name(&self) -> Option<Atom> {
+ clause_name(&self.heap, self.focus)
+ }
+
+ #[inline]
+ fn arity(&self) -> usize {
+ clause_arity(&self.heap, self.focus)
+ }
+}
+
+impl<'a> ClauseInfo for FocusedHeapRefMut<'a> {
+ #[inline]
+ fn name(&self) -> Option<Atom> {
+ clause_name(self.heap, self.focus)
+ }
+
+ #[inline]
+ fn arity(&self) -> usize {
+ clause_arity(self.heap, self.focus)
+ }
+}
+
+/*
impl ClauseInfo for Term {
fn name(&self) -> Option<Atom> {
match self {
}
}
}
+*/
impl ClauseInfo for Rule {
fn name(&self) -> Option<Atom> {
- Some(self.head.0)
+ self.term.name(self.term.focus)
}
fn arity(&self) -> usize {
- self.head.1.len()
+ self.term.arity(self.term.focus)
}
}
impl ClauseInfo for PredicateClause {
fn name(&self) -> Option<Atom> {
match self {
- PredicateClause::Fact(ref term, ..) => term.head.name(),
- PredicateClause::Rule(ref rule, ..) => rule.name(),
+ PredicateClause::Fact(ref fact, ..) => fact.term.name(fact.term.focus),
+ PredicateClause::Rule(ref rule, ..) => rule.term.name(rule.term.focus),
}
}
fn arity(&self) -> usize {
match self {
- PredicateClause::Fact(ref term, ..) => term.head.arity(),
- PredicateClause::Rule(ref rule, ..) => rule.arity(),
+ PredicateClause::Fact(ref fact, ..) => fact.term.arity(fact.term.focus),
+ PredicateClause::Rule(ref rule, ..) => rule.term.arity(rule.term.focus),
}
}
}
}
impl PredicateClause {
- pub(crate) fn args(&self) -> Option<&[Term]> {
- match self {
- PredicateClause::Fact(term, ..) => match &term.head {
- Term::Clause(_, _, args) => Some(args),
- _ => None,
- },
- PredicateClause::Rule(rule, ..) => {
- if rule.head.1.is_empty() {
- None
- } else {
- Some(&rule.head.1)
- }
+ pub(crate) fn args(&self) -> Option<&[HeapCellValue]> {
+ let (term, focus) = match self {
+ PredicateClause::Fact(Fact { term }, _) => (term, term.focus),
+ PredicateClause::Rule(Rule { term, .. }, _) => {
+ let focus = term.nth_arg(term.focus, 1).unwrap();
+ (term, focus)
+ }
+ };
+
+ let arity = term.arity(focus);
+
+ read_heap_cell!(term.deref_loc(focus),
+ (HeapCellValueTag::Str, s) => {
+ Some(&term.heap[s+1 .. s+arity+1])
+ }
+ _ => {
+ None
}
+ )
+ }
+
+ pub(crate) fn heap(&self) -> &[HeapCellValue] {
+ match self {
+ PredicateClause::Fact(ref fact, ..) => &fact.term.heap,
+ PredicateClause::Rule(ref rule, ..) => &rule.term.heap,
}
}
}
start_value: HeapCellValue,
iter_stack: Vec<HeapCellValue>,
mark_phase: bool,
- heap: &'a mut Heap,
+ pub heap: &'a mut Heap,
}
impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> {
#[derive(Debug)]
pub struct StackfulPreOrderHeapIter<'a, ElideLists> {
- pub heap: &'a mut Vec<HeapCellValue>,
+ pub heap: &'a mut [HeapCellValue],
pub machine_stack: &'a mut Stack,
stack: Vec<IterStackLoc>,
h: IterStackLoc,
cell.set_mark_bit(false);
}
- self.heap.pop();
+ // self.heap.pop();
}
}
-pub trait FocusedHeapIter: Iterator<Item = HeapCellValue> {
+pub trait FocusedHeapIter:
+ Deref<Target = [HeapCellValue]> + Iterator<Item = HeapCellValue>
+{
fn focus(&self) -> IterStackLoc;
}
}
}
+impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> {
+ type Target = [HeapCellValue];
+
+ fn deref(&self) -> &Self::Target {
+ &self.heap
+ }
+}
+
impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
#[inline]
pub fn read_cell_mut(&mut self, loc: IterStackLoc) -> &mut HeapCellValue {
impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> {
#[inline]
- fn new(heap: &'a mut Vec<HeapCellValue>, stack: &'a mut Stack, cell: HeapCellValue) -> Self {
- let h = IterStackLoc::iterable_loc(heap.len(), HeapOrStackTag::Heap);
- heap.push(cell);
+ fn new(heap: &'a mut [HeapCellValue], stack: &'a mut Stack, root_loc: usize) -> Self {
+ let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap);
+ // heap.push(cell);
Self {
heap,
}
}
+
impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a, ElideLists> {
type Item = HeapCellValue;
pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>(
heap: &'a mut Vec<HeapCellValue>,
stack: &'a mut Stack,
- cell: HeapCellValue,
+ root_loc: usize,
) -> StackfulPreOrderHeapIter<'a, ElideLists> {
- StackfulPreOrderHeapIter::new(heap, stack, cell)
+ StackfulPreOrderHeapIter::new(heap, stack, root_loc)
}
#[derive(Debug)]
}
impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> {
- type Target = Iter;
+ type Target = [HeapCellValue];
fn deref(&self) -> &Self::Target {
&self.base_iter
}
}
+/*
impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
/* return true if the term at heap offset idx_loc is a
* direct/inlined subterm of a structure at the focus of
false
}
}
+*/
pub(crate) type LeftistPostOrderHeapIter<'a, ElideLists> =
PostOrderIterator<StackfulPreOrderHeapIter<'a, ElideLists>>;
pub(crate) fn stackful_post_order_iter<'a, ElideLists: ListElisionPolicy>(
heap: &'a mut Heap,
stack: &'a mut Stack,
- cell: HeapCellValue,
+ root_loc: usize,
) -> LeftistPostOrderHeapIter<'a, ElideLists> {
- PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, stack, cell))
+ PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, stack, root_loc))
}
#[cfg(test)]
.heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+ wam.machine_st.heap.push(str_loc_as_cell!(0));
+
{
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- str_loc_as_cell!(0),
+ 3,
);
assert_eq!(
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- str_loc_as_cell!(0),
+ 4,
);
assert_eq!(
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
let mut var = heap_loc_as_cell!(0);
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 1,
);
assert_eq!(
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
assert_eq!(
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
// the cycle will be iterated twice before being detected.
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
- heap_loc_as_cell!(0)
+ list_loc_as_cell!(1)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ atom_as_cell!(a_atom)
+ );
+ assert_eq!(
+ unmark_cell_bits!(iter.next().unwrap()),
+ list_loc_as_cell!(3)
);
assert_eq!(iter.next(), None);
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
// cut the iteration short to check that all cells are
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
let mut iter = stackful_preorder_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
.heap
.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
+ let h = wam.machine_st.heap.len();
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
{
let mut iter = stackful_preorder_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- pstr_loc_as_cell!(0),
+ h,
);
let pstr_offset_cell = pstr_offset_as_cell!(0);
}
*/
+ wam.machine_st.heap.pop();
wam.machine_st.heap.pop();
wam.machine_st
.heap
.push(fixnum_as_cell!(Fixnum::build_with(1i64)));
+ let h = wam.machine_st.heap.len();
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
{
let mut iter = stackful_preorder_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- pstr_loc_as_cell!(0),
+ h,
);
let pstr_offset_cell = pstr_offset_as_cell!(0);
wam.machine_st.heap.extend(functor);
+ let h = wam.machine_st.heap.len();
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
{
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ h,
);
assert_eq!(
let mut iter = stackful_preorder_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ h,
);
assert_eq!(
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
let mut cyclic_link = list_loc_as_cell!(1);
wam.machine_st.heap.push(pstr_as_cell!(atom!("a string")));
wam.machine_st.heap.push(empty_list_as_cell!());
+ wam.machine_st.heap.push(pstr_loc_as_cell!(0));
{
let mut iter = stackful_preorder_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 2,
);
assert_eq!(
wam.machine_st.heap.push(str_loc_as_cell!(4));
wam.machine_st.heap.push(empty_list_as_cell!());
+ let h = wam.machine_st.heap.len();
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
{
let mut iter = stackful_preorder_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ h,
);
assert_eq!(
let a_atom = atom!("a");
let b_atom = atom!("b");
+ wam.machine_st.heap.push(str_loc_as_cell!(1));
+
wam.machine_st
.heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- str_loc_as_cell!(0),
+ 0,
);
assert_eq!(
wam.machine_st.heap.clear();
+ wam.machine_st.heap.push(str_loc_as_cell!(1));
wam.machine_st.heap.extend(functor!(
f_atom,
[
atom(a_atom),
atom(b_atom),
atom(a_atom),
- cell(str_loc_as_cell!(0))
+ cell(str_loc_as_cell!(1))
]
));
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- str_loc_as_cell!(0),
+ 0,
);
assert_eq!(
atom_as_cell!(a_atom)
);
- assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0));
+ assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1));
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
let mut var = heap_loc_as_cell!(0);
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 1,
);
assert_eq!(
wam.machine_st.heap.push(atom_as_cell!(b_atom));
wam.machine_st.heap.push(empty_list_as_cell!());
+ let h = wam.machine_st.heap.len();
+ wam.machine_st.heap.push(heap_loc_as_cell!(0));
+
{
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ h,
);
assert_eq!(
assert_eq!(iter.next(), None);
}
+ wam.machine_st.heap.pop();
wam.machine_st.heap.pop();
// now make the list cyclic.
+ let h = wam.machine_st.heap.len();
wam.machine_st.heap.push(heap_loc_as_cell!(0));
{
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ h,
);
// the cycle will be iterated twice before being detected.
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
// cut the iteration short to check that all cells are
put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
+ wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+
+ let h = wam.machine_st.heap.len() - 1;
+
{
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- pstr_loc_as_cell!(0),
+ h,
);
assert_eq!(
assert_eq!(iter.next(), None);
}
+ wam.machine_st.heap.pop();
wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(2));
put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl);
let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
+ wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+
+ let h = wam.machine_st.heap.len() - 1;
+
{
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- pstr_loc_as_cell!(0),
+ h,
);
assert_eq!(
assert_eq!(iter.next(), None);
}
+ wam.machine_st.heap.pop();
wam.machine_st.heap.pop();
wam.machine_st
.heap
.heap
.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
+ wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+
+ let h = wam.machine_st.heap.len() - 1;
+
{
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- pstr_loc_as_cell!(0),
+ h,
);
assert_eq!(
assert_eq!(iter.next(), None);
}
+ wam.machine_st.heap.pop();
wam.machine_st.heap.pop();
wam.machine_st
.heap
.push(fixnum_as_cell!(Fixnum::build_with(1i64)));
+ wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+
+ let h = wam.machine_st.heap.len() - 1;
+
{
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- pstr_loc_as_cell!(0),
+ h,
);
assert_eq!(
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
assert_eq!(
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- heap_loc_as_cell!(0),
+ 0,
);
assert_eq!(
stack: &'a mut Stack,
op_dir: &'a OpDir,
output: Outputter,
- cell: HeapCellValue,
+ root_loc: usize,
) -> Self {
HCPrinter {
outputter: output,
- iter: stackful_preorder_iter(heap, stack, cell),
+ iter: stackful_preorder_iter(heap, stack, root_loc),
atom_tbl,
op_dir,
state_stack: vec![],
.heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
+ wam.machine_st.heap.push(str_loc_as_cell!(0));
+
{
let printer = HCPrinter::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(0),
+ 0,
);
let output = printer.print();
]
));
+ let h = wam.machine_st.heap.len();
+ wam.machine_st.heap.push(str_loc_as_cell!(0));
+
{
let printer = HCPrinter::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(0),
+ h,
);
let output = printer.print();
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(0),
+ 0,
);
let output = printer.print();
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(0),
+ 0,
);
printer
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(0),
+ 0,
);
let output = printer.print();
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(0),
+ 0,
);
let output = printer.print();
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(0),
+ 0,
);
printer
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(0),
+ 0,
);
printer.max_depth = 5;
put_partial_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
+ wam.machine_st.heap.push(pstr_loc_as_cell!(0));
+
+ let h = wam.machine_st.heap.len() - 1;
+
{
let printer = HCPrinter::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- pstr_loc_as_cell!(0),
+ h,
);
let output = printer.print();
all_cells_unmarked(&wam.machine_st.heap);
+ wam.machine_st.heap.pop();
wam.machine_st.heap.pop();
wam.machine_st.heap.push(list_loc_as_cell!(2));
&mut wam.machine_st.stack,
&wam.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(0),
+ 0,
);
printer.double_quotes = true;
use crate::atom_table::*;
-use crate::parser::ast::*;
-
use crate::forms::*;
use crate::instructions::*;
+use crate::parser::ast::*;
+use crate::types::*;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
pub(crate) fn index_term(
&mut self,
- optimal_arg: &Term,
+ heap: &[HeapCellValue],
+ optimal_arg: HeapCellValue,
index: usize,
clause_index_info: &mut ClauseIndexInfo,
atom_tbl: &AtomTable,
) {
- match optimal_arg {
- &Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
- clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
- self.index_list(index);
+ read_heap_cell!(optimal_arg,
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
+
+ if (name, arity) == (atom!("."), 2) {
+ clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
+ self.index_list(index);
+ } else {
+ clause_index_info.opt_arg_index_key =
+ OptArgIndexKey::Structure(self.optimal_index, 0, name, arity);
+
+ self.index_structure(name, arity, index);
+ }
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+
+ let overlapping_constants = self.index_constant(atom_tbl, Literal::Atom(name), index);
+
+ clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
+ self.optimal_index,
+ 0,
+ Literal::Atom(name),
+ overlapping_constants,
+ );
}
- &Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
+ (HeapCellValueTag::Lis
+ | HeapCellValueTag::CStr
+ | HeapCellValueTag::PStrLoc) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
- &Term::Clause(_, name, ref terms) => {
- clause_index_info.opt_arg_index_key =
- OptArgIndexKey::Structure(self.optimal_index, 0, name, terms.len());
-
- self.index_structure(name, terms.len(), index);
- }
- &Term::Literal(_, constant) => {
- let overlapping_constants = self.index_constant(atom_tbl, constant, index);
-
- clause_index_info.opt_arg_index_key =
- OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
+ _ => {
+ match Literal::try_from(optimal_arg) {
+ Ok(lit) => {
+ let overlapping_constants = self.index_constant(atom_tbl, lit, index);
+
+ clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
+ self.optimal_index,
+ 0,
+ lit,
+ overlapping_constants,
+ );
+ }
+ _ => {}
+ }
}
- _ => {}
- }
+ );
}
pub(crate) fn no_indices(&mut self) -> bool {
-use crate::atom_table::*;
+use crate::atom_table::AtomCell;
use crate::forms::*;
-use crate::instructions::*;
-use crate::parser::ast::*;
+use crate::heap_iter::*;
+use crate::machine::heap::*;
+use crate::machine::stack::*;
+use crate::types::*;
+
+use bit_set::*;
+use fxhash::FxBuildHasher;
+use indexmap::IndexMap;
-use std::cell::Cell;
use std::collections::VecDeque;
use std::iter::*;
+use std::ops::Deref;
use std::vec::Vec;
-#[allow(clippy::borrowed_box)]
-#[derive(Debug, Clone)]
-pub(crate) enum TermRef<'a> {
- AnonVar(Level),
- Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
- Literal(Level, &'a Cell<RegType>, &'a Literal),
- Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
- PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
- CompleteString(Level, &'a Cell<RegType>, Atom),
- Var(Level, &'a Cell<VarReg>, VarPtr),
-}
-
-/*
-impl<'a> TermRef<'a> {
- pub(crate) fn level(&self) -> Level {
- match self {
- TermRef::AnonVar(lvl) |
- TermRef::Cons(lvl, ..) |
- TermRef::Literal(lvl, ..) |
- TermRef::Var(lvl, ..) |
- TermRef::Clause(lvl, ..) |
- TermRef::CompleteString(lvl, ..) |
- TermRef::PartialString(lvl, ..) => *lvl,
- }
- }
+pub(crate) trait TermIterator:
+ Deref<Target = [HeapCellValue]> + Iterator<Item = HeapCellValue>
+{
+ fn focus(&self) -> IterStackLoc;
+ fn level(&mut self) -> Level;
}
-*/
-#[allow(clippy::borrowed_box)]
#[derive(Debug)]
-pub(crate) enum TermIterState<'a> {
- AnonVar(Level),
- Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
- Literal(Level, &'a Cell<RegType>, &'a Literal),
- InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
- FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
- InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
- FinalPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
- CompleteString(Level, &'a Cell<RegType>, Atom),
- Var(Level, &'a Cell<VarReg>, VarPtr),
+pub(crate) struct TargetIterator<I: FocusedHeapIter, const SKIP_ROOT: bool> {
+ shallow_terms: IndexMap<usize, BitSet<usize>, FxBuildHasher>,
+ root_terms: BitSet<usize>,
+ iter: I,
+ arg_c: usize,
}
-impl<'a> TermIterState<'a> {
- pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
- match term {
- Term::AnonVar => TermIterState::AnonVar(lvl),
- Term::Clause(cell, name, subterms) => {
- TermIterState::Clause(lvl, 0, cell, *name, subterms)
- }
- Term::Cons(cell, head, tail) => {
- TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
+fn record_path(
+ heap: &[HeapCellValue],
+ root_terms: &mut BitSet<usize>,
+ mut root_loc: usize,
+) -> usize {
+ loop {
+ let cell = heap[root_loc];
+ root_terms.insert(root_loc);
+
+ read_heap_cell!(cell,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if h == root_loc {
+ break;
+ } else {
+ root_loc = h;
+ }
}
- Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
- Term::PartialString(cell, string_buf, tail) => {
- TermIterState::InitialPartialString(lvl, cell, string_buf, tail)
+ (HeapCellValueTag::Lis) => {
+ root_terms.insert(root_loc);
+ break;
+ }
+ _ => {
+ if cell.is_ref() {
+ root_terms.insert(cell.get_value() as usize);
+ }
+
+ break;
}
- Term::CompleteString(cell, atom) => TermIterState::CompleteString(lvl, cell, *atom),
- Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
- }
+ );
}
+
+ root_loc
}
-#[derive(Debug)]
-pub(crate) struct QueryIterator<'a> {
- state_stack: Vec<TermIterState<'a>>,
+fn find_root_terms(heap: &[HeapCellValue], root_loc: usize) -> (usize, BitSet<usize>) {
+ let mut root_terms = BitSet::<usize>::default();
+ let root_loc = record_path(heap, &mut root_terms, root_loc);
+ (root_loc, root_terms)
}
-impl<'a> QueryIterator<'a> {
- fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
- self.state_stack
- .push(TermIterState::subterm_to_state(lvl, term));
- }
+fn find_shallow_terms(
+ heap: &[HeapCellValue],
+ root_loc: usize,
+) -> IndexMap<usize, BitSet<usize>, FxBuildHasher> {
+ let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default());
- /*
- fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
- let state_stack = terms
- .iter()
- .rev()
- .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
- .collect();
+ let (h, arity) = read_heap_cell!(heap[root_loc],
+ (HeapCellValueTag::Str, s) => {
+ (s+1, cell_as_atom_cell!(heap[s]).get_arity())
+ }
+ (HeapCellValueTag::Lis, l) => {
+ (l, 2)
+ }
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ (root_loc + 1, arity)
+ }
+ _ => {
+ (root_loc, 0)
+ }
+ );
- QueryIterator { state_stack }
+ for idx in 0..arity {
+ let mut shallow_terms = BitSet::default();
+ record_path(heap, &mut shallow_terms, h + idx);
+ shallow_terms_map.insert(idx + 1, shallow_terms);
}
- */
-
- fn from_term(term: &'a Term) -> Self {
- let state = match term {
- Term::AnonVar
- | Term::Cons(..)
- | Term::Literal(..)
- | Term::PartialString(..)
- | Term::CompleteString(..) => {
- return QueryIterator {
- state_stack: vec![],
- }
- }
- Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms),
- Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
- };
- QueryIterator {
- state_stack: vec![state],
+ shallow_terms_map
+}
+
+impl<I: FocusedHeapIter, const SKIP_ROOT: bool> TargetIterator<I, SKIP_ROOT> {
+ fn new(iter: I, root_loc: usize, arg_c: usize) -> Self {
+ let (derefed_root_loc, root_terms) = find_root_terms(&iter, root_loc);
+ let shallow_terms = find_shallow_terms(&iter, derefed_root_loc);
+
+ Self {
+ shallow_terms,
+ root_terms,
+ iter,
+ arg_c,
}
}
- fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) {
- match term {
- QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
- self.state_stack
- .push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms));
- }
- QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
- self.state_stack
- .push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
+ fn current_level(&self, arg_c_inc: usize) -> Level {
+ let current_focus = self.iter.focus().value() as usize;
+
+ if self.root_terms.contains(current_focus) {
+ return Level::Root;
+ }
+
+ if let Some(shallow_terms) = self.shallow_terms.get(&(self.arg_c + arg_c_inc)) {
+ if shallow_terms.contains(current_focus) {
+ return Level::Shallow;
}
- _ => {}
}
- }
- pub fn new(term: &'a QueryTerm) -> Self {
- let mut iter = QueryIterator {
- state_stack: vec![],
- };
- iter.extend_state(Level::Root, term);
- iter
+ Level::Deep
}
}
-impl<'a> Iterator for QueryIterator<'a> {
- type Item = TermRef<'a>;
+impl<'a, const SKIP_ROOT: bool> TermIterator for FactIterator<'a, SKIP_ROOT> {
+ fn focus(&self) -> IterStackLoc {
+ self.iter.focus()
+ }
- fn next(&mut self) -> Option<Self::Item> {
- while let Some(iter_state) = self.state_stack.pop() {
- match iter_state {
- TermIterState::AnonVar(lvl) => {
- return Some(TermRef::AnonVar(lvl));
- }
- TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
- if child_num == child_terms.len() {
- match name {
- atom!("$call") if lvl == Level::Root => {
- self.push_subterm(Level::Shallow, &child_terms[0]);
- }
- _ => {
- return match lvl {
- Level::Root => None,
- lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
- }
- }
- };
- } else {
- self.state_stack.push(TermIterState::Clause(
- lvl,
- child_num + 1,
- cell,
- name,
- child_terms,
- ));
-
- self.push_subterm(lvl.child_level(), &child_terms[child_num]);
- }
- }
- TermIterState::InitialCons(lvl, cell, head, tail) => {
- self.state_stack
- .push(TermIterState::FinalCons(lvl, cell, head, tail));
+ fn level(&mut self) -> Level {
+ let lvl = self.current_level(1);
- self.push_subterm(lvl.child_level(), tail);
- self.push_subterm(lvl.child_level(), head);
- }
- TermIterState::InitialPartialString(lvl, cell, string, tail) => {
- self.state_stack
- .push(TermIterState::FinalPartialString(lvl, cell, string, tail));
- self.push_subterm(lvl.child_level(), tail);
- }
- TermIterState::FinalPartialString(lvl, cell, atom, tail) => {
- return Some(TermRef::PartialString(lvl, cell, atom, tail));
- }
- TermIterState::CompleteString(lvl, cell, atom) => {
- return Some(TermRef::CompleteString(lvl, cell, atom));
- }
- TermIterState::FinalCons(lvl, cell, head, tail) => {
- return Some(TermRef::Cons(lvl, cell, head, tail));
- }
- TermIterState::Literal(lvl, cell, constant) => {
- return Some(TermRef::Literal(lvl, cell, constant));
- }
- TermIterState::Var(lvl, cell, var_ptr) => {
- return Some(TermRef::Var(lvl, cell, var_ptr));
- }
- };
+ if let Level::Shallow = lvl {
+ self.arg_c += 1;
}
- None
+ lvl
}
}
-#[derive(Debug)]
-pub(crate) struct FactIterator<'a> {
- state_queue: VecDeque<TermIterState<'a>>,
- iterable_root: RootIterationPolicy,
-}
-
-impl<'a> FactIterator<'a> {
- fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
- self.state_queue
- .push_back(TermIterState::subterm_to_state(lvl, term));
+impl<'a, const SKIP_ROOT: bool> TermIterator for QueryIterator<'a, SKIP_ROOT> {
+ fn focus(&self) -> IterStackLoc {
+ self.iter.focus()
}
- pub(crate) fn from_rule_head_clause(terms: &'a [Term]) -> Self {
- let state_queue = terms
- .iter()
- .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
- .collect();
+ fn level(&mut self) -> Level {
+ let lvl = self.current_level(0);
- FactIterator {
- state_queue,
- iterable_root: RootIterationPolicy::NotIterated,
+ if let Level::Shallow = lvl {
+ self.arg_c += 1;
}
- }
- fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self {
- let states = match term {
- Term::AnonVar => {
- vec![TermIterState::AnonVar(Level::Root)]
- }
- Term::Clause(cell, name, terms) => {
- vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
- }
- Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
- Level::Root,
- cell,
- head.as_ref(),
- tail.as_ref(),
- )],
- Term::PartialString(cell, string_buf, tail) => {
- vec![TermIterState::InitialPartialString(
- Level::Root,
- cell,
- string_buf,
- tail,
- )]
- }
- Term::CompleteString(cell, atom) => {
- vec![TermIterState::CompleteString(Level::Root, cell, *atom)]
- }
- Term::Literal(cell, constant) => {
- vec![TermIterState::Literal(Level::Root, cell, constant)]
- }
- Term::Var(cell, var_ptr) => {
- vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())]
- }
- };
-
- FactIterator {
- state_queue: VecDeque::from(states),
- iterable_root,
- }
+ lvl
}
}
-impl<'a> Iterator for FactIterator<'a> {
- type Item = TermRef<'a>;
+impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Iterator for TargetIterator<I, SKIP_ROOT> {
+ type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> {
- while let Some(state) = self.state_queue.pop_front() {
- match state {
- TermIterState::AnonVar(lvl) => {
- return Some(TermRef::AnonVar(lvl));
- }
- TermIterState::Clause(lvl, _, cell, name, child_terms) => {
- for child_term in child_terms {
- self.push_subterm(lvl.child_level(), child_term);
- }
+ loop {
+ let next_term = self.iter.next();
- match lvl {
- Level::Root if !self.iterable_root.iterable() => continue,
- _ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
- };
- }
- TermIterState::InitialCons(lvl, cell, head, tail) => {
- self.push_subterm(Level::Deep, head);
- self.push_subterm(Level::Deep, tail);
+ if next_term.is_none() {
+ return None;
+ }
- return Some(TermRef::Cons(lvl, cell, head, tail));
- }
- TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => {
- self.push_subterm(Level::Deep, tail);
- return Some(TermRef::PartialString(lvl, cell, string_buf, tail));
- }
- TermIterState::CompleteString(lvl, cell, atom) => {
- return Some(TermRef::CompleteString(lvl, cell, atom));
- }
- TermIterState::Literal(lvl, cell, constant) => {
- return Some(TermRef::Literal(lvl, cell, constant))
- }
- TermIterState::Var(lvl, cell, var_ptr) => {
- return Some(TermRef::Var(lvl, cell, var_ptr));
- }
- _ => {}
+ let focus = self.iter.focus().value() as usize;
+
+ if SKIP_ROOT && self.root_terms.contains(focus) {
+ continue;
+ } else {
+ return next_term;
}
}
+ }
+}
- None
+impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Deref for TargetIterator<I, SKIP_ROOT> {
+ type Target = [HeapCellValue];
+
+ fn deref(&self) -> &Self::Target {
+ self.iter.deref()
}
}
-pub(crate) fn post_order_iter(term: &'_ Term) -> QueryIterator {
- QueryIterator::from_term(term)
+impl<I: FocusedHeapIter, const SKIP_ROOT: bool> FocusedHeapIter for TargetIterator<I, SKIP_ROOT> {
+ fn focus(&self) -> IterStackLoc {
+ self.iter.focus()
+ }
}
-pub(crate) fn breadth_first_iter(
- term: &'_ Term,
- iterable_root: RootIterationPolicy,
-) -> FactIterator {
- FactIterator::new(term, iterable_root)
+pub(crate) type FactIterator<'a, const SKIP_ROOT: bool> =
+ TargetIterator<StackfulPreOrderHeapIter<'a, NonListElider>, SKIP_ROOT>;
+
+pub(crate) fn fact_iterator<'a, const SKIP_ROOT: bool>(
+ heap: &'a mut Heap,
+ stack: &'a mut Stack,
+ root_loc: usize,
+) -> FactIterator<'a, SKIP_ROOT> {
+ // let cell = heap[root_loc];
+ TargetIterator::new(stackful_preorder_iter(heap, stack, root_loc), root_loc, 0)
+}
+
+pub(crate) type QueryIterator<'a, const SKIP_ROOT: bool> =
+ TargetIterator<PostOrderIterator<StackfulPreOrderHeapIter<'a, NonListElider>>, SKIP_ROOT>;
+
+pub(crate) fn query_iterator<'a, const SKIP_ROOT: bool>(
+ heap: &'a mut Heap,
+ stack: &'a mut Stack,
+ root_loc: usize,
+) -> QueryIterator<'a, SKIP_ROOT> {
+ // let cell = heap[root_loc];
+ TargetIterator::new(stackful_post_order_iter(heap, stack, root_loc), root_loc, 1)
}
#[derive(Debug, Copy, Clone)]
!,
'$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),
% The clause will be inserted at the beginning of the module.
asserta(Clause0) :-
loader:strip_subst_module(Clause0, user, Module, Clause),
- asserta_(Module, Clause).
-
-asserta_(Module, (Head :- Body)) :-
- !,
- '$asserta'(Module, Head, Body).
-asserta_(Module, Fact) :-
- '$asserta'(Module, Fact, true).
+ '$asserta'(Module, Clause).
:- meta_predicate assertz(:).
% The clase will be inserted at the end of the module.
assertz(Clause0) :-
loader:strip_subst_module(Clause0, user, Module, Clause),
- assertz_(Module, Clause).
-
-assertz_(Module, (Head :- Body)) :-
- !,
- '$assertz'(Module, Head, Body).
-assertz_(Module, Fact) :-
- '$assertz'(Module, Fact, true).
+ '$assertz'(Module, Clause).
:- meta_predicate retract(:).
when_condition_si((A ; B)) :-
when_condition_si(A),
when_condition_si(B).
-
read_term(Stream, Term, [singletons(Singletons)])
; Term = end_of_file
),
+ % write('Term: '), writeq(Term), nl,
( Term == end_of_file ->
close(Stream),
'$conclude_load'(Evacuable)
compile_term(Term, Evacuable) :-
expand_terms_and_goals(Term, Terms),
+ % write('Terms: '), writeq(Terms),nl,
!,
( var(Terms) ->
instantiation_error(load/1)
value: HeapCellValue,
) -> Result<Number, MachineStub> {
let stub_gen = || functor_stub(atom!("is"), 2);
- let mut iter =
- stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, value);
+
+ let root_loc = if value.is_ref() {
+ value.get_value() as usize
+ } else {
+ let type_error = self.type_error(ValidType::Evaluable, value);
+ return Err(self.error_form(type_error, stub_gen()));
+ };
+
+ let mut iter = stackful_post_order_iter::<NonListElider>(
+ &mut self.heap, &mut self.stack, root_loc,
+ );
while let Some(value) = iter.next() {
if value.get_forwarding_bit() {
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
#[derive(Debug)]
-pub(super) struct AttrVarInitializer {
- pub(super) attr_var_queue: Vec<usize>,
+pub(crate) struct AttrVarInitializer {
+ pub(crate) attr_var_queue: Vec<usize>,
pub(super) bindings: Bindings,
pub(super) p: usize,
pub(super) cp: usize,
pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
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::<NonListElider>(&mut self.heap, &mut self.stack, cell);
+ let mut iter = stackful_preorder_iter::<NonListElider>(
+ &mut self.heap, &mut self.stack, root_loc, // cell,
+ );
while let Some(value) = iter.next() {
read_heap_cell!(value,
use crate::machine::*;
use crate::parser::ast::*;
-use std::cell::Cell;
use std::collections::VecDeque;
use std::mem;
use std::ops::Range;
fn compile_standalone_clause(
&mut self,
- term: Term,
+ term: FocusedHeap,
settings: CodeGenSettings,
) -> Result<StandaloneCompileResult, SessionError> {
let mut preprocessor = Preprocessor::new(settings);
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
- // let queue = preprocessor.parse_queue(self)?;
-
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
let clause_code = cg.compile_predicate(vec![clause])?;
}
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
-
let mut code = cg.compile_predicate(clauses)?;
if settings.is_extensible {
pub(super) fn incremental_compile_clause(
&mut self,
key: PredicateKey,
- clause: Term,
+ clause: FocusedHeap,
compilation_target: CompilationTarget,
non_counted_bt: bool,
append_or_prepend: AppendOrPrepend,
}
impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
- pub(super) fn compile_clause_clauses<ClauseIter: Iterator<Item = (Term, Term)>>(
+ pub(super) fn compile_clause_clauses(
&mut self,
key: PredicateKey,
compilation_target: CompilationTarget,
- clause_clauses: ClauseIter,
+ clause_clauses: Vec<FocusedHeap>,
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,
let mut num_clause_predicates = 0;
- for clause_term in clause_predicates {
+ for clause_term in clause_clauses {
self.incremental_compile_clause(
(atom!("$clause"), 2),
clause_term,
.clause_clauses
.drain(0..std::cmp::min(predicates_len, clause_clauses_len))
.collect();
-
let compilation_target = self.payload.predicates.compilation_target;
self.compile_clause_clauses(
key,
compilation_target,
- clauses_vec.into_iter(),
+ clauses_vec,
AppendOrPrepend::Append,
)?;
}
pub(crate) fn compile_standalone_clause(
&mut self,
- term_loc: RegType,
- vars: &[Term],
+ term_reg: RegType,
+ vars: Vec<HeapCellValue>,
) -> Result<(), SessionError> {
- let mut compile = || {
+ let cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg]));
+
+ // append the variables of vars.
+ let focus = cell.get_value() as usize;
+ let header_loc = term_nth_arg(&self.machine_st.heap, focus, 0).unwrap();
+ let name = term_name(&self.machine_st.heap, header_loc).unwrap();
+ let old_arity = term_arity(&self.machine_st.heap, header_loc);
+
+ let new_header_loc = self.machine_st.heap.len();
+ let new_arity = old_arity + vars.len();
+
+ self.machine_st.heap.push(atom_as_cell!(name, new_arity));
+
+ for idx in header_loc + 1 .. header_loc + 1 + old_arity {
+ self.machine_st.heap.push(self.machine_st.heap[idx]);
+ }
+
+ for var in vars {
+ self.machine_st.heap.push(var);
+ }
+
+ let value = if new_arity > 0 {
+ str_loc_as_cell!(new_header_loc)
+ } else {
+ heap_loc_as_cell!(new_header_loc)
+ };
+
+ let mut compile = |cell| {
+ use crate::heap_iter::eager_stackful_preorder_iter;
+
let mut loader: Loader<'_, InlineLoadState<'_>> =
Loader::new(self, InlineTermStream {});
- let term = loader.read_term_from_heap(term_loc);
- let clause = build_rule_body(vars, term);
+ let mut term = loader.copy_term_from_heap(cell);
let settings = CodeGenSettings {
global_clock_tick: None,
non_counted_bt: true,
};
- loader.compile_standalone_clause(clause, settings)
+ let value = term.heap[term.focus];
+
+ term.var_locs = var_locs_from_iter(
+ eager_stackful_preorder_iter(&mut term.heap, value),
+ );
+
+ loader.compile_standalone_clause(term, settings)
};
- let StandaloneCompileResult { clause_code, .. } = compile()?;
+ let StandaloneCompileResult { clause_code, .. } = compile(value)?;
self.code.extend(clause_code);
Ok(())
use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
-use crate::iterators::*;
+use crate::iterators::fact_iterator;
+use crate::machine::Stack;
use crate::machine::loader::*;
use crate::machine::machine_errors::CompilationError;
use crate::machine::preprocessor::*;
use crate::parser::ast::*;
use crate::parser::dashu::Rational;
+use crate::types::*;
use crate::variable_records::*;
use dashu::Integer;
use indexmap::{IndexMap, IndexSet};
-use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::hash::{Hash, Hasher};
// where it leaves off.
BuildFinalDisjunct(usize),
Fail,
- GetCutPoint { var_num: usize, prev_b: bool },
- Cut { var_num: usize, is_global: bool },
+ Succeed,
+ GetCutPoint {
+ var_num: usize,
+ prev_b: bool,
+ },
+ Cut {
+ var_num: usize,
+ is_global: bool,
+ },
CutPrev(usize),
ResetCallPolicy(CallPolicy),
- Term(Term),
+ Term {
+ subterm: HeapCellValue,
+ term_loc: usize,
+ },
OverrideGlobalCutVar(usize),
ResetGlobalCutVarOverride(Option<usize>),
RemoveBranchNum, // pop the current_branch_num and from the root set.
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)
}
if let Some(global_cut_var_num) = global_cut_var_num {
let term = QueryTerm::GetLevel(global_cut_var_num);
self.records[global_cut_var_num].allocation =
- VarAlloc::Perm(0, PermVarAllocation::Pending);
+ VarAlloc::Perm { reg: 0, allocation: PermVarAllocation::Pending };
match build_stack.front_mut() {
Some(ChunkedTerms::Branch(_)) => {
}
}
-pub type ClassifyFactResult = (Term, VarData);
-pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData);
+pub type ClassifyFactResult = VarData;
+pub type ClassifyRuleResult = (ChunkedTermVec, VarData);
fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
let mut branch_info = BranchInfo::new(BranchNumber::default());
}
}
- pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> {
- self.classify_head_variables(&term)?;
- Ok((
- term,
- self.branch_map.separate_and_classify_variables(
- self.var_num,
- self.global_cut_var_num,
- self.current_chunk_num,
- ),
+ pub fn classify_fact(
+ mut self,
+ term: &mut FocusedHeap,
+ ) -> Result<ClassifyFactResult, CompilationError> {
+ let focus = term.focus;
+ self.classify_head_variables(term, focus)?;
+
+ Ok(self.branch_map.separate_and_classify_variables(
+ self.var_num,
+ self.global_cut_var_num,
+ self.current_chunk_num,
))
}
pub fn classify_rule<'a, LS: LoadState<'a>>(
mut self,
loader: &mut Loader<'a, LS>,
- head: Term,
- body: Term,
+ term: &mut FocusedHeap,
) -> Result<ClassifyRuleResult, CompilationError> {
- self.classify_head_variables(&head)?;
+ let head_loc = term.nth_arg(term.focus, 1).unwrap();
+ let body_loc = term.nth_arg(term.focus, 2).unwrap();
+
+ self.classify_head_variables(term, head_loc)?;
self.root_set.insert(self.current_branch_num.clone());
- let mut query_terms = self.classify_body_variables(loader, body)?;
+ let mut query_terms = self.classify_body_variables(loader, term, body_loc)?;
self.merge_branches();
var_data.emit_initial_get_level(&mut query_terms);
- Ok((head, query_terms, var_data))
+ Ok((query_terms, var_data))
}
fn merge_branches(&mut self) {
}
}
- fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) {
+ fn probe_body_term(
+ &mut self,
+ arg_c: usize,
+ arity: usize,
+ term: &mut FocusedHeap,
+ term_loc: usize,
+ ) {
let classify_info = ClassifyInfo { arg_c, arity };
+ let mut lvl = Level::Shallow;
+ let mut stack = Stack::uninitialized();
+ let mut iter = fact_iterator::<false>(
+ &mut term.heap,
+ &mut stack,
+ term_loc,
+ );
+
// second arg is true to iterate the root, which may be a variable
- for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
- if let TermRef::Var(lvl, _, var_ptr) = term_ref {
- // root terms are shallow here (since we're iterating a
- // body term) so take the child level.
- let lvl = lvl.child_level();
- self.probe_body_var(VarInfo {
- var_ptr,
- lvl,
- classify_info,
- chunk_type: self.current_chunk_type,
- });
+ while let Some(subterm) = iter.next() {
+ if !subterm.is_var() {
+ lvl = Level::Deep;
+ continue;
}
+
+ let var_loc = subterm.get_value() as usize;
+ let var_ptr = term.var_locs.read_next_var_ptr_at_key(var_loc).unwrap();
+
+ self.probe_body_var(VarInfo {
+ var_ptr: var_ptr.clone(),
+ lvl,
+ classify_info,
+ chunk_type: self.current_chunk_type,
+ });
}
}
self.probe_body_var(var_info);
}
- fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> {
- match term {
- Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {}
- _ => return Err(CompilationError::InvalidRuleHead),
- }
+ fn classify_head_variables(
+ &mut self,
+ term: &mut FocusedHeap,
+ head_loc: usize,
+ ) -> Result<(), CompilationError> {
+ let arity = read_heap_cell!(term.deref_loc(head_loc),
+ (HeapCellValueTag::Str, s) => {
+ cell_as_atom_cell!(term.heap[s]).get_arity()
+ }
+ (HeapCellValueTag::Atom) => {
+ return Ok(());
+ }
+ _ => {
+ return Err(CompilationError::InvalidRuleHead);
+ }
+ );
- let mut classify_info = ClassifyInfo {
- arg_c: 1,
- arity: term.arity(),
- };
+ let mut classify_info = ClassifyInfo { arg_c: 1, arity };
- if let Term::Clause(_, _, terms) = term {
- for term in terms.iter() {
- for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
- if let TermRef::Var(lvl, _, var_ptr) = term_ref {
- // a body term, so we need the child level here.
- let lvl = lvl.child_level();
+ if arity > 0 {
+ let (_term_loc, value) = subterm_index(&term.heap, head_loc);
+ let str_offset = value.get_value() as usize;
- // the body of the if let here is an inlined
- // "probe_head_var". note the difference between it
- // and "probe_body_var".
- let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
+ debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str);
- let needs_new_branch = branch_info_v.is_empty();
+ for idx in str_offset + 1 ..= str_offset + arity {
+ let mut lvl = Level::Shallow;
+ let mut stack = Stack::uninitialized();
+ let mut iter = fact_iterator::<false>(
+ &mut term.heap,
+ &mut stack,
+ idx,
+ );
- if needs_new_branch {
- branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
- }
+ while let Some(subterm) = iter.next() {
+ if !subterm.is_var() {
+ lvl = Level::Deep;
+ continue;
+ }
- let branch_info = branch_info_v.last_mut().unwrap();
- let needs_new_chunk = branch_info.chunks.is_empty();
+ let h = subterm.get_value() as usize;
+ let var_ptr = term.var_locs.read_next_var_ptr_at_key(h).unwrap().clone();
- if needs_new_chunk {
- branch_info.chunks.push(ChunkInfo {
- chunk_num: self.current_chunk_num,
- term_loc: GenContext::Head,
- vars: vec![],
- });
- }
+ // the body of the if let here is an inlined
+ // "probe_head_var". note the difference between it
+ // and "probe_body_var".
+ let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
+ let needs_new_branch = branch_info_v.is_empty();
- let chunk_info = branch_info.chunks.last_mut().unwrap();
- let var_info = VarInfo {
- var_ptr,
- classify_info,
- chunk_type: self.current_chunk_type,
- lvl,
- };
+ if needs_new_branch {
+ branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
+ }
+
+ let branch_info = branch_info_v.last_mut().unwrap();
+ let needs_new_chunk = branch_info.chunks.is_empty();
- chunk_info.vars.push(var_info);
+ if needs_new_chunk {
+ branch_info.chunks.push(ChunkInfo {
+ chunk_num: self.current_chunk_num,
+ term_loc: GenContext::Head,
+ vars: vec![],
+ });
}
+
+ let chunk_info = branch_info.chunks.last_mut().unwrap();
+ let var_info = VarInfo {
+ var_ptr,
+ classify_info,
+ chunk_type: self.current_chunk_type,
+ lvl,
+ };
+
+ chunk_info.vars.push(var_info);
}
classify_info.arg_c += 1;
Ok(())
}
+ fn new_cut_state(&mut self) -> TraversalState {
+ let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override {
+ (var_num, false)
+ } else if let Some(var_num) = self.global_cut_var_num {
+ (var_num, true)
+ } else {
+ let var_num = self.var_num;
+
+ self.global_cut_var_num = Some(var_num);
+ self.var_num += 1;
+
+ (var_num, true)
+ };
+
+ self.probe_in_situ_var(var_num);
+
+ TraversalState::Cut { var_num, is_global }
+ }
+
fn classify_body_variables<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
- term: Term,
+ terms: &mut FocusedHeap,
+ term_loc: usize,
) -> Result<ChunkedTermVec, CompilationError> {
- let mut state_stack = vec![TraversalState::Term(term)];
+ let mut state_stack = vec![TraversalState::Term {
+ subterm: terms.heap[term_loc],
+ term_loc,
+ }];
let mut build_stack = ChunkedTermVec::new();
self.current_chunk_type = ChunkType::Mid;
- while let Some(traversal_st) = state_stack.pop() {
+ 'outer: while let Some(traversal_st) = state_stack.pop() {
match traversal_st {
TraversalState::AddBranchNum(branch_num) => {
self.root_set.insert(branch_num.clone());
TraversalState::Fail => {
build_stack.push_chunk_term(QueryTerm::Fail);
}
- TraversalState::Term(term) => {
+ TraversalState::Succeed => {
+ build_stack.push_chunk_term(QueryTerm::Succeed);
+ }
+ TraversalState::Term {
+ mut subterm,
+ mut term_loc,
+ } => {
// return true iff new chunk should be added.
- let update_chunk_data = |classifier: &mut Self, predicate_name, arity| {
- if ClauseType::is_inlined(predicate_name, arity) {
+ let update_chunk_data = |classifier: &mut Self, key: PredicateKey| {
+ if ClauseType::is_inlined(key.0, key.1) {
classifier.try_set_chunk_at_inlined_boundary()
} else {
classifier.try_set_chunk_at_call_boundary()
}
};
- let mut add_chunk = |classifier: &mut Self, name: Atom, terms: Vec<Term>| {
- if update_chunk_data(classifier, name, terms.len()) {
- build_stack.add_chunk();
- }
-
- for (arg_c, term) in terms.iter().enumerate() {
- classifier.probe_body_term(arg_c + 1, terms.len(), term);
- }
-
- build_stack.push_chunk_term(clause_to_query_term(
- loader,
- name,
- terms,
- classifier.call_policy,
- ));
- };
-
- match term {
- Term::Clause(
- _,
- name @ (atom!("->") | atom!(";") | atom!(",")),
- mut terms,
- ) if terms.len() == 3 => {
- if let Some(last_arg) = terms.last() {
- if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
- terms.pop();
- state_stack.push(TraversalState::Term(Term::Clause(
- Cell::default(),
- name,
- terms,
- )));
- } else {
- add_chunk(self, name, terms);
- }
+ macro_rules! add_chunk {
+ ($classifier:ident, $key:expr, $tag:expr, $term_loc:expr) => {{
+ if update_chunk_data($classifier, $key) {
+ build_stack.add_chunk();
}
- }
- Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => {
- let tail = terms.pop().unwrap();
- let head = terms.pop().unwrap();
-
- let iter = unfold_by_str(tail, atom!(","))
- .into_iter()
- .rev()
- .chain(std::iter::once(head))
- .map(TraversalState::Term);
-
- state_stack.extend(iter);
- }
- Term::Clause(_, atom!(";"), mut terms) if terms.len() == 2 => {
- let tail = terms.pop().unwrap();
- let head = terms.pop().unwrap();
-
- let first_branch_num = self.current_branch_num.split();
- let branches: Vec<_> = std::iter::once(head)
- .chain(unfold_by_str(tail, atom!(";")).into_iter())
- .collect();
-
- let mut branch_numbers = vec![first_branch_num];
-
- for idx in 1..branches.len() {
- let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
- branch_numbers.push(if idx + 1 < branches.len() {
- succ_branch_number.split()
- } else {
- succ_branch_number
- });
+ for (arg_c, term_loc) in
+ ($term_loc + 1 ..= $term_loc + $key.1).enumerate()
+ {
+ $classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
}
- let build_stack_len = build_stack.len();
- build_stack.reserve_branch(branches.len());
-
- state_stack.push(TraversalState::RepBranchNum(
- self.current_branch_num.halve_delta(),
- ));
-
- let iter = branches.into_iter().zip(branch_numbers.into_iter());
- let final_disjunct_loc = state_stack.len();
+ build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
+ loader,
+ $key,
+ terms.as_ref_mut($term_loc),
+ HeapCellValue::build_with($tag, $term_loc as u64),
+ $classifier.call_policy,
+ )));
+ }};
+ }
- for (term, branch_num) in iter.rev() {
- state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
- state_stack.push(TraversalState::RemoveBranchNum);
- state_stack.push(TraversalState::Term(term));
- state_stack.push(TraversalState::AddBranchNum(branch_num));
+ macro_rules! add_qualified_chunk {
+ ($classifier:ident, $module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{
+ if update_chunk_data($classifier, $key) {
+ build_stack.add_chunk();
}
- if let TraversalState::BuildDisjunct(build_stack_len) =
- state_stack[final_disjunct_loc]
+ for (arg_c, term_loc) in
+ ($term_loc + 1..$term_loc + $key.1 + 1).enumerate()
{
- state_stack[final_disjunct_loc] =
- TraversalState::BuildFinalDisjunct(build_stack_len);
+ $classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
}
- self.current_chunk_type = ChunkType::Mid;
- self.current_chunk_num += 1;
- }
- Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => {
- let then_term = terms.pop().unwrap();
- let if_term = terms.pop().unwrap();
-
- let prev_b = if matches!(
- state_stack.last(),
- Some(TraversalState::RemoveBranchNum)
- ) {
- // check if the second-to-last element
- // is a regular BuildDisjunct, as we
- // don't want to add GetPrevLevel in
- // case of a TrustMe.
- match state_stack.iter().rev().nth(1) {
- Some(&TraversalState::BuildDisjunct(preceding_len)) => {
- preceding_len + 1 == build_stack.len()
- }
- _ => false,
- }
- } else {
- false
- };
-
- state_stack.push(TraversalState::Term(then_term));
- state_stack.push(TraversalState::Cut {
- var_num: self.var_num,
- is_global: false,
- });
- state_stack.push(TraversalState::Term(if_term));
- state_stack.push(TraversalState::GetCutPoint {
- var_num: self.var_num,
- prev_b,
- });
-
- self.var_num += 1;
- }
- Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => {
- let not_term = terms.pop().unwrap();
- let build_stack_len = build_stack.len();
-
- build_stack.reserve_branch(2);
-
- state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
- state_stack.push(TraversalState::Term(Term::Clause(
- Cell::default(),
- atom!("$succeed"),
- vec![],
- )));
- state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
- state_stack.push(TraversalState::Fail);
- state_stack.push(TraversalState::CutPrev(self.var_num));
- state_stack.push(TraversalState::ResetGlobalCutVarOverride(
- self.global_cut_var_num_override,
+ build_stack.push_chunk_term(QueryTerm::Clause(
+ qualified_clause_to_query_term(
+ loader,
+ $key,
+ $module_name,
+ terms.as_ref_mut($term_loc),
+ HeapCellValue::build_with($tag, $term_loc as u64),
+ $classifier.call_policy,
+ ),
));
- state_stack.push(TraversalState::Term(not_term));
- state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
- state_stack.push(TraversalState::GetCutPoint {
- var_num: self.var_num,
- prev_b: false,
- });
+ }};
+ }
- self.current_chunk_type = ChunkType::Mid;
- self.current_chunk_num += 1;
+ loop {
+ read_heap_cell!(subterm,
+ (HeapCellValueTag::Str, subterm_loc) => {
+ let (name, arity) = cell_as_atom_cell!(terms.heap[subterm_loc])
+ .get_name_and_arity();
- self.var_num += 1;
- }
- Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => {
- let predicate_name = terms.pop().unwrap();
- let module_name = terms.pop().unwrap();
-
- match (module_name, predicate_name) {
- (
- Term::Literal(_, Literal::Atom(module_name)),
- Term::Literal(_, Literal::Atom(predicate_name)),
- ) => {
- if update_chunk_data(self, predicate_name, 0) {
- build_stack.add_chunk();
- }
+ match (name, arity) {
+ (atom!("->") | atom!(";") | atom!(","), 3) => {
+ if blunt_index_ptr(&mut terms.heap, (name, 2), subterm_loc) {
+ subterm = terms.heap[subterm_loc];
+ continue;
+ }
- build_stack.push_chunk_term(qualified_clause_to_query_term(
- loader,
- module_name,
- predicate_name,
- vec![],
- self.call_policy,
- ));
- }
- (
- Term::Literal(_, Literal::Atom(module_name)),
- Term::Clause(_, name, terms),
- ) => {
- if update_chunk_data(self, name, terms.len()) {
- build_stack.add_chunk();
+ add_chunk!(self, (name, 2), HeapCellValueTag::Str, subterm_loc);
}
-
- for (arg_c, term) in terms.iter().enumerate() {
- self.probe_body_term(arg_c + 1, terms.len(), term);
+ (atom!(","), 2) => {
+ let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
+ let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap();
+ let head = terms.heap[head_loc];
+
+ let iter = unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(","))
+ .into_iter()
+ .rev()
+ .chain(std::iter::once((head, head_loc)))
+ .map(|(subterm, term_loc)| {
+ TraversalState::Term { subterm, term_loc }
+ });
+ state_stack.extend(iter);
}
-
- build_stack.push_chunk_term(qualified_clause_to_query_term(
- loader,
- module_name,
- name,
- terms,
- self.call_policy,
- ));
- }
- (module_name, predicate_name) => {
- if update_chunk_data(self, atom!("call"), 2) {
- build_stack.add_chunk();
+ (atom!(";"), 2) => {
+ let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
+ let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap();
+
+ let head = terms.heap[head_loc];
+
+ let first_branch_num = self.current_branch_num.split();
+ let branches: Vec<_> = std::iter::once((head, head_loc))
+ .chain(
+ unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(";"))
+ .into_iter(),
+ )
+ .collect();
+
+ let mut branch_numbers = vec![first_branch_num];
+
+ for idx in 1..branches.len() {
+ let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
+
+ branch_numbers.push(if idx + 1 < branches.len() {
+ succ_branch_number.split()
+ } else {
+ succ_branch_number
+ });
+ }
+
+ let build_stack_len = build_stack.len();
+ build_stack.reserve_branch(branches.len());
+
+ state_stack.push(TraversalState::RepBranchNum(
+ self.current_branch_num.halve_delta(),
+ ));
+
+ let iter = branches.into_iter().zip(branch_numbers.into_iter());
+ let final_disjunct_loc = state_stack.len();
+
+ for ((subterm, term_loc), branch_num) in iter.rev() {
+ state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
+ state_stack.push(TraversalState::RemoveBranchNum);
+ state_stack.push(TraversalState::Term { subterm, term_loc });
+ state_stack.push(TraversalState::AddBranchNum(branch_num));
+ }
+
+ if let TraversalState::BuildDisjunct(build_stack_len) =
+ state_stack[final_disjunct_loc]
+ {
+ state_stack[final_disjunct_loc] =
+ TraversalState::BuildFinalDisjunct(build_stack_len);
+ }
+
+ self.current_chunk_type = ChunkType::Mid;
+ self.current_chunk_num += 1;
}
+ (atom!("->"), 2) => {
+ let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
+ let then_term_loc = terms.nth_arg(subterm_loc, 2).unwrap();
+
+ let if_term = terms.heap[if_term_loc];
+ let then_term = terms.heap[then_term_loc];
+
+ let prev_b = if matches!(
+ state_stack.last(),
+ Some(TraversalState::RemoveBranchNum)
+ ) {
+ // check if the second-to-last element
+ // is a regular BuildDisjunct, as we
+ // don't want to add GetPrevLevel in
+ // case of a TrustMe.
+ match state_stack.iter().rev().nth(1) {
+ Some(&TraversalState::BuildDisjunct(preceding_len)) => {
+ preceding_len + 1 == build_stack.len()
+ }
+ _ => false,
+ }
+ } else {
+ false
+ };
+
+ state_stack.push(TraversalState::Term {
+ subterm: then_term,
+ term_loc: then_term_loc,
+ });
+ state_stack.push(TraversalState::Cut {
+ var_num: self.var_num,
+ is_global: false,
+ });
+ state_stack.push(TraversalState::Term {
+ subterm: if_term,
+ term_loc: if_term_loc,
+ });
+ state_stack.push(TraversalState::GetCutPoint {
+ var_num: self.var_num,
+ prev_b,
+ });
+
+ self.var_num += 1;
+ }
+ (atom!("\\+"), 1) => {
+ let not_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
+ let not_term = terms.heap[not_term_loc];
+ let build_stack_len = build_stack.len();
+
+ build_stack.reserve_branch(2);
+
+ let branch_num = self.current_branch_num.split();
+ let succ_branch_num = branch_num.incr_by_delta();
+
+ state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
+ state_stack.push(TraversalState::Succeed);
+ state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
+ state_stack.push(TraversalState::RepBranchNum(succ_branch_num));
+ state_stack.push(TraversalState::Fail);
+ state_stack.push(TraversalState::CutPrev(self.var_num));
+ state_stack.push(TraversalState::ResetGlobalCutVarOverride(
+ self.global_cut_var_num_override,
+ ));
+ state_stack.push(TraversalState::Term {
+ subterm: not_term,
+ term_loc: not_term_loc,
+ });
+ state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
+ state_stack.push(TraversalState::GetCutPoint {
+ var_num: self.var_num,
+ prev_b: false,
+ });
+ state_stack.push(TraversalState::AddBranchNum(branch_num));
+
+ self.current_chunk_type = ChunkType::Mid;
+ self.current_chunk_num += 1;
+
+ self.var_num += 1;
+ }
+ (atom!(":"), 2) => {
+ let module_name_loc = terms.nth_arg(subterm_loc, 1).unwrap();
+ let predicate_term_loc = terms.nth_arg(subterm_loc, 2).unwrap();
+
+ let module_name = terms.deref_loc(module_name_loc);
+ let predicate_term = terms.deref_loc(predicate_term_loc);
+
+ read_heap_cell!(module_name,
+ (HeapCellValueTag::Atom, (module_name, arity)) => {
+ if arity == 0 {
+ read_heap_cell!(predicate_term,
+ (HeapCellValueTag::Str, s) => {
+ let key = cell_as_atom_cell!(terms.heap[s])
+ .get_name_and_arity();
+
+ add_qualified_chunk!(
+ self,
+ module_name,
+ key,
+ HeapCellValueTag::Str,
+ s
+ );
+ }
+ (HeapCellValueTag::Atom, (predicate_name, predicate_arity)) => {
+ debug_assert_eq!(predicate_arity, 0);
+ let key = (predicate_name, predicate_arity);
+
+ add_qualified_chunk!(
+ self,
+ module_name,
+ key,
+ HeapCellValueTag::Str,
+ predicate_term_loc
+ );
+ }
+ _ => {}
+ );
+
+ continue 'outer;
+ }
+ }
+ _ => {}
+ );
+
+ if update_chunk_data(self, (atom!("call"), 2)) {
+ build_stack.add_chunk();
+ }
+
+ self.probe_body_term(1, 0, terms, module_name_loc);
+ self.probe_body_term(2, 0, terms, predicate_term_loc);
+
+ let h = terms.heap.len();
+
+ terms.heap.push(atom_as_cell!(atom!("call"), 1));
+ terms.heap.push(str_loc_as_cell!(subterm_loc));
+
+ build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
+ loader,
+ (atom!("call"), 1),
+ terms.as_ref_mut(h),
+ str_loc_as_cell!(h),
+ self.call_policy,
+ )));
+ }
+ (atom!("$call_with_inference_counting"), 1) => {
+ let term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
+ let subterm = terms.deref_loc(term_loc);
- self.probe_body_term(1, 0, &module_name);
- self.probe_body_term(2, 0, &predicate_name);
-
- terms.push(module_name);
- terms.push(predicate_name);
+ state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
+ state_stack.push(TraversalState::Term { subterm, term_loc });
- build_stack.push_chunk_term(clause_to_query_term(
- loader,
- atom!("call"),
- vec![Term::Clause(Cell::default(), atom!(":"), terms)],
- self.call_policy,
- ));
+ self.call_policy = CallPolicy::Counted;
+ }
+ (name, arity) => {
+ add_chunk!(self, (name, arity), HeapCellValueTag::Str, subterm_loc);
+ }
}
}
- }
- Term::Clause(_, atom!("$call_with_inference_counting"), mut terms)
- if terms.len() == 1 =>
- {
- state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
- state_stack.push(TraversalState::Term(terms.pop().unwrap()));
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
- self.call_policy = CallPolicy::Counted;
- }
- Term::Clause(_, name, terms) => {
- add_chunk(self, name, terms);
- }
- var @ Term::Var(..) => {
- if update_chunk_data(self, atom!("call"), 1) {
- build_stack.add_chunk();
+ if name == atom!("!") {
+ state_stack.push(self.new_cut_state());
+ } else {
+ add_chunk!(self, (name, 0), HeapCellValueTag::Var, term_loc);
+ }
}
-
- self.probe_body_term(1, 1, &var);
-
- build_stack.push_chunk_term(clause_to_query_term(
- loader,
- atom!("call"),
- vec![var],
- self.call_policy,
- ));
- }
- Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
- let (var_num, is_global) =
- if let Some(var_num) = self.global_cut_var_num_override {
- (var_num, false)
- } else if let Some(var_num) = self.global_cut_var_num {
- (var_num, true)
+ (HeapCellValueTag::Char, c) => {
+ if c == '!' {
+ state_stack.push(self.new_cut_state());
} else {
- let var_num = self.var_num;
-
- self.global_cut_var_num = Some(var_num);
- self.var_num += 1;
-
- (var_num, true)
- };
-
- self.probe_in_situ_var(var_num);
+ return Err(CompilationError::InadmissibleQueryTerm);
+ }
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if h != term_loc {
+ subterm = terms.heap[h];
+ term_loc = h;
+ continue;
+ }
- state_stack.push(TraversalState::Cut { var_num, is_global });
- }
- Term::Literal(_, Literal::Atom(name)) => {
- if update_chunk_data(self, name, 0) {
- build_stack.add_chunk();
+ add_chunk!(self, (atom!("call"), 1), HeapCellValueTag::Var, h);
+ }
+ _ => {
+ return Err(CompilationError::InadmissibleQueryTerm);
}
+ );
- build_stack.push_chunk_term(clause_to_query_term(
- loader,
- name,
- vec![],
- self.call_policy,
- ));
- }
- _ => {
- return Err(CompilationError::InadmissibleQueryTerm);
- }
+ break;
}
}
}
var_data.records[var_num].num_occurrences += chunk.vars.len();
for var_info in chunk.vars.iter_mut() {
- var_info.var_ptr.set(Var::Generated(var_num));
+ let is_anon = var_info.var_ptr.is_anon();
+ var_info.var_ptr.set(Var::Generated { is_anon, var_num });
}
}
}
&Instruction::CallNamed(arity, name, ref idx) => {
let idx = idx.get();
+ // println!("calling {}/{}", name.as_str(), arity);
+
try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
if self.machine_st.fail {
&Instruction::ExecuteNamed(arity, name, ref idx) => {
let idx = idx.get();
+ // println!("executing {}/{}", name.as_str(), arity);
+
try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
if self.machine_st.fail {
&Instruction::DefaultCallNamed(arity, name, ref idx) => {
let idx = idx.get();
+ // println!("calling {}/{}", name.as_str(), arity);
+
try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
if self.machine_st.fail {
&Instruction::DefaultExecuteNamed(arity, name, ref idx) => {
let idx = idx.get();
+ // println!("executing {}/{}", name.as_str(), arity);
+
try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
if self.machine_st.fail {
self.dynamic_module_resolution(arity - 2)
);
+ /*
+ println!(
+ "(slow) calling {}:{}/{}",
+ module_name.as_str(),
+ key.0.as_str(),
+ key.1,
+ );
+ */
+
try_or_throw!(self.machine_st, self.call_clause(module_name, key));
if self.machine_st.fail {
self.dynamic_module_resolution(arity - 2)
);
+ /*
+ println!(
+ "(slow) executing {}:{}/{}",
+ module_name.as_str(),
+ key.0.as_str(),
+ key.1,
+ );
+ */
+
try_or_throw!(self.machine_st, self.execute_clause(module_name, key));
if self.machine_st.fail {
#[cfg(test)]
use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc};
+#[cfg(test)]
+use std::ops::Deref;
+
pub(crate) trait UnmarkPolicy {
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
where
iter_state: UMP,
}
+#[cfg(test)]
+impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> {
+ type Target = [HeapCellValue];
+
+ fn deref(&self) -> &Self::Target {
+ self.heap
+ }
+}
+
#[cfg(test)]
impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
#[inline]
use std::collections::BTreeMap;
use crate::atom_table;
-use crate::machine::machine_indices::VarKey;
+use crate::heap_print::{HCPrinter, HCValueOutputter, PrinterOutputter};
use crate::machine::mock_wam::CompositeOpDir;
-use crate::machine::{BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS};
+use crate::machine::{copy_and_align_iter, BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS};
use crate::parser::ast::{Var, VarPtr};
use crate::parser::parser::{Parser, Tokens};
-use crate::read::{write_term_to_heap, TermWriteResult};
use indexmap::IndexMap;
use super::{
self.allocate_stub_choice_point();
// Write parsed term to heap
- let term_write_result =
- write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl)
- .expect("couldn't write term to heap");
-
- let var_names: IndexMap<_, _> = term_write_result
- .var_dict
- .iter()
- .map(|(var_key, cell)| match var_key {
- // NOTE: not the intention behind Var::InSitu here but
- // we can hijack it to store anonymous variables
- // without creating problems.
- VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))),
- VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()),
- })
- .collect();
+ let heap_loc = self.machine_st.heap.len();
+ self.machine_st.heap.extend(copy_and_align_iter(
+ term.heap.iter().cloned(),
+ 0,
+ heap_loc as i64,
+ ));
// Write term to heap
- self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc];
+ self.machine_st.registers[1] = self.machine_st.heap[heap_loc + term.focus];
self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
let call_index_p = self
.local()
.unwrap();
+ let var_names: IndexMap<_, _> = term
+ .var_locs
+ .iter()
+ .map(|(var_loc, var_ptrs)| {
+ let var_loc = var_loc + heap_loc;
+ let cell = self.machine_st.heap[var_loc];
+ let var_ptr = var_ptrs.front().unwrap();
+
+ match &*var_ptr.borrow() {
+ // NOTE: not the intention behind Var::InSitu here but
+ // we can hijack it to store anonymous variables
+ // without creating problems.
+ Var::Anon => (cell, VarPtr::from(Var::InSitu(var_loc))),
+ _ => (cell, var_ptr.clone()),
+ }
+ })
+ .collect();
+
self.machine_st.execute_at_index(1, call_index_p);
let stub_b = self.machine_st.b;
pub(super) fn try_term_to_tl(
&mut self,
- term: Term,
+ term: FocusedHeap,
preprocessor: &mut Preprocessor,
) -> Result<PredicateClause, SessionError> {
let tl = preprocessor.try_term_to_tl(self, term)?;
let mut path_buf = PathBuf::from(&*filename.as_str());
path_buf.set_extension("pl");
- let file = File::open(&path_buf)?;
+ let file = File::open(&path_buf)
+ .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
(
Stream::from_file_as_input(
ModuleSource::File(filename) => {
let mut path_buf = PathBuf::from(&*filename.as_str());
path_buf.set_extension("pl");
- let file = File::open(&path_buf)?;
+ let file = File::open(&path_buf)
+ .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
(
Stream::from_file_as_input(
use indexmap::IndexSet;
-use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fmt;
}
pub struct PredicateQueue {
- pub(super) predicates: Vec<Term>,
+ pub(super) predicates: Vec<FocusedHeap>,
pub(super) compilation_target: CompilationTarget,
}
impl PredicateQueue {
#[inline]
- pub(super) fn push(&mut self, clause: Term) {
+ pub(super) fn push(&mut self, clause: FocusedHeap) {
self.predicates.push(clause);
}
#[inline]
- pub(crate) fn first(&self) -> Option<&Term> {
+ pub(crate) fn first(&self) -> Option<&FocusedHeap> {
self.predicates.first()
}
}
}
- pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Term {
+ pub(crate) fn copy_term_from_heap(&mut self, cell: HeapCellValue) -> FocusedHeap {
+ use crate::iterators::fact_iterator;
+
+ let mut term = FocusedHeap::empty();
+ let mut stack = Stack::uninitialized();
let machine_st = LS::machine_st(&mut self.payload);
- let cell = machine_st[r];
- machine_st.read_term_from_heap(cell)
+ term.copy_term_from_machine_heap(machine_st, cell);
+ term.var_locs = var_locs_from_iter(
+ fact_iterator::<false>(
+ &mut term.heap,
+ &mut stack,
+ 0,
+ ),
+ );
+
+ term
}
pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
let compilation_target = &load_state.compilation_target;
let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target);
- let term = load_state.term_stream.next(&composite_op_dir)?;
+ let mut term = load_state.term_stream.next(&composite_op_dir)?;
if !term.is_consistent(&load_state.predicates) {
self.compile_and_submit()?;
}
- let term = match term {
- Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => {
- return Ok(Some(setup_declaration(self, terms)?));
- }
- term => term,
- };
+ if Some(atom!(":-")) == term.name(term.focus) && term.arity(term.focus) == 1 {
+ let new_focus = term.nth_arg(term.focus, 1).unwrap();
+ let term = term.as_ref_mut(new_focus);
+ return Ok(Some(setup_declaration(self, term)?));
+ }
self.payload.predicates.push(term);
}
let machine_st = LS::machine_st(&mut self.payload);
let cell = machine_st[r];
- let export_list = machine_st.read_term_from_heap(cell);
- let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl;
- let export_list = setup_module_export_list(export_list, atom_tbl)?;
+ let export_list = FocusedHeapRefMut::from_cell(&mut machine_st.heap, cell);
+ let export_list = setup_module_export_list(export_list)?;
Ok(export_list.into_iter().collect())
}
- fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> {
- match term {
- Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => {
- let body = terms.pop().unwrap();
- let head = terms.pop().unwrap();
+ fn clause_clause(&mut self, cell: HeapCellValue) -> Result<FocusedHeap, CompilationError> {
+ let machine_st = LS::machine_st(&mut self.payload);
+ let mut term = FocusedHeap::empty();
+
+ read_heap_cell!(cell,
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
+ .get_name_and_arity();
+
+ term.copy_term_from_machine_heap(machine_st, cell);
+ let focus = term.heap.len();
+
+ term.heap.push(str_loc_as_cell!(focus+1));
+ term.heap.push(atom_as_cell!(atom!("clause"), 2));
+
+ match (name, arity) {
+ (atom!(":-"), 2) => {
+ term.heap.push(heap_loc_as_cell!(2));
+ term.heap.push(heap_loc_as_cell!(3));
+ }
+ _ => {
+ term.heap.push(heap_loc_as_cell!(0));
+ term.heap.push(atom_as_cell!(atom!("true")));
+ }
+ }
- self.payload.clause_clauses.push((head, body));
+ term.focus = focus;
}
- head @ Term::Literal(_, Literal::Atom(..)) | head @ Term::Clause(..) => {
- let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
- self.payload.clause_clauses.push((head, body));
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ term.heap.push(str_loc_as_cell!(1));
+ term.heap.push(atom_as_cell!(atom!("clause"), 2));
+ term.heap.push(atom_as_cell!(name));
+ term.heap.push(atom_as_cell!(atom!("true")));
+
+ term.focus = 0;
+ } else {
+ return Err(CompilationError::InadmissibleFact);
+ }
}
_ => {
return Err(CompilationError::InadmissibleFact);
}
- }
+ );
- Ok(())
+ let value = term.heap[term.focus];
+ term.var_locs = var_locs_from_iter(eager_stackful_preorder_iter(&mut term.heap, value));
+ Ok(term)
}
fn add_extensible_predicate_declaration(
)
}
- fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
- if let Some(predicate_name) = ClauseInfo::name(term) {
- let arity = ClauseInfo::arity(term);
+ fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> {
+ let machine_st = LS::machine_st(&mut self.payload);
+ let term = FocusedHeapRefMut::from_cell(&mut machine_st.heap, value);
+
+ let name_opt = ClauseInfo::name(&term);
+
+ if let Some(predicate_name) = name_opt {
+ let arity = ClauseInfo::arity(&term);
let predicates_compilation_target = self.payload.predicates.compilation_target;
let is_dynamic = self
.unwrap_or(false);
if is_dynamic {
- self.add_clause_clause(term.clone())?;
+ let clause_clause_term = self.clause_clause(value)?;
+ self.payload.clause_clauses.push(clause_clause_term);
}
}
}
}
+/*
impl MachineState {
- pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term {
- let mut term_stack = vec![];
- let mut iter =
- stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term_addr);
-
- while let Some(addr) = iter.next() {
- let addr = unmark_cell_bits!(addr);
+ pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> FocusedHeap {
+ let mut term = FocusedHeap::empty();
+ term.copy_term_from_machine_heap(self, term_addr);
- read_heap_cell!(addr,
- (HeapCellValueTag::Lis) => {
- use crate::parser::parser::as_partial_string;
+ let value = term.heap[0];
+ let iter = eager_stackful_preorder_iter(&mut term.heap, value);
- let tail = term_stack.pop().unwrap();
- let head = term_stack.pop().unwrap();
-
- match as_partial_string(head, tail) {
- Ok((string, Some(tail))) => {
- term_stack.push(Term::PartialString(Cell::default(), string, tail));
- }
- Ok((string, None)) => {
- let atom = AtomTable::build_with(&self.atom_tbl, &string);
- term_stack.push(Term::CompleteString(Cell::default(), atom));
- }
- Err(cons_term) => term_stack.push(cons_term),
- }
- }
- (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
- term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
- }
- (HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
- HeapCellValueTag::Char | HeapCellValueTag::F64) => {
- term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
- }
- (HeapCellValueTag::Atom, (name, arity)) => {
- let h = iter.focus().value() as usize;
- let mut arity = arity;
-
- if iter.heap.len() > h + arity + 1 {
- let value = iter.heap[h + arity + 1];
-
- if let Some(idx) = get_structure_index(value) {
- // in the second condition, arity == 0,
- // meaning idx cannot pertain to this atom
- // if it is the direct subterm of a larger
- // structure.
- if arity > 0 || !iter.direct_subterm_of_str(h) {
- term_stack.push(
- Term::Literal(Cell::default(), Literal::CodeIndex(idx))
- );
-
- arity += 1;
- }
- }
- }
-
- if arity == 0 {
- term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
- } else {
- let subterms = term_stack
- .drain(term_stack.len() - arity ..)
- .collect();
-
- term_stack.push(Term::Clause(Cell::default(), name, subterms));
- }
- }
- (HeapCellValueTag::PStr, atom) => {
- let tail = term_stack.pop().unwrap();
-
- if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
- term_stack.push(Term::CompleteString(Cell::default(), atom));
- } else {
- term_stack.push(Term::PartialString(
- Cell::default(),
- atom.as_str().to_owned(),
- Box::new(tail),
- ));
- }
- }
- (HeapCellValueTag::PStrLoc, h) => {
- let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
- let tail = term_stack.pop().unwrap();
-
- term_stack.push(Term::PartialString(
- Cell::default(),
- atom.as_str().to_owned(),
- Box::new(tail),
- ));
- }
- _ => {
- }
- );
- }
-
- debug_assert!(term_stack.len() == 1);
- term_stack.pop().unwrap()
+ term.var_locs = var_locs_from_iter(iter);
+ term
}
}
+*/
impl Machine {
pub(crate) fn use_module(&mut self) -> CallResult {
}
pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult {
+ let value = self.machine_st.registers[1];
let mut loader = self.loader_from_heap_evacuable(temp_v!(2));
let add_clause = || {
- let term = loader.read_term_from_heap(temp_v!(1));
+ let term = loader.copy_term_from_heap(value);
loader.incremental_compile_clause(
(atom!("term_expansion"), 2),
.machine_st
.store(self.machine_st.deref(self.machine_st.registers[1])));
+ let value = self.machine_st.registers[2];
let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
let compilation_target = match target_module_name {
};
let add_clause = || {
- let term = loader.read_term_from_heap(temp_v!(2));
+ let term = loader.copy_term_from_heap(value);
- let indexing_arg = match term.name() {
- Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg),
- Some(_) => term.first_arg(),
+ let indexing_arg = match term.name(term.focus) {
+ Some(atom!(":-")) => term.nth_arg(term.focus, 1).and_then(|h| term.nth_arg(h, 1)),
+ Some(_) => term.nth_arg(term.focus, 1),
None => None,
};
- if let Some(indexing_term) = indexing_arg {
- if let Some(indexing_name) = indexing_term.name() {
+ if let Some(indexing_term_loc) = indexing_arg {
+ if let Some(indexing_name) = term.name(indexing_term_loc) {
loader
.wam_prelude
.indices
.goal_expansion_indices
- .insert((indexing_name, indexing_term.arity()));
+ .insert((indexing_name, term.arity(indexing_term_loc)));
}
}
};
let stub_gen = || functor_stub(key.0, key.1);
+ let assert_clause = self.machine_st.registers[2];
+ let (name, arity) = {
+ let term = FocusedHeapRefMut::from_cell(&mut self.machine_st.heap, assert_clause);
+ (ClauseInfo::name(&term), ClauseInfo::arity(&term))
+ };
- let head = self.deref_register(2);
-
- if head.is_var() {
- let err = self.machine_st.instantiation_error();
- return Err(self.machine_st.error_form(err, stub_gen()));
- }
-
- let mut compile_assert = || {
+ let mut compile_assert = |assert_clause, name, arity| {
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
Loader::new(self, LiveTermStream::new(ListingSource::User));
loader.payload.compilation_target = compilation_target;
- let head =
- LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head);
-
- let name = if let Some(name) = head.name() {
+ let name = if let Some(name) = name {
name
} else {
return Err(SessionError::from(CompilationError::InvalidRuleHead));
};
- let arity = head.arity();
let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity));
let is_dynamic_predicate = loader
return LiveLoadAndMachineState::evacuate(loader);
}
- let body = loader.read_term_from_heap(temp_v!(3));
-
- let asserted_clause = Term::Clause(
- Cell::default(),
- atom!(":-"),
- vec![head.clone(), body.clone()],
- );
-
// if a new predicate was just created, make it dynamic.
loader.add_dynamic_predicate(compilation_target, name, arity)?;
+ let asserted_clause = loader.copy_term_from_heap(assert_clause);
loader.incremental_compile_clause(
(name, arity),
append_or_prepend,
)?;
+ let clause_clause_term = loader.clause_clause(assert_clause)?;
+
// the global clock is incremented after each assertion.
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
loader.compile_clause_clauses(
(name, arity),
compilation_target,
- std::iter::once((head, body)),
+ vec![clause_clause_term],
append_or_prepend,
)?;
LiveLoadAndMachineState::evacuate(loader)
};
- match compile_assert() {
+ match compile_assert(assert_clause, name, arity) {
Ok(_) => Ok(()),
Err(SessionError::CompilationError(
CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact,
self.payload.predicates.compilation_target = compilation_target;
}
- let term = self.read_term_from_heap(term_reg);
+ let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload);
+ let value = machine_st[term_reg];
+
+ self.add_clause_clause_if_dynamic(value)?;
- self.add_clause_clause_if_dynamic(&term)?;
+ let term = self.copy_term_from_heap(value);
self.payload.term_stream.term_queue.push_back(term);
self.load()
#[derive(Debug)]
pub(crate) struct MachineError {
stub: MachineStub,
- location: Option<(usize, usize)>, // line_num, col_num
+ location: Option<ParserErrorSrc>,
from: ErrorProvenance,
}
stub[1] = err.stub[0];
}
- if let Some((line_num, _)) = location {
+ if let Some(ParserErrorSrc { line_num, .. }) = location {
stub.push(atom_as_cell!(atom!(":"), 2));
stub.push(str_loc_as_cell!(h + 6 + stub_addition_len));
stub.push(integer_as_cell!(Number::arena_from(
}
impl CompilationError {
- pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> {
+ pub(crate) fn line_and_col_num(&self) -> Option<ParserErrorSrc> {
match self {
- CompilationError::ParserError(err) => err.line_and_col_num(),
+ CompilationError::ParserError(err) => Some(err.err_src()),
_ => None,
}
}
PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
}
-impl From<std::io::Error> for SessionError {
- #[inline]
- fn from(err: std::io::Error) -> SessionError {
- SessionError::from(ParserError::from(err))
- }
-}
-
impl From<ParserError> for SessionError {
#[inline]
fn from(err: ParserError) -> Self {
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)]
}
}
-#[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<VarKey, HeapCellValue, FxBuildHasher>;
-
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
_ => self
.get_meta_predicate_spec(key.0, key.1, &compilation_target)
.map(|meta_specs| {
- meta_specs.iter().find(|meta_spec| {
- matches!(
- meta_spec,
- MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_)
- )
+ meta_specs.iter().find(|meta_spec| match meta_spec {
+ MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) => true,
+ _ => false,
})
})
.map(|meta_spec_opt| meta_spec_opt.is_some())
pub(super) e: usize,
pub(super) num_of_args: usize,
pub(super) cp: usize,
- pub(super) attr_var_init: AttrVarInitializer,
+ pub(crate) attr_var_init: AttrVarInitializer,
pub(super) fail: bool,
pub heap: Heap,
pub(super) mode: MachineMode,
)
}
-fn push_var_eq_functors<'a>(
+fn push_var_eq_functors(
heap: &mut Heap,
- iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
+ iter: impl Iterator<Item = (usize, VarPtr)>, // (&'a VarPtr, &'a HeapCellValue)>,
atom_tbl: &AtomTable,
) -> Vec<HeapCellValue> {
let mut list_of_var_eqs = vec![];
- for (var, binding) in iter {
- let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
+ for (var_loc, var_ptr) in iter { // (var, binding) in iter {
+ let var_atom = AtomTable::build_with(atom_tbl, &*var_ptr.borrow().to_string());
let h = heap.len();
+ let binding = heap[var_loc];
heap.push(atom_as_cell!(atom!("="), 2));
heap.push(atom_as_cell!(var_atom));
- heap.push(*binding);
+ heap.push(binding);
list_of_var_eqs.push(str_loc_as_cell!(h));
}
list_of_var_eqs
}
+
+pub(crate) fn copy_and_align_iter<Iter: Iterator<Item = HeapCellValue>>(
+ iter: Iter,
+ boundary: i64,
+ h: i64,
+) -> impl Iterator<Item = HeapCellValue> {
+ let diff = boundary - h;
+ iter.map(move |heap_value| heap_value - diff)
+}
+
#[derive(Debug)]
pub struct Ball {
pub(super) boundary: usize,
}
pub(super) fn copy_and_align(&self, h: usize) -> Heap {
- let diff = self.boundary as i64 - h as i64;
-
- self.stub
- .iter()
- .cloned()
- .map(|heap_value| heap_value - diff)
- .collect()
+ copy_and_align_iter(self.stub.iter().cloned(), self.boundary as i64, h as i64).collect()
}
}
}
#[derive(Debug)]
-pub(super) struct CopyBallTerm<'a> {
+pub(crate) struct CopyBallTerm<'a> {
attr_var_queue: &'a mut Vec<usize>,
stack: &'a mut Stack,
heap: &'a mut Heap,
}
impl<'a> CopyBallTerm<'a> {
- pub(super) fn new(
+ pub(crate) fn new(
attr_var_queue: &'a mut Vec<usize>,
stack: &'a mut Stack,
heap: &'a mut Heap,
pub fn write_read_term_options(
&mut self,
- mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
+ mut var_list: Vec<(VarPtr, HeapCellValue, usize)>,
singleton_var_list: Vec<HeapCellValue>,
) -> CallResult {
var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2));
let list_of_var_eqs = push_var_eq_functors(
&mut self.heap,
- var_list.iter().filter_map(|(var_name, var, _)| {
- if var_name.is_anon() {
+ var_list.iter().filter_map(|(var_ptr, var, _)| {
+ if var_ptr.is_anon() {
None
} else {
- Some((var_name, var))
+ let var_loc = var.get_value() as usize;
+ Some((var_loc, var_ptr.clone()))
}
}),
&self.atom_tbl,
Ok(unify_fn!(*self, var_names_offset, var_names_addr))
}
- pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
- let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
+ pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult {
+ let heap_loc = read_heap_cell!(self.heap[term.heap_loc],
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
- pstr_loc_as_cell!(term_write_result.heap_loc)
+ pstr_loc_as_cell!(term.heap_loc)
}
_ => {
- heap_loc_as_cell!(term_write_result.heap_loc)
+ heap_loc_as_cell!(term.heap_loc)
}
);
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<Ref, bool> = IndexMap::new();
- for cell in
- stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, heap_loc)
- {
+ for cell in eager_stackful_preorder_iter(&mut self.heap, heap_loc) {
let cell = unmark_cell_bits!(cell);
if let Some(var) = cell.as_var() {
let singleton_var_list = push_var_eq_functors(
&mut self.heap,
- term_write_result
- .var_dict
+ term.var_locs
.iter()
- .filter(|(var_name, binding)| {
- if var_name.is_anon() {
- return false;
+ .filter_map(|(var_loc, var_ptrs)| {
+ let var_ptr = var_ptrs.front().unwrap();
+
+ if var_ptr.is_anon() {
+ return None;
}
- if let Some(r) = binding.as_var() {
- *singleton_var_set.get(&r).unwrap_or(&false)
+ // add h to offset the term variable into its heap location.
+ let r = Ref::heap_cell(var_loc);
+
+ if singleton_var_set.get(&r).cloned().unwrap_or(false) {
+ Some((var_loc, var_ptr.clone()))
} else {
- false
+ None
}
}),
&self.atom_tbl,
);
+ /*
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
+ */
let mut var_list = Vec::with_capacity(singleton_var_set.len());
- for (var_name, addr) in term_write_result.var_dict {
- if let Some(var) = addr.as_var() {
- if let Some(idx) = singleton_var_set.get_index_of(&var) {
- var_list.push((var_name, addr, idx));
- }
+ for (var_loc, var_ptrs) in term.var_locs.iter() {
+ let var_ptr = var_ptrs.front().unwrap().clone();
+ let r = Ref::heap_cell(var_loc);
+ let cell = self.heap[var_loc];
+
+ if let Some(idx) = singleton_var_set.get_index_of(&r) {
+ var_list.push((var_ptr, cell, idx));
}
}
}
loop {
- match self.read(stream, &indices.op_dir) {
- Ok(term_write_result) => return self.read_term_body(term_write_result),
+ match self.read_to_heap(stream, &indices.op_dir) {
+ Ok(term) => return self.read_term_body(term),
Err(err) => {
match &err {
CompilationError::ParserError(e) if e.is_unexpected_eof() => {
}
);
+ let h = self.heap.len();
+ self.heap.push(term_to_be_printed);
+
let mut printer = HCPrinter::new(
&mut self.heap,
Arc::clone(&self.atom_tbl),
&mut self.stack,
op_dir,
PrinterOutputter::new(),
- term_to_be_printed,
+ h,
);
printer.ignore_ops = ignore_ops;
&mut self,
input_stream: Stream,
) -> Result<TermWriteResult, CompilationError> {
- self.machine_st.read(input_stream, &self.op_dir)
+ self.machine_st.read_to_heap(input_stream, &self.op_dir)
}
pub fn parse_and_write_parsed_term_to_heap(
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
+ let var_names = term_write_result
+ .var_locs
+ .iter()
+ .map(|(var_loc, var_ptrs)| {
+ (self.machine_st.heap[var_loc], var_ptrs.front().unwrap().clone())
+ })
+ .collect();
+
let mut printer = HCPrinter::new(
&mut self.machine_st.heap,
Arc::clone(&self.machine_st.atom_tbl),
&mut self.machine_st.stack,
&self.op_dir,
PrinterOutputter::new(),
- heap_loc_as_cell!(term_write_result.heap_loc),
+ term_write_result.heap_loc,
);
- printer.var_names = term_write_result
- .var_dict
- .into_iter()
- .map(|(var, cell)| match var {
- VarKey::VarPtr(var) => (cell, var.clone()),
- VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string())),
- })
- .collect();
+ printer.var_names = var_names;
Ok(printer.print().result())
}
input_stream: Stream,
op_dir: &OpDir,
) -> Result<TermWriteResult, CompilationError> {
- machine_st.read(input_stream, op_dir)
+ machine_st.read_to_heap(input_stream, op_dir)
}
#[cfg(test)]
wam.heap.clear();
{
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ let term_write_result_1 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
unify!(
wam,
- str_loc_as_cell!(1),
+ heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
wam.heap.clear();
{
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ let term_write_result_1 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
unify!(
wam,
- heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
wam.heap.clear();
{
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ let term_write_result_1 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
unify!(
wam,
- heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
wam.heap.clear();
{
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ let term_write_result_1 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
unify!(
wam,
- heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
wam.heap.clear();
{
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ let term_write_result_1 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
unify!(
wam,
- heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
wam.heap.push(heap_loc_as_cell!(0));
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
-
assert!(!wam.fail);
all_cells_unmarked(&wam.heap);
- wam.heap.clear();
-
- {
- let term_write_result_1 =
- parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
-
- print_heap_terms(wam.heap.iter(), term_write_result_1.heap_loc);
-
- unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
-
- assert_eq!(wam.heap[2], str_loc_as_cell!(4));
- }
}
#[test]
unify_with_occurs_check!(
wam,
- str_loc_as_cell!(0),
- str_loc_as_cell!(term_write_result_2.heap_loc)
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(wam.fail);
use crate::machine::disjuncts::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::*;
+use crate::machine::CodeIndex;
use crate::parser::ast::*;
+use crate::types::*;
+use fxhash::FxBuildHasher;
+use indexmap::IndexMap;
use indexmap::IndexSet;
-use std::cell::Cell;
use std::convert::TryFrom;
pub(crate) fn to_op_decl(prec: u16, spec: OpDeclSpec, name: Atom) -> OpDecl {
OpDecl::new(OpDesc::build_with(prec, spec), name)
})
}
-fn setup_op_decl(mut terms: Vec<Term>, atom_tbl: &AtomTable) -> Result<OpDecl, CompilationError> {
- // should allow non-partial lists?
- let name = match terms.pop().unwrap() {
- Term::Literal(_, Literal::Atom(name)) => name,
- Term::Literal(_, Literal::Char(c)) => AtomTable::build_with(atom_tbl, &c.to_string()),
- other => {
- return Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidOpDeclNameType(other),
- ));
- }
- };
+fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> {
+ let (focus, _cell) = subterm_index(term.heap, term.focus);
- let spec = match terms.pop().unwrap() {
- Term::Literal(_, Literal::Atom(name)) => name,
- other => {
- return Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidOpDeclSpecDomain(other),
- ))
- }
+ let name = match term.name(focus+3) {
+ Some(name) => name,
+ None => return Err(CompilationError::InconsistentEntry),
};
- let spec = to_op_decl_spec(spec)?;
+ let spec = match term.name(focus+2) {
+ Some(name) => name,
+ None => return Err(CompilationError::InconsistentEntry),
+ };
- let prec = match terms.pop().unwrap() {
- Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) {
- Ok(n) if n <= 1200 => n,
- _ => {
- return Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidOpDeclPrecDomain(bi),
- ));
+ let prec = read_heap_cell!(term.deref_loc(focus+1),
+ (HeapCellValueTag::Fixnum, n) => {
+ match u16::try_from(n.get_num()) {
+ Ok(n) if n <= 1200 => n,
+ _ => return Err(CompilationError::InconsistentEntry),
}
- },
- other => {
- return Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidOpDeclPrecType(other),
- ));
}
- };
+ _ => {
+ return Err(CompilationError::InconsistentEntry);
+ }
+ );
if name == "[]" || name == "{}" {
return Err(CompilationError::InvalidDirective(
Ok(to_op_decl(prec, spec, name))
}
-fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
- match term {
- Term::Clause(_, slash, ref mut terms)
- if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 =>
- {
- let arity = terms.pop().unwrap();
- let name = terms.pop().unwrap();
-
- let arity = match arity {
- Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(),
- Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
- _ => None,
- }
- .ok_or(CompilationError::InvalidModuleExport)?;
+fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result<PredicateKey, CompilationError> {
+ let name_opt = term.name(term.focus);
+ let arity = term.arity(term.focus);
- let name = match name {
- Term::Literal(_, Literal::Atom(name)) => Some(name),
- _ => None,
- }
+ if let (Some(atom!("/") | atom!("//")), 2) = (name_opt, arity) {
+ let arity_loc = term.nth_arg(term.focus, 2).unwrap();
+
+ let arity = match Number::try_from(term.deref_loc(arity_loc)) {
+ Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
+ Ok(Number::Integer(n)) => (&*n).try_into().ok(),
+ _ => None,
+ }
+ .ok_or(CompilationError::InvalidModuleExport)?;
+
+ let name_loc = term.nth_arg(term.focus, 1).unwrap();
+ let name = term
+ .name(name_loc)
.ok_or(CompilationError::InvalidModuleExport)?;
- if *slash == atom!("/") {
- Ok((name, arity))
- } else {
- Ok((name, arity + 2))
- }
+ if name_opt == Some(atom!("/")) {
+ Ok((name, arity))
+ } else {
+ Ok((name, arity + 2))
}
- _ => Err(CompilationError::InvalidModuleExport),
+ } else {
+ Err(CompilationError::InvalidModuleExport)
}
}
-fn setup_module_export(
- mut term: Term,
- atom_tbl: &AtomTable,
-) -> Result<ModuleExport, CompilationError> {
- setup_predicate_indicator(&mut term)
+fn setup_module_export(term: &FocusedHeapRefMut) -> Result<ModuleExport, CompilationError> {
+ setup_predicate_indicator(term)
.map(ModuleExport::PredicateKey)
.or_else(|_| {
- if let Term::Clause(_, name, terms) = term {
- if terms.len() == 3 && name == atom!("op") {
- Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?))
- } else {
- Err(CompilationError::InvalidModuleDecl)
- }
+ let name_opt = term.name(term.focus);
+ let arity = term.arity(term.focus);
+
+ if let (Some(atom!("op")), 3) = (name_opt, arity) {
+ Ok(ModuleExport::OpDecl(setup_op_decl(term)?))
} else {
Err(CompilationError::InvalidModuleDecl)
}
})
}
+/* TODO: should be unnecessary now.
+
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
let head_term = Term::Clause(Cell::default(), atom!(""), vars.to_vec());
let rule = vec![head_term, body_term];
Term::Clause(Cell::default(), atom!(":-"), rule)
}
+*/
pub(super) fn setup_module_export_list(
- mut export_list: Term,
- atom_tbl: &AtomTable,
+ term: FocusedHeapRefMut,
) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![];
-
- while let Term::Cons(_, t1, t2) = export_list {
- let module_export = setup_module_export(*t1, atom_tbl)?;
-
- exports.push(module_export);
- export_list = *t2;
+ let mut focus = term.focus;
+
+ loop {
+ read_heap_cell!(term.heap[focus],
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if h == focus {
+ break;
+ } else {
+ focus = h;
+ }
+ }
+ (HeapCellValueTag::Lis, l) => {
+ let term = FocusedHeapRefMut {
+ heap: term.heap,
+ focus: l,
+ };
+ exports.push(setup_module_export(&term)?);
+
+ focus = l + 1;
+ }
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ if name == atom!("[]") {
+ return Ok(exports);
+ } else {
+ break;
+ }
+ }
+ _ => {
+ break;
+ }
+ );
}
- if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
- Ok(exports)
- } else {
- Err(CompilationError::InvalidModuleDecl)
- }
+ Err(CompilationError::InvalidModuleDecl)
}
-fn setup_module_decl(
- mut terms: Vec<Term>,
- atom_tbl: &AtomTable,
-) -> Result<ModuleDecl, CompilationError> {
- let export_list = terms.pop().unwrap();
- let name = terms.pop().unwrap();
-
- let name = match name {
- Term::Literal(_, Literal::Atom(name)) => Some(name),
- _ => None,
- }
- .ok_or(CompilationError::InvalidModuleDecl)?;
-
- let exports = setup_module_export_list(export_list, atom_tbl)?;
+fn setup_module_decl(term: FocusedHeapRefMut) -> Result<ModuleDecl, CompilationError> {
+ let name = term
+ .name(term.focus + 1)
+ .ok_or(CompilationError::InvalidModuleDecl)?;
+ let export_list = FocusedHeapRefMut {
+ heap: term.heap,
+ focus: term.focus + 2,
+ };
+ let exports = setup_module_export_list(export_list)?;
Ok(ModuleDecl { name, exports })
}
-fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
- match terms.pop().unwrap() {
- Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
- match terms.pop().unwrap() {
- Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
- _ => Err(CompilationError::InvalidModuleDecl),
+fn setup_use_module_decl(term: &FocusedHeapRefMut) -> Result<ModuleSource, CompilationError> {
+ read_heap_cell!(term.deref_loc(term.focus+1),
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity();
+
+ if (name, arity) == (atom!("library"), 1) {
+ read_heap_cell!(term.deref_loc(s+1),
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ return Ok(ModuleSource::Library(name));
+ }
+ }
+ _ => {
+ }
+ )
}
+
+ return Err(CompilationError::InvalidModuleDecl);
}
- Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
- _ => Err(CompilationError::InvalidUseModuleDecl),
- }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ Ok(ModuleSource::File(name))
+ } else {
+ Err(CompilationError::InvalidUseModuleDecl)
+ }
+ }
+ _ => {
+ Err(CompilationError::InvalidUseModuleDecl)
+ }
+ )
}
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
-fn setup_qualified_import(
- mut terms: Vec<Term>,
- atom_tbl: &AtomTable,
-) -> Result<UseModuleExport, CompilationError> {
- let mut export_list = terms.pop().unwrap();
- let module_src = match terms.pop().unwrap() {
- Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
- match terms.pop().unwrap() {
- Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
- _ => Err(CompilationError::InvalidModuleDecl),
- }
- }
- Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
- _ => Err(CompilationError::InvalidUseModuleDecl),
- }?;
-
+fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, CompilationError> {
+ let module_src = setup_use_module_decl(&term)?;
let mut exports = IndexSet::new();
- while let Term::Cons(_, t1, t2) = export_list {
- exports.insert(setup_module_export(*t1, atom_tbl)?);
- export_list = *t2;
+ let mut focus = term.focus + 2;
+
+ while let HeapCellValueTag::Lis = term.heap[focus].get_tag() {
+ focus = term.heap[focus].get_value() as usize;
+
+ let term = FocusedHeapRefMut {
+ heap: term.heap,
+ focus,
+ };
+ exports.insert(setup_module_export(&term)?);
+
+ focus = focus + 1;
}
- if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
+ if term.heap[focus] == empty_list_as_cell!() {
Ok((module_src, exports))
} else {
Err(CompilationError::InvalidModuleDecl)
*/
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
- mut terms: Vec<Term>,
+ term: FocusedHeapRefMut,
loader: &mut Loader<'a, LS>,
) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
- fn get_name_and_meta_specs(
- name: Atom,
- terms: &mut [Term],
- ) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
+ fn get_meta_specs(
+ term: FocusedHeapRefMut,
+ arity: usize,
+ ) -> Result<Vec<MetaSpec>, CompilationError> {
let mut meta_specs = vec![];
- for meta_spec in terms.iter_mut() {
- match meta_spec {
- Term::Literal(_, Literal::Atom(meta_spec)) => {
+ for meta_spec_loc in term.focus + 1..term.focus + arity + 1 {
+ read_heap_cell!(term.deref_loc(meta_spec_loc),
+ (HeapCellValueTag::Atom, (meta_spec, arity)) => {
+ debug_assert_eq!(arity, 0);
+
let meta_spec = match meta_spec {
atom!("+") => MetaSpec::Plus,
atom!("-") => MetaSpec::Minus,
meta_specs.push(meta_spec);
}
- Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
- Ok(n) if n <= MAX_ARITY => {
- meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
- }
- _ => {
- return Err(CompilationError::InvalidMetaPredicateDecl);
+ (HeapCellValueTag::Fixnum, n) => {
+ match usize::try_from(n.get_num()) {
+ Ok(n) if n <= MAX_ARITY => {
+ meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
+ }
+ _ => {
+ return Err(CompilationError::InvalidMetaPredicateDecl);
+ }
}
- },
+ }
_ => {
return Err(CompilationError::InvalidMetaPredicateDecl);
}
- }
+ );
}
- Ok((name, meta_specs))
+ Ok(meta_specs)
}
- match terms.pop().unwrap() {
- Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => {
- let spec = terms.pop().unwrap();
- let module_name = terms.pop().unwrap();
-
- match module_name {
- Term::Literal(_, Literal::Atom(module_name)) => match spec {
- Term::Clause(_, name, mut terms) => {
- let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
- Ok((module_name, name, meta_specs))
- }
- _ => Err(CompilationError::InvalidMetaPredicateDecl),
- },
- _ => Err(CompilationError::InvalidMetaPredicateDecl),
+ read_heap_cell!(term.deref_loc(term.focus+1),
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity();
+
+ match (name, arity) {
+ (atom!(":"), 2) => {
+ let module_name = term.heap[s+1];
+ let spec = term.heap[s+2];
+
+ read_heap_cell!(module_name,
+ (HeapCellValueTag::Atom, (module_name, arity)) => {
+ if arity == 0 {
+ read_heap_cell!(spec,
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(term.heap[s])
+ .get_name_and_arity();
+
+ let term = FocusedHeapRefMut { heap: term.heap, focus: s };
+ return Ok((module_name, name, get_meta_specs(term, arity)?));
+ }
+ _ => {
+ }
+ );
+ } else {
+ return Err(CompilationError::InvalidMetaPredicateDecl);
+ }
+ }
+ _ => {
+ }
+ );
+ }
+ _ => {
+ let term = FocusedHeapRefMut { heap: term.heap, focus: s };
+ let module_name = loader.payload.compilation_target.module_name();
+ return Ok((module_name, name, get_meta_specs(term, arity)?));
+ }
}
+
+ Err(CompilationError::InvalidMetaPredicateDecl)
}
- Term::Clause(_, name, mut terms) => {
- let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
- Ok((
- loader.payload.compilation_target.module_name(),
- name,
- meta_specs,
- ))
+ _ => {
+ Err(CompilationError::InvalidMetaPredicateDecl)
}
- _ => Err(CompilationError::InvalidMetaPredicateDecl),
- }
+ )
}
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
- mut terms: Vec<Term>,
+ term: FocusedHeapRefMut,
) -> Result<Declaration, CompilationError> {
- let term = terms.pop().unwrap();
+ let mut focus = term.focus;
- match term {
- Term::Clause(_, name, mut terms) => match (name, terms.len()) {
- (atom!("dynamic"), 1) => {
- let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
- Ok(Declaration::Dynamic(name, arity))
- }
- (atom!("module"), 2) => {
- let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
- Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?))
- }
- (atom!("op"), 3) => {
- let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
- Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?))
+ loop {
+ read_heap_cell!(term.heap[focus],
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ let term = FocusedHeapRefMut { heap: term.heap, focus };
+
+ return match (name, arity) {
+ (atom!("dynamic"), 1) => {
+ let (name, arity) = setup_predicate_indicator(&term)?;
+ Ok(Declaration::Dynamic(name, arity))
+ }
+ (atom!("module"), 2) => {
+ Ok(Declaration::Module(setup_module_decl(term)?))
+ }
+ (atom!("op"), 3) => {
+ Ok(Declaration::Op(setup_op_decl(&term)?))
+ }
+ (atom!("non_counted_backtracking"), 1) => {
+ let focus = term.nth_arg(term.focus, 1).unwrap();
+ let (name, arity) = setup_predicate_indicator(&FocusedHeapRefMut { heap: term.heap, focus })?;
+ Ok(Declaration::NonCountedBacktracking(name, arity))
+ }
+ (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&term)?)),
+ (atom!("use_module"), 2) => {
+ let (name, exports) = setup_qualified_import(term)?;
+
+ Ok(Declaration::UseQualifiedModule(name, exports))
+ }
+ (atom!("meta_predicate"), 1) => {
+ let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?;
+ Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
+ }
+ _ => Err(CompilationError::InvalidDirective(
+ DirectiveError::InvalidDirective(name, arity)
+ ))
+ };
}
- (atom!("non_counted_backtracking"), 1) => {
- let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
- Ok(Declaration::NonCountedBacktracking(name, arity))
+ (HeapCellValueTag::Str, s) => {
+ focus = s;
}
- (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
- (atom!("use_module"), 2) => {
- let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
- let (name, exports) = setup_qualified_import(terms, atom_tbl)?;
-
- Ok(Declaration::UseQualifiedModule(name, exports))
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if focus != h {
+ focus = h;
+ } else {
+ return Err(CompilationError::InvalidDirective(
+ DirectiveError::ExpectedDirective(heap_loc_as_cell!(h)),
+ ));
+ }
}
- (atom!("meta_predicate"), 1) => {
- let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
- Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
+ _ => {
+ return Err(CompilationError::InvalidDirective(
+ DirectiveError::ExpectedDirective(term.heap[focus])
+ ));
}
- _ => Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidDirective(name, terms.len()),
- )),
- },
- other => Err(CompilationError::InvalidDirective(
- DirectiveError::ExpectedDirective(other),
- )),
+ );
}
}
fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
module_name: Atom,
- terms: Vec<Term>,
+ arity: usize,
+ term: &FocusedHeapRefMut,
meta_specs: Vec<MetaSpec>,
-) -> Vec<Term> {
- let mut arg_terms = Vec::with_capacity(terms.len());
+) -> IndexMap<usize, CodeIndex, FxBuildHasher> {
+ let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default());
- for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) {
+ for (subterm_loc, meta_spec) in (term.focus + 1..term.focus + arity + 1).zip(meta_specs) {
if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
- if let Some(name) = term.name() {
+ if let Some(name) = term.name(subterm_loc) {
if name == atom!("$call") {
- arg_terms.push(term);
continue;
}
- let arity = term.arity();
+ let arity = term.arity(subterm_loc);
+
+ struct QualifiedNameInfo {
+ module_name: Atom,
+ name: Atom,
+ qualified_term_loc: usize,
+ }
fn get_qualified_name(
- module_term: &Term,
- qualified_term: &Term,
- ) -> Option<(Atom, Atom)> {
- if let Term::Literal(_, Literal::Atom(module_name)) = module_term {
- if let Some(name) = qualified_term.name() {
- return Some((*module_name, name));
+ term: &FocusedHeapRefMut,
+ module_term_loc: usize,
+ qualified_term_loc: usize,
+ ) -> Option<QualifiedNameInfo> {
+ let (module_term_loc, _) = subterm_index(term.heap, module_term_loc);
+ let (qualified_term_loc, _) = subterm_index(term.heap, qualified_term_loc);
+
+ read_heap_cell!(term.heap[module_term_loc],
+ (HeapCellValueTag::Atom, (module_name, arity)) => {
+ if arity == 0 {
+ if let Some(name) = term.name(qualified_term_loc) {
+ return Some(QualifiedNameInfo {
+ module_name,
+ name,
+ qualified_term_loc,
+ });
+ }
+ }
}
- }
+ _ => {}
+ );
None
}
- fn identity_fn(_module_name: Atom, term: Term) -> Term {
- term
- }
+ let (subterm_loc, _) = subterm_index(term.heap, subterm_loc);
- fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
- Term::Clause(
- Cell::default(),
- atom!(":"),
- vec![
- Term::Literal(Cell::default(), Literal::Atom(module_name)),
- term,
- ],
- )
- }
+ let subterm_arity = term.arity(subterm_loc);
+ let subterm_name_opt = term.name(subterm_loc);
- let process_term: fn(Atom, Term) -> Term;
+ let (module_name, key, term_loc) =
+ if subterm_name_opt == Some(atom!(":")) && subterm_arity == 2 {
+ debug_assert_eq!(term.heap[subterm_loc].get_tag(), HeapCellValueTag::Atom);
- let (module_name, key, term) = match term {
- Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => {
- if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1])
- {
- process_term = tag_with_module_name;
- (
+ match get_qualified_name(term, subterm_loc + 1, subterm_loc + 2) {
+ Some(QualifiedNameInfo {
module_name,
- (name, terms[1].arity() + supp_args),
- terms.pop().unwrap(),
- )
- } else {
- arg_terms.push(Term::Clause(cell, atom!(":"), terms));
- continue;
- }
- }
- term => {
- process_term = identity_fn;
- (module_name, (name, arity + supp_args), term)
- }
- };
-
- let term = match term {
- Term::Clause(cell, name, mut terms) => {
- if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
- arg_terms
- .push(process_term(module_name, Term::Clause(cell, name, terms)));
-
- continue;
- }
-
- let idx = loader.get_or_insert_qualified_code_index(module_name, key);
-
- terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
- process_term(module_name, Term::Clause(cell, name, terms))
- }
- Term::Literal(cell, Literal::Atom(name)) => {
- let idx = loader.get_or_insert_qualified_code_index(module_name, key);
-
- process_term(
- module_name,
- Term::Clause(
- cell,
name,
- vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
+ qualified_term_loc,
+ }) => (
+ module_name,
+ (name, term.arity(qualified_term_loc) + supp_args),
+ qualified_term_loc,
),
- )
- }
- term => term,
- };
+ None => {
+ continue;
+ }
+ }
+ } else {
+ (module_name, (name, arity + supp_args), subterm_loc)
+ };
- arg_terms.push(term);
- continue;
+ if let Some(index_ptr) = fetch_index_ptr(term.heap, key.1, term_loc) {
+ index_ptrs.insert(term_loc, index_ptr);
+ continue;
+ }
+
+ index_ptrs.insert(
+ term_loc,
+ loader.get_or_insert_qualified_code_index(module_name, key),
+ );
}
}
-
- arg_terms.push(term);
}
- arg_terms
+ index_ptrs
}
#[inline]
pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
- name: Atom,
- mut terms: Vec<Term>,
+ key: PredicateKey,
+ terms: FocusedHeapRefMut,
+ term: HeapCellValue,
call_policy: CallPolicy,
-) -> QueryTerm {
- if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
- // supplementary code vector indices are unnecessary for
- // root-level clauses.
- terms.pop();
- }
+) -> QueryClause {
+ // supplementary code vector indices are unnecessary for
+ // root-level clauses.
+ blunt_index_ptr(terms.heap, key, terms.focus);
- let mut ct = loader.get_clause_type(name, terms.len());
+ let mut ct = loader.get_clause_type(key.0, key.1);
if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let module_name = loader.payload.compilation_target.module_name();
- let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
-
- return QueryTerm::Clause(
- Cell::default(),
- ClauseType::Named(arity, name, idx),
- terms,
+ let code_indices =
+ build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs);
+
+ return QueryClause {
+ ct: ClauseType::Named(key.1, key.0, idx),
+ arity,
+ term,
+ code_indices,
call_policy,
- );
+ };
}
- ct = ClauseType::Named(arity, name, idx);
+ ct = ClauseType::Named(key.1, key.0, idx);
}
- QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
+ QueryClause {
+ ct,
+ arity: key.1,
+ term,
+ code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
+ call_policy,
+ }
}
#[inline]
pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
+ key: PredicateKey,
module_name: Atom,
- name: Atom,
- mut terms: Vec<Term>,
+ terms: FocusedHeapRefMut,
+ term: HeapCellValue,
call_policy: CallPolicy,
-) -> QueryTerm {
- if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
- // supplementary code vector indices are unnecessary for
- // root-level clauses.
- terms.pop();
- }
+) -> QueryClause {
+ // supplementary code vector indices are unnecessary for
+ // root-level clauses.
+ blunt_index_ptr(terms.heap, key, terms.focus);
- let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len());
+ let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1);
if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
- let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
-
- return QueryTerm::Clause(
- Cell::default(),
- ClauseType::Named(arity, name, idx),
- terms,
+ let code_indices =
+ build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs);
+
+ return QueryClause {
+ ct: ClauseType::Named(key.1, key.0, idx),
+ arity,
+ term,
+ code_indices,
call_policy,
- );
+ };
}
- ct = ClauseType::Named(arity, name, idx);
+ ct = ClauseType::Named(key.1, key.0, idx);
}
- QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
+ QueryClause {
+ ct,
+ arity: key.1,
+ term,
+ code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
+ call_policy,
+ }
}
#[derive(Debug)]
Preprocessor { settings }
}
- fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
- match term {
- Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
- let classifier = VariableClassifier::new(self.settings.default_call_policy());
-
- let (head, var_data) = classifier.classify_fact(term)?;
- Ok((Fact { head }, var_data))
- }
- _ => Err(CompilationError::InadmissibleFact),
+ pub fn setup_fact(
+ &mut self,
+ mut term: FocusedHeap,
+ ) -> Result<(Fact, VarData), CompilationError> {
+ if term.name(term.focus).is_some() {
+ let classifier = VariableClassifier::new(self.settings.default_call_policy());
+ let var_data = classifier.classify_fact(&mut term)?;
+
+ Ok((Fact { term }, var_data))
+ } else {
+ Err(CompilationError::InadmissibleFact)
}
}
fn setup_rule<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
- head: Term,
- body: Term,
+ mut term: FocusedHeap,
) -> Result<(Rule, VarData), CompilationError> {
let classifier = VariableClassifier::new(self.settings.default_call_policy());
+ let (clauses, var_data) = classifier.classify_rule(loader, &mut term)?;
+ let head_loc = term.nth_arg(term.focus, 1).unwrap();
- let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
-
- match head {
- Term::Clause(_, name, terms) => Ok((
- Rule {
- head: (name, terms),
- clauses,
- },
- var_data,
- )),
- Term::Literal(_, Literal::Atom(name)) => Ok((
- Rule {
- head: (name, vec![]),
- clauses,
- },
- var_data,
- )),
- _ => Err(CompilationError::InvalidRuleHead),
+ if term.name(head_loc).is_some() {
+ Ok((Rule { term, clauses }, var_data))
+ } else {
+ Err(CompilationError::InvalidRuleHead)
}
}
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
- term: Term,
+ term: FocusedHeap,
) -> Result<TopLevel, CompilationError> {
- match term {
- Term::Clause(r, name, mut terms) => {
- let is_rule = name == atom!(":-") && terms.len() == 2;
-
- if is_rule {
- let tail = terms.pop().unwrap();
- let head = terms.pop().unwrap();
+ let name = term.name(term.focus);
+ let arity = term.arity(term.focus);
- let (rule, var_data) = self.setup_rule(loader, head, tail)?;
- Ok(TopLevel::Rule(rule, var_data))
- } else {
- let term = Term::Clause(r, name, terms);
- let (fact, var_data) = self.setup_fact(term)?;
- Ok(TopLevel::Fact(fact, var_data))
- }
+ match (name, arity) {
+ (Some(atom!(":-")), 2) => {
+ let (rule, var_data) = self.setup_rule(loader, term)?;
+ Ok(TopLevel::Rule(rule, var_data))
}
- term => {
+ _ => {
let (fact, var_data) = self.setup_fact(term)?;
Ok(TopLevel::Fact(fact, var_data))
}
impl<T: RawBlockTraits> RawBlock<T> {
pub(crate) fn new() -> Self {
- let mut block = RawBlock {
- size: 0,
- base: ptr::null(),
- top: ptr::null(),
- _marker: PhantomData,
- };
+ let mut block = Self::uninitialized();
unsafe {
block.grow();
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());
}
}
+ 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 {
) -> Result<Stream, ParserError> {
match stream.peek_char() {
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
- Some(Err(e)) => Err(ParserError::IO(e)),
+ Some(Err(e)) => Err(ParserError::IO(e, ParserErrorSrc::default())),
Some(Ok(c)) => {
if c == '\u{feff}' {
// skip UTF-8 BOM
use crate::machine::streams::*;
use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC};
use crate::parser::char_reader::*;
-use crate::parser::dashu::Integer;
+use crate::parser::dashu::{Integer, Rational};
use crate::read::*;
use crate::types::*;
use rand::rngs::StdRng;
) {
let mut seen_set = IndexSet::new();
- {
- let mut iter =
- stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term);
+ let outcome = if term.is_ref() {
+ {
+ let mut iter = stackful_post_order_iter::<NonListElider>(
+ &mut self.heap, &mut self.stack, term.get_value() as usize,
+ );
- while let Some(value) = iter.next() {
- if iter.parent_stack_len() >= max_depth {
- iter.pop_stack();
- continue;
- }
+ while let Some(value) = iter.next() {
+ if iter.parent_stack_len() >= max_depth {
+ iter.pop_stack();
+ continue;
+ }
- let value = unmark_cell_bits!(value);
+ let value = unmark_cell_bits!(value);
- if value.is_var() {
- seen_set.insert(value);
+ if value.is_var() {
+ seen_set.insert(value);
+ }
}
}
- }
- let outcome = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter(),));
+ heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter()))
+ } else {
+ empty_list_as_cell!()
+ };
unify_fn!(*self, list_of_vars, outcome);
}
tokens.reverse();
match parser.read_term(&op_dir, Tokens::Provided(tokens)) {
- Err(err) => {
- let err = self.syntax_error(err);
- return Err(self.error_form(err, stub_gen()));
- }
- Ok(Term::Literal(_, Literal::Rational(n))) => {
- self.unify_rational(n, nx);
- }
- Ok(Term::Literal(_, Literal::Float(n))) => {
- self.unify_f64(n.as_ptr(), nx);
- }
- Ok(Term::Literal(_, Literal::Integer(n))) => {
- self.unify_big_int(n, nx);
- }
- Ok(Term::Literal(_, Literal::Fixnum(n))) => {
- self.unify_fixnum(n, nx);
- }
- _ => {
- let err = ParserError::ParseBigInt(0, 0);
- let err = self.syntax_error(err);
+ Ok(term) => {
+ let mut error_gen = || {
+ let e = ParserError::ParseBigInt(ParserErrorSrc::default());
+ let e = self.syntax_error(e);
+
+ return Err(self.error_form(e, stub_gen()));
+ };
- return Err(self.error_form(err, stub_gen()));
+ read_heap_cell!(term.heap[term.focus],
+ (HeapCellValueTag::Cons, c) => {
+ match_untyped_arena_ptr!(c,
+ (ArenaHeaderTag::Rational, n) => {
+ self.unify_rational(n, nx);
+ }
+ (ArenaHeaderTag::Integer, n) => {
+ self.unify_big_int(n, nx);
+ }
+ _ => {
+ return error_gen();
+ }
+ )
+ }
+ (HeapCellValueTag::F64, n) => {
+ self.unify_f64(n, nx);
+ }
+ (HeapCellValueTag::Fixnum, n) => {
+ self.unify_fixnum(n, nx);
+ }
+ _ => {
+ return error_gen();
+ }
+ );
+ }
+ Err(e) => {
+ let e = self.syntax_error(e);
+ return Err(self.error_form(e, stub_gen()));
}
}
lexer.skip_char('.');
}
Ok(c) => {
- let (line_num, col_num) = (lexer.line_num, lexer.col_num);
+ let err_src = lexer.loc_to_err_src();
- let err = ParserError::UnexpectedChar(c, line_num, col_num);
+ let err = ParserError::UnexpectedChar(c, err_src);
let err = self.syntax_error(err);
return Err(self.error_form(err, stub_gen()));
.get_predicate_code_index(name, arity, module_name)
});
+ // println!("(fast) calling {}/{}", name.as_str(), arity);
+
if let Some(code_index) = index_cell {
if !code_index.is_undefined() {
load_registers(&mut self.machine_st, goal, goal_arity);
let vars: Vec<_> = vars
.union(&result.supp_vars) // difference + union does not cancel.
- .map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value()))))
+ .cloned()
.collect();
let helper_clause_loc = self.code.len();
- match self.compile_standalone_clause(temp_v!(1), &vars) {
+ match self.compile_standalone_clause(temp_v!(1), vars) {
Err(e) => {
let err = self.machine_st.session_error(e);
let stub = functor_stub(atom!("call"), result.key.1);
}
Some(Err(e)) => {
let stub = functor_stub(atom!("$get_n_chars"), 3);
- let err = self.machine_st.session_error(SessionError::from(e));
+ let err = self.machine_st.session_error(SessionError::from(
+ ParserError::IO(e, ParserErrorSrc::default()),
+ ));
return Err(self.machine_st.error_form(err, stub));
}
}
#[inline(always)]
- fn read_term_and_write_to_heap(
+ fn read_term_from_atom(
&mut self,
atom_or_string: AtomOrString,
- ) -> Result<Option<TermWriteResult>, MachineStub> {
+ ) -> Result<Option<FocusedHeap>, MachineStub> {
let string = match atom_or_string {
AtomOrString::Atom(atom!("[]")) => "".to_owned(),
_ => atom_or_string.into(),
let mut parser = Parser::new(chars, &mut self.machine_st);
let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
- let term_write_result = parser
+ let term = parser
.read_term(&op_dir, Tokens::Default)
- .map_err(|err| error_after_read_term(err, 0, &parser))
- .and_then(|term| {
- write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl)
- });
+ .map_err(|e| error_after_read_term(e, 0));
- match term_write_result {
- Ok(term_write_result) => Ok(Some(term_write_result)),
+ match term {
+ Ok(term) => Ok(Some(term)),
Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => {
let value = self.machine_st.registers[2];
self.machine_st.unify_atom(atom!("end_of_file"), value);
#[inline(always)]
pub(crate) fn read_from_chars(&mut self) -> CallResult {
- if let Some(atom_or_string) = self
+ let atom_or_string = self
.machine_st
.value_to_str_like(self.machine_st.registers[1])
- {
- if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
- let result = heap_loc_as_cell!(term_write_result.heap_loc);
- let var = self.deref_register(2).as_var().unwrap();
+ .unwrap();
- self.machine_st.bind(var, result);
- }
+ if let Some(mut term) = self.read_term_from_atom(atom_or_string)? {
+ let heap_len = self.machine_st.heap.len();
- Ok(())
- } else {
- unreachable!()
+ self.machine_st.heap.extend(
+ copy_and_align_iter(term.heap.drain(..), 0, heap_len as i64),
+ );
+
+ let result = heap_loc_as_cell!(heap_len + term.focus);
+ let var = self.deref_register(2).as_var().unwrap();
+
+ self.machine_st.bind(var, result);
}
+
+ Ok(())
}
#[inline(always)]
pub(crate) fn read_term_from_chars(&mut self) -> CallResult {
- if let Some(atom_or_string) = self
+ let atom_or_string = self
.machine_st
.value_to_str_like(self.machine_st.registers[1])
- {
- if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
- self.machine_st.read_term_body(term_write_result)
- } else {
- if !self.machine_st.fail {
- // wrote end_of_file term in this case.
- self.machine_st.write_read_term_options(vec![], vec![])?;
- }
+ .unwrap();
- Ok(())
- }
- } else {
- unreachable!()
- }
+ let string = match atom_or_string {
+ AtomOrString::Atom(atom!("[]")) => "".to_owned(),
+ _ => atom_or_string.into(),
+ };
+
+ let chars = CharReader::new(ByteStream::from_string(string));
+ let term_write_result = self.machine_st.read(chars, &self.indices.op_dir)
+ .map(|(term, _)| term.to_machine_heap(&mut self.machine_st))
+ .map_err(|e| {
+ let e = self.machine_st.session_error(SessionError::from(e));
+ let stub = functor_stub(atom!("read_term_from_chars"), 3);
+
+ self.machine_st.error_form(e, stub)
+ })?;
+
+ self.machine_st.read_term_body(term_write_result)
}
#[inline(always)]
match devour_whitespace(&mut parser) {
Ok(false) => {
- // not at EOF.
+ // not at EOF ...
stream.add_lines_read(parser.lines_read());
+
+ // ... unless we are.
+ if stream.at_end_of_stream() {
+ self.machine_st.fail = true;
+ }
}
Ok(true) => {
stream.add_lines_read(parser.lines_read());
pub(super) module_op_exports: ModuleOpExports,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey, FxBuildHasher>,
pub(super) predicates: PredicateQueue,
- pub(super) clause_clauses: Vec<(Term, Term)>,
+ pub(super) clause_clauses: Vec<FocusedHeap>,
}
pub trait TermStream: Sized {
- fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
+ fn next(&mut self, op_dir: &CompositeOpDir) -> Result<FocusedHeap, CompilationError>;
fn eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource;
}
impl<'a> TermStream for BootstrappingTermStream<'a> {
#[inline]
- fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
+ fn next(&mut self, op_dir: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
self.parser.reset();
self.parser
.read_term(op_dir, Tokens::Default)
}
pub struct LiveTermStream {
- pub(super) term_queue: VecDeque<Term>,
+ pub(super) term_queue: VecDeque<FocusedHeap>,
pub(super) listing_src: ListingSource,
}
impl TermStream for LiveTermStream {
#[inline]
- fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
+ fn next(&mut self, _: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
Ok(self.term_queue.pop_front().unwrap())
}
pub struct InlineTermStream {}
impl TermStream for InlineTermStream {
- fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
- Err(CompilationError::from(ParserError::unexpected_eof()))
+ fn next(&mut self, _: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
+ Err(CompilationError::from(ParserError::unexpected_eof(ParserErrorSrc::default())))
}
fn eof(&mut self) -> Result<bool, CompilationError> {
let mut occurs_triggered = false;
- if !value.is_constant() {
- let machine_st: &mut MachineState = unifier.deref_mut();
+ let machine_st: &mut MachineState = unifier.deref_mut();
+ let value = machine_st.store(MachineState::deref(machine_st, value));
+
+ if value.is_ref() && !value.is_stack_var() {
+ let root_loc = value.get_value() as usize;
for cell in stackful_preorder_iter::<NonListElider>(
&mut machine_st.heap,
&mut machine_st.stack,
- value,
+ root_loc, // value,
) {
let cell = unmark_cell_bits!(cell);
#[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)]
use crate::arena::*;
use crate::atom_table::*;
+use crate::forms::PredicateKey;
+use crate::machine::copier::*;
+use crate::machine::heap::*;
use crate::machine::machine_indices::*;
-use crate::parser::char_reader::*;
-use crate::types::HeapCellValueTag;
+use crate::machine::machine_state::*;
+use crate::types::*;
-use std::cell::{Cell, Ref, RefCell, RefMut};
+use std::cell::{Ref, RefCell, RefMut};
+use std::collections::VecDeque;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::io::{Error as IOError, ErrorKind};
-use std::ops::{Deref, Neg};
+use std::ops::{Deref, Neg, RangeBounds};
use std::rc::Rc;
use std::sync::Arc;
use std::vec::Vec;
UninstantiatedVar,
}
-#[allow(dead_code)]
+#[derive(Debug, Copy, Clone, Default)]
+pub struct ParserErrorSrc {
+ pub col_num: usize,
+ pub line_num: usize,
+}
+
#[derive(Debug)]
pub enum ParserError {
- BackQuotedString(usize, usize),
- IO(IOError),
- IncompleteReduction(usize, usize),
- InvalidSingleQuotedCharacter(char),
- LexicalError(lexical::Error),
- MissingQuote(usize, usize),
- NonPrologChar(usize, usize),
- ParseBigInt(usize, usize),
- UnexpectedChar(char, usize, usize),
+ BackQuotedString(ParserErrorSrc),
+ IO(IOError, ParserErrorSrc),
+ IncompleteReduction(ParserErrorSrc),
+ InvalidSingleQuotedCharacter(char, ParserErrorSrc),
+ LexicalError(lexical::Error, ParserErrorSrc),
+ MissingQuote(ParserErrorSrc),
+ NonPrologChar(ParserErrorSrc),
+ ParseBigInt(ParserErrorSrc),
+ UnexpectedChar(char, ParserErrorSrc),
// UnexpectedEOF,
- Utf8Error(usize, usize),
+ Utf8Error(ParserErrorSrc),
}
impl ParserError {
- pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
+ pub fn err_src(&self) -> ParserErrorSrc {
match self {
- &ParserError::BackQuotedString(line_num, col_num)
- | &ParserError::IncompleteReduction(line_num, col_num)
- | &ParserError::MissingQuote(line_num, col_num)
- | &ParserError::NonPrologChar(line_num, col_num)
- | &ParserError::ParseBigInt(line_num, col_num)
- | &ParserError::UnexpectedChar(_, line_num, col_num)
- | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
- _ => None,
+ &ParserError::BackQuotedString(err_src)
+ | &ParserError::IO(_, err_src)
+ | &ParserError::IncompleteReduction(err_src)
+ | &ParserError::InvalidSingleQuotedCharacter(_, err_src)
+ | &ParserError::LexicalError(_, err_src)
+ | &ParserError::MissingQuote(err_src)
+ | &ParserError::NonPrologChar(err_src)
+ | &ParserError::ParseBigInt(err_src)
+ | &ParserError::UnexpectedChar(_, err_src)
+ | &ParserError::Utf8Error(err_src) => err_src,
}
}
ParserError::InvalidSingleQuotedCharacter(..) => {
atom!("invalid_single_quoted_character")
}
- 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"),
}
#[inline]
- pub fn unexpected_eof() -> Self {
- ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof))
+ pub fn unexpected_eof(err_src: ParserErrorSrc) -> Self {
+ ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof), err_src)
}
#[inline]
pub fn is_unexpected_eof(&self) -> bool {
- if let ParserError::IO(e) = self {
+ if let ParserError::IO(e, _) = self {
e.kind() == ErrorKind::UnexpectedEof
} else {
false
}
}
}
-
+/*
impl From<lexical::Error> for ParserError {
- fn from(e: lexical::Error) -> ParserError {
- ParserError::LexicalError(e)
+ fn from((e, err_src): (lexical::Error, ParserErrorSrc)) -> ParserError {
+ ParserError::LexicalError(e, err_src)
}
}
}
}
}
-
+*/
#[derive(Debug, Clone, Copy)]
pub struct CompositeOpDir<'a, 'b> {
pub primary_op_dir: Option<&'b OpDir>,
}
impl VarPtr {
+ #[inline]
+ pub(crate) fn is_anon(&self) -> bool {
+ match *self.borrow() {
+ Var::Anon | Var::Generated { is_anon: true, .. } => true,
+ _ => false,
+ }
+ }
+
#[inline(always)]
pub(crate) fn borrow(&self) -> Ref<'_, Var> {
self.0.borrow()
pub(crate) fn to_var_num(&self) -> Option<usize> {
match *self.borrow() {
- Var::Generated(var_num) => Some(var_num),
+ Var::Generated { var_num, .. } => Some(var_num),
_ => None,
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Var {
- Generated(usize),
+ Anon,
+ Generated { is_anon: bool, var_num: usize },
InSitu(usize),
Named(String),
}
#[inline(always)]
pub fn to_string(&self) -> String {
match self {
- Var::InSitu(n) | Var::Generated(n) => format!("_{}", n),
+ Var::Anon => "_".to_owned(),
+ Var::InSitu(var_num) | Var::Generated { var_num, .. } => format!("_{}", var_num),
Var::Named(value) => value.to_owned(),
}
}
}
+pub(crate) fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) {
+ let subterm = heap[subterm_loc];
+
+ if subterm.is_ref() {
+ let subterm = heap_bound_deref(heap, subterm);
+ let subterm_loc = subterm.get_value() as usize;
+ let subterm = heap_bound_store(heap, subterm);
+
+ let subterm_loc = if subterm.is_ref() {
+ subterm.get_value() as usize
+ } else {
+ subterm_loc
+ };
+
+ (subterm_loc, subterm)
+ } else {
+ (subterm_loc, subterm)
+ }
+}
+
+/*
#[derive(Debug, Clone)]
pub enum Term {
AnonVar,
terms.push(term);
terms
}
+ */
+
+pub(crate) fn fetch_index_ptr(
+ heap: &[HeapCellValue],
+ arity: usize,
+ term_loc: usize,
+) -> Option<CodeIndex> {
+ if term_loc + arity + 1 >= heap.len() {
+ return None;
+ }
+
+ read_heap_cell!(heap[term_loc + arity + 1],
+ (HeapCellValueTag::Cons, c) => {
+ match_untyped_arena_ptr!(c,
+ (ArenaHeaderTag::IndexPtr, ptr) => {
+ return Some(CodeIndex::from(ptr));
+ }
+ _ => {}
+ );
+ }
+ _ => {}
+ );
+
+ None
+}
+
+pub(crate) fn blunt_index_ptr(
+ heap: &mut [HeapCellValue],
+ key: PredicateKey,
+ term_loc: usize,
+) -> bool {
+ if fetch_index_ptr(heap, key.1, term_loc).is_some() {
+ heap[term_loc] = atom_as_cell!(key.0, key.1);
+ true
+ } else {
+ false
+ }
+}
+
+pub(crate) fn unfold_by_str_once(
+ heap: &mut [HeapCellValue],
+ start_term: HeapCellValue,
+ atom: Atom,
+) -> Option<usize> {
+ let start_term = heap_bound_store(
+ heap,
+ heap_bound_deref(heap, start_term),
+ );
+
+ if let HeapCellValueTag::Str = start_term.get_tag() {
+ let s = start_term.get_value() as usize;
+
+ let (s_atom, s_arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
+ blunt_index_ptr(heap, (s_atom, s_arity), s);
+
+ if (s_atom, s_arity) == (atom, 2) {
+ return Some(s+1);
+ }
+ }
+
+ None
+}
+
+pub fn unfold_by_str(
+ heap: &mut [HeapCellValue],
+ mut start_term: HeapCellValue,
+ atom: Atom,
+) -> Vec<HeapCellValue> {
+ let mut terms = vec![];
+ start_term = heap_bound_store(heap, heap_bound_deref(heap, start_term));
+
+ while let Some(fst_loc) = unfold_by_str_once(heap, start_term, atom) {
+ let (_, snd) = subterm_index(heap, fst_loc + 1);
+ let (_, fst) = subterm_index(heap, fst_loc);
+ terms.push(fst);
+ start_term = snd;
+ }
+
+ terms
+}
+
+/*
+pub fn unfold_by_str_locs(
+ heap: &mut [HeapCellValue],
+ mut term_loc: usize,
+ atom: Atom,
+) -> Vec<(HeapCellValue, usize)> {
+ let mut terms = vec![];
+ let mut current_term = heap_bound_store(
+ heap,
+ heap_bound_deref(heap, heap[term_loc]),
+ );
+
+ while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) {
+ (term_loc, current_term) = subterm_index(heap, fst_loc + 1);
+ let (fst_loc, fst) = subterm_index(heap, fst_loc);
+ terms.push((fst, fst_loc));
+ }
+
+ terms.push((current_term, term_loc));
+ terms
+}
+*/
+
+pub fn unfold_by_str_locs(
+ heap: &mut [HeapCellValue],
+ mut term_loc: usize,
+ atom: Atom,
+) -> Vec<(HeapCellValue, usize)> {
+ let mut terms = vec![];
+ let mut current_term = heap[term_loc];
+
+ while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) {
+ term_loc = fst_loc+1;
+ current_term = heap[term_loc];
+ let fst = heap[fst_loc];
+ terms.push((fst, fst_loc));
+ }
+
+ terms.push((current_term, term_loc));
+ terms
+}
+
+pub fn term_name(heap: &[HeapCellValue], mut term_loc: usize) -> Option<Atom> {
+ loop {
+ read_heap_cell!(heap[term_loc],
+ (HeapCellValueTag::Atom, (name, _arity)) => {
+ return Some(name);
+ }
+ (HeapCellValueTag::Str, s) => {
+ term_loc = s;
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if h != term_loc {
+ term_loc = h;
+ } else {
+ return None;
+ }
+ }
+ _ => {
+ return None;
+ }
+ );
+ }
+}
+
+pub fn term_arity(heap: &[HeapCellValue], mut term_loc: usize) -> usize {
+ loop {
+ read_heap_cell!(heap[term_loc],
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ return arity;
+ }
+ (HeapCellValueTag::Str, s) => {
+ term_loc = s;
+ }
+ (HeapCellValueTag::Lis) => {
+ return 2;
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if h != term_loc {
+ term_loc = h;
+ } else {
+ return 0;
+ }
+ }
+ _ => {
+ return 0;
+ }
+ );
+ }
+}
+
+pub fn var_locs_from_iter<I: Iterator<Item = HeapCellValue>>(iter: I) -> VarLocs {
+ let mut occurrence_set: IndexMap<HeapCellValue, usize, FxBuildHasher> =
+ IndexMap::with_hasher(FxBuildHasher::default());
+
+ for term in iter {
+ if term.is_var() {
+ let var_count = occurrence_set.entry(term).or_insert(0);
+ *var_count += 1;
+ }
+ }
+
+ VarLocs(
+ occurrence_set
+ .into_iter()
+ .map(|(var, count)| {
+ let key = var.get_value() as usize;
+ let queue = if count > 1 {
+ (0 .. count).map(|_| VarPtr::from(format!("_{}", key))).collect()
+ } else {
+ (0 .. count).map(|_| VarPtr::from(Var::Anon)).collect()
+ };
+
+ (key, queue)
+ })
+ .collect()
+ )
+}
+
+/*
+pub fn term_deref(heap: &[HeapCellValue], mut term_loc: usize) -> HeapCellValue {
+ loop {
+ read_heap_cell!(heap[term_loc],
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if h != term_loc {
+ term_loc = h;
+ } else {
+ return heap[h];
+ }
+ }
+ _ => {
+ return heap[term_loc];
+ }
+ )
+ }
+}
+*/
+
+pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Option<usize> {
+ loop {
+ read_heap_cell!(heap[term_loc],
+ (HeapCellValueTag::Str, s) => {
+ return if cell_as_atom_cell!(heap[s]).get_arity() >= n {
+ Some(s+n)
+ } else {
+ None
+ };
+ }
+ (HeapCellValueTag::Atom, (_name, arity)) => {
+ return if arity >= n {
+ Some(term_loc + n)
+ } else {
+ None
+ };
+ }
+ (HeapCellValueTag::Lis, l) => {
+ return if 1 <= n && n <= 2 {
+ Some(l+n-1)
+ } else if n == 0 {
+ Some(term_loc)
+ } else {
+ None
+ };
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if h != term_loc {
+ term_loc = h;
+ } else {
+ return None;
+ }
+ }
+ _ => {
+ return None;
+ }
+ );
+ }
+}
+
+pub type VarNamesToLocs = IndexMap<String, HeapCellValue, FxBuildHasher>;
+
+#[derive(Debug, Default)]
+pub struct VarLocs(IndexMap<usize, VecDeque<VarPtr>, FxBuildHasher>);
+
+impl VarLocs {
+ pub fn get(&self, key: usize) -> Option<&VarPtr> {
+ self.0.get(&key)
+ .and_then(|queue| {
+ queue.front()
+ })
+ }
+
+ // if a queue of VarPtr's is stored at location key, pop the front
+ // if it exists and pass it along to wrapper, returning a value of
+ // type R. A return value of None indicates that the key doesn't
+ // exist (the map containing a key necessarily means its queue
+ // value is non-empty).
+ fn rotate_latest_mut<R>(
+ &mut self,
+ key: usize,
+ wrapper: impl FnOnce(&VarPtr) -> R,
+ ) -> Option<R> {
+ self.0.get_mut(&key)
+ .and_then(move |queue| {
+ if let Some(var_ptr) = queue.pop_front() {
+ let result = wrapper(&var_ptr);
+ queue.push_back(var_ptr);
+ Some(result)
+ } else {
+ None
+ }
+ })
+ }
+
+ pub fn peek_next_var_ptr_at_key(&self, key: usize) -> Option<&VarPtr> {
+ self.0.get(&key).and_then(|queue| queue.front())
+ }
+
+ pub fn read_next_var_ptr_at_key(&mut self, key: usize) -> Option<VarPtr> {
+ self.rotate_latest_mut(key, VarPtr::clone)
+ }
+
+ pub fn push_at_key(&mut self, key: usize, var_ptr: VarPtr) {
+ let entry = self.0.entry(key).or_default();
+ entry.push_back(var_ptr);
+ }
+
+ #[inline]
+ pub fn iter(&self) -> impl Iterator<Item = (usize, &VecDeque<VarPtr>)> {
+ self.0.iter().map(|(&k, v)| (k, v))
+ }
+
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.0.is_empty()
+ }
+
+ #[inline]
+ pub fn drain<R>(&mut self, range: R) -> indexmap::map::Drain<usize, VecDeque<VarPtr>>
+ where R: RangeBounds<usize>
+ {
+ self.0.drain(range)
+ }
+
+ #[inline]
+ pub fn insert(&mut self, key: usize, var_ptrs: VecDeque<VarPtr>) {
+ self.0.insert(key, var_ptrs);
+ }
+}
+
+#[derive(Debug)]
+pub struct FocusedHeap {
+ pub heap: Vec<HeapCellValue>,
+ pub focus: usize,
+ pub var_locs: VarLocs,
+}
+
+impl FocusedHeap {
+ pub fn empty() -> Self {
+ Self {
+ heap: vec![],
+ focus: 0,
+ var_locs: VarLocs::default(),
+ }
+ }
+
+ pub fn copy_term_from_machine_heap(
+ &mut self,
+ machine_st: &mut MachineState,
+ cell: HeapCellValue,
+ ) {
+ let hb = machine_st.heap.len();
+
+ copy_term(
+ CopyBallTerm::new(
+ &mut machine_st.attr_var_init.attr_var_queue,
+ &mut machine_st.stack,
+ &mut machine_st.heap,
+ &mut self.heap,
+ ),
+ cell,
+ AttrVarPolicy::DeepCopy,
+ );
+
+ for cell in self.heap.iter_mut() {
+ *cell = *cell - hb;
+ }
+ }
+
+ pub fn as_ref_mut(&mut self, focus: usize) -> FocusedHeapRefMut {
+ FocusedHeapRefMut {
+ heap: &mut self.heap,
+ focus,
+ // var_locs: &self.var_locs,
+ }
+ }
+
+ pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue {
+ use crate::machine::heap::*;
+
+ let cell = self.heap[term_loc];
+ heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell))
+ }
+
+ pub fn name(&self, term_loc: usize) -> Option<Atom> {
+ term_name(&self.heap, term_loc)
+ }
+
+ pub fn arity(&self, term_loc: usize) -> usize {
+ term_arity(&self.heap, term_loc)
+ }
+
+ pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option<usize> {
+ term_nth_arg(&self.heap, term_loc, n)
+ }
+}
+
+pub struct FocusedHeapRefMut<'a> {
+ pub heap: &'a mut Vec<HeapCellValue>,
+ pub focus: usize,
+}
+
+impl<'a> FocusedHeapRefMut<'a> {
+ pub fn name(&self, term_loc: usize) -> Option<Atom> {
+ term_name(&self.heap, term_loc)
+ }
+
+ pub fn arity(&self, term_loc: usize) -> usize {
+ term_arity(&self.heap, term_loc)
+ }
+
+ pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue {
+ use crate::machine::heap::*;
+
+ let cell = self.heap[term_loc];
+ heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell))
+ }
+
+ pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option<usize> {
+ term_nth_arg(self.heap, term_loc, n)
+ }
+
+ pub fn from_cell(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
+ let focus = read_heap_cell!(cell,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ h
+ }
+ _ => {
+ let h = heap.len();
+ heap.push(cell);
+
+ h
+ }
+ );
+
+ Self { heap, focus }
+ }
+}
+use lexical::{FromLexicalLossy, parse_lossy};
+
+use crate::arena::ArenaAllocated;
use crate::atom_table::*;
pub use crate::machine::machine_state::*;
use crate::parser::ast::*;
pub fn lookahead_char(&mut self) -> Result<char, ParserError> {
match self.reader.peek_char() {
Some(Ok(c)) => Ok(c),
- _ => Err(ParserError::unexpected_eof()),
+ _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())),
}
}
pub fn read_char(&mut self) -> Result<char, ParserError> {
match self.reader.read_char() {
Some(Ok(c)) => Ok(c),
- _ => Err(ParserError::unexpected_eof()),
+ _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())),
}
}
+ #[inline]
+ pub fn loc_to_err_src(&self) -> ParserErrorSrc {
+ ParserErrorSrc { line_num: self.line_num, col_num: self.col_num }
+ }
+
#[inline(always)]
fn return_char(&mut self, c: char) {
self.reader.put_back_char(c);
match comment_loop() {
Err(e) if e.is_unexpected_eof() => {
- return Err(ParserError::IncompleteReduction(
- self.line_num,
- self.col_num,
- ));
+ return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
}
Err(e) => {
return Err(e);
self.skip_char(c);
Ok(true)
} else {
- Err(ParserError::NonPrologChar(self.line_num, self.col_num))
+ Err(ParserError::NonPrologChar(self.loc_to_err_src()))
}
} else {
self.return_char('/');
if !back_quote_char!(c2) {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
+ Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
} else {
self.skip_char(c2);
Ok(c2)
Ok(None)
} else {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
+ Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
}
} else {
self.get_back_quoted_char().map(Some)
self.skip_char(c);
Ok(token)
} else {
- Err(ParserError::MissingQuote(self.line_num, self.col_num))
+ Err(ParserError::MissingQuote(self.loc_to_err_src()))
}
} else {
- Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
+ Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
}
}
if !single_quote_char!(c2) {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
+ Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
} else {
self.skip_char(c2);
Ok(c2)
if !double_quote_char!(c2) {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
+ Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
} else {
self.skip_char(c2);
Ok(c2)
't' => '\t',
'n' => '\n',
'r' => '\r',
- c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)),
+ c => return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())),
};
self.skip_char(c);
if hexadecimal_digit_char!(c) {
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
} else {
- Err(ParserError::IncompleteReduction(
- self.line_num,
- self.col_num,
- ))
+ Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
}
}
if backslash_char!(c) {
self.skip_char(c);
u32::from_str_radix(&token, radix).map_or_else(
- |_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)),
+ |_| Err(ParserError::ParseBigInt(self.loc_to_err_src())),
|n| {
char::try_from(n)
- .map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num))
+ .map_err(|_| ParserError::Utf8Error(self.loc_to_err_src()))
},
)
} else {
- Err(ParserError::IncompleteReduction(
- self.line_num,
- self.col_num,
- ))
+ Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
}
}
Ok(c)
} else {
if !backslash_char!(c) {
- return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num));
+ return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()));
}
self.skip_char(c);
self.skip_char(c);
Ok(token)
} else {
- Err(ParserError::MissingQuote(self.line_num, self.col_num))
+ Err(ParserError::MissingQuote(self.loc_to_err_src()))
}
}
&mut self.machine_st.arena
)))
})
- .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
+ .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
} else {
self.return_char(start);
- Err(ParserError::ParseBigInt(self.line_num, self.col_num))
+ Err(ParserError::ParseBigInt(self.loc_to_err_src()))
}
}
&mut self.machine_st.arena
)))
})
- .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
+ .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
} else {
self.return_char(start);
- Err(ParserError::ParseBigInt(self.line_num, self.col_num))
+ Err(ParserError::ParseBigInt(self.loc_to_err_src()))
}
}
&mut self.machine_st.arena
)))
})
- .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
+ .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
} else {
self.return_char(start);
- Err(ParserError::ParseBigInt(self.line_num, self.col_num))
+ Err(ParserError::ParseBigInt(self.loc_to_err_src()))
}
}
}
}
} else {
- return Err(ParserError::InvalidSingleQuotedCharacter(c));
+ return Err(ParserError::InvalidSingleQuotedCharacter(c, self.loc_to_err_src()));
}
} else {
match self.get_back_quoted_string() {
- Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)),
+ Ok(_) => return Err(ParserError::BackQuotedString(self.loc_to_err_src())),
Err(e) => return Err(e),
}
}
}
}
+ fn parse_lossy_wrapper<T: FromLexicalLossy>(&self, token: String) -> Result<T, ParserError> {
+ match parse_lossy::<T, _>(token.as_bytes()) {
+ Ok(n) => Ok(n),
+ Err(e) => return Err(ParserError::LexicalError(e, self.loc_to_err_src())),
+ }
+ }
+
fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
self.return_char(token.pop().unwrap());
-
- let n = parse_float_lossy(&token)?;
-
- Ok(Token::Literal(Literal::from(float_alloc!(
- n,
- self.machine_st.arena
- ))))
+ let n = self.parse_lossy_wrapper::<f64>(token)?;
+ Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena))))
}
fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
if decimal_digit_char!(c) {
Ok(c)
} else {
- Err(ParserError::ParseBigInt(self.line_num, self.col_num))
+ Err(ParserError::ParseBigInt(self.loc_to_err_src()))
}
} else {
Ok(c)
&mut self.machine_st.arena
)))
})
- .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
+ .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
} else if decimal_digit_char!(self.lookahead_char()?) {
token.push('.');
}
}
- let n = parse_float_lossy(&token)?;
+ let n = self.parse_lossy_wrapper::<f64>(token)?;
+
Ok(Token::Literal(Literal::from(float_alloc!(
n,
self.machine_st.arena
return self.vacate_with_float(token);
}
} else {
- let n = parse_float_lossy(&token)?;
+ let n = self.parse_lossy_wrapper::<f64>(token)?;
Ok(Token::Literal(Literal::from(float_alloc!(
n,
self.machine_st.arena
&mut self.machine_st.arena
)))
})
- .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
+ .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
}
} else if token.starts_with('0') && token.len() == 1 {
)))
})
.map_err(|_| {
- ParserError::ParseBigInt(self.line_num, self.col_num)
+ ParserError::ParseBigInt(self.loc_to_err_src())
})
})
} else {
)))
})
.map_err(|_| {
- ParserError::ParseBigInt(self.line_num, self.col_num)
+ ParserError::ParseBigInt(self.loc_to_err_src())
})
})
} else {
)))
})
.map_err(|_| {
- ParserError::ParseBigInt(self.line_num, self.col_num)
+ ParserError::ParseBigInt(self.loc_to_err_src())
})
})
} else {
)))
})
.map_err(|_| {
- ParserError::ParseBigInt(self.line_num, self.col_num)
+ ParserError::ParseBigInt(self.loc_to_err_src())
})
})
})
&mut self.machine_st.arena
)))
})
- .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
+ .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
}
} else {
&mut self.machine_st.arena
)))
})
- .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
+ .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
}
}
}
if c == '\u{0}' {
- return Err(ParserError::unexpected_eof());
+ return Err(ParserError::unexpected_eof(self.loc_to_err_src()));
}
self.name_token(c)
use crate::arena::*;
use crate::atom_table::*;
+use crate::machine::heap::{heap_bound_deref, heap_bound_store};
+use crate::machine::partial_string::*;
use crate::parser::ast::*;
use crate::parser::char_reader::*;
use crate::parser::lexer::*;
+use crate::types::*;
+
+use fxhash::FxBuildHasher;
+use indexmap::IndexMap;
-use std::cell::Cell;
use std::mem;
use std::ops::Neg;
#[derive(Debug, Clone, Copy, PartialEq)]
enum TokenType {
- Term,
+ Term { heap_loc: HeapCellValue },
Open,
OpenCT,
OpenList, // '['
End,
}
+impl TokenType {
+ fn sep_to_atom(self) -> Option<Atom> {
+ 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.
unfold_bounds: usize,
}
-pub(crate) fn as_partial_string(
- head: Term,
- mut tail: Term,
-) -> Result<(String, Option<Box<Term>>), Term> {
- let mut string = match &head {
- Term::Literal(_, Literal::Atom(atom)) => {
- if let Some(c) = atom.as_char() {
- c.to_string()
- } else {
- return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
- }
- }
- Term::Literal(_, Literal::Char(c)) => c.to_string(),
- _ => {
- return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
- }
- };
-
- let mut orig_tail = Box::new(tail);
- let mut tail_ref = &mut orig_tail;
-
- loop {
- match &mut **tail_ref {
- Term::Cons(_, prev, succ) => {
- match prev.as_ref() {
- Term::Literal(_, Literal::Atom(atom)) => {
- if let Some(c) = atom.as_char() {
- string.push(c);
- } else {
- return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
- }
- }
- Term::Literal(_, Literal::Char(c)) => {
- string.push(*c);
- }
- _ => {
- tail = Term::Cons(
- Cell::default(),
- Box::new((**prev).clone()),
- Box::new((**succ).clone()),
- );
- break;
- }
- }
-
- tail_ref = succ;
- }
- Term::PartialString(_, pstr, tail) => {
- string += pstr;
- tail_ref = tail;
- }
- Term::CompleteString(_, cstr) => {
- string += &*cstr.as_str();
- tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
- break;
- }
- tail_ref => {
- tail = mem::replace(tail_ref, Term::AnonVar);
- break;
- }
- }
- }
-
- match &tail {
- Term::AnonVar | Term::Var(..) => Ok((string, Some(Box::new(tail)))),
- Term::Literal(_, Literal::Atom(atom!("[]"))) => Ok((string, None)),
- Term::Literal(_, Literal::String(tail)) => {
- string += &*tail.as_str();
- Ok((string, None))
- }
- _ => Ok((string, Some(Box::new(tail)))),
- }
-}
-
pub fn get_op_desc(name: Atom, op_dir: &CompositeOpDir) -> Option<CompositeOpDesc> {
let mut op_desc = CompositeOpDesc {
pre: 0,
pub lexer: Lexer<'a, R>,
tokens: Vec<Token>,
stack: Vec<TokenDesc>,
- terms: Vec<Term>,
+ terms: Vec<HeapCellValue>,
+ var_locs: VarLocs,
+ var_names_to_locs: VarNamesToLocs,
}
fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> {
}
}
Err(e) if e.is_unexpected_eof() && !tokens.is_empty() => {
- return Err(ParserError::IncompleteReduction(
- lexer.line_num,
- lexer.col_num,
- ));
+ return Err(ParserError::IncompleteReduction(lexer.loc_to_err_src()));
}
Err(e) => {
return Err(e);
Ok(tokens)
}
-fn atomize_term(atom_tbl: &AtomTable, term: &Term) -> Option<Atom> {
- match term {
- Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c),
- _ => None,
- }
-}
-
-fn atomize_constant(atom_tbl: &AtomTable, c: Literal) -> Option<Atom> {
+fn atomize_literal(atom_tbl: &AtomTable, c: Literal) -> Option<Atom> {
match c {
Literal::Atom(ref name) => Some(*name),
Literal::Char(c) => Some(AtomTable::build_with(atom_tbl, &c.to_string())),
}
}
+pub(crate) fn as_partial_string(
+ heap: &[HeapCellValue],
+ head: HeapCellValue,
+ tail: HeapCellValue,
+) -> Option<(String, Option<HeapCellValue>)> {
+ let head = heap_bound_store(heap, heap_bound_deref(heap, head));
+ let mut tail = heap_bound_store(heap, heap_bound_deref(heap, tail));
+
+ let mut string = read_heap_cell!(head,
+ (HeapCellValueTag::Atom, (atom, arity)) => {
+ if arity == 0 {
+ if let Some(c) = atom.as_char() {
+ c.to_string()
+ } else {
+ return None;
+ }
+ } else {
+ return None;
+ }
+ }
+ (HeapCellValueTag::Char, c) => {
+ c.to_string()
+ }
+ _ => {
+ return None;
+ }
+ );
+
+ loop {
+ read_heap_cell!(tail,
+ (HeapCellValueTag::Lis, l) => {
+ read_heap_cell!(heap[l],
+ (HeapCellValueTag::Atom, (atom, arity)) => {
+ if arity == 0 {
+ if let Some(c) = atom.as_char() {
+ string.push(c);
+ } else {
+ return None;
+ }
+ } else {
+ break;
+ }
+ }
+ (HeapCellValueTag::Char, c) => {
+ string.push(c);
+ }
+ _ => {
+ return None;
+ }
+ );
+
+ tail = heap[l+1];
+ }
+ (HeapCellValueTag::PStrLoc, l) => {
+ let (index, n) = pstr_loc_and_offset(&heap, l);
+ let n = n.get_num() as usize;
+
+ string += &*cell_as_string!(heap[index]).as_str_from(n);
+ tail = heap[l+1];
+ }
+ (HeapCellValueTag::CStr, cstr_atom) => {
+ string += &*cstr_atom.as_str();
+ tail = empty_list_as_cell!();
+ break;
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ if heap[h] != tail {
+ tail = heap[h];
+ } else {
+ break;
+ }
+ }
+ _ => {
+ // Anon
+ break;
+ }
+ );
+ }
+
+ read_heap_cell!(tail,
+ (HeapCellValueTag::Var) => {
+ Some((string, Some(tail)))
+ }
+ (HeapCellValueTag::Atom, (atom, arity)) => {
+ if atom == atom!("[]") && arity == 0 {
+ Some((string, None))
+ } else {
+ Some((string, Some(tail)))
+ }
+ }
+ _ => {
+ Some((string, Some(tail)))
+ }
+ )
+}
+
impl<'a, R: CharRead> Parser<'a, R> {
pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self {
Parser {
tokens: vec![],
stack: vec![],
terms: vec![],
+ var_locs: VarLocs::default(),
+ var_names_to_locs: IndexMap::with_hasher(FxBuildHasher::default()),
}
}
tokens: vec![],
stack: vec![],
terms: vec![],
+ var_locs: VarLocs::default(),
+ var_names_to_locs: IndexMap::with_hasher(FxBuildHasher::default()),
}
}
- fn sep_to_atom(&mut self, tt: TokenType) -> Option<Atom> {
- match tt {
- TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
- TokenType::Close => Some(atom!(")")),
- TokenType::OpenList => Some(atom!("[")),
- TokenType::CloseList => Some(atom!("]")),
- TokenType::OpenCurly => Some(atom!("{")),
- TokenType::CloseCurly => Some(atom!("}")),
- TokenType::HeadTailSeparator => Some(atom!("|")),
- TokenType::Comma => Some(atom!(",")),
- TokenType::End => Some(atom!(".")),
- _ => None,
- }
- }
-
- fn get_term_name(&mut self, td: TokenDesc) -> Option<Atom> {
+ fn get_term_name(&self, td: TokenDesc) -> Option<Atom> {
match td.tt {
TokenType::HeadTailSeparator => Some(atom!("|")),
TokenType::Comma => Some(atom!(",")),
- TokenType::Term => match self.terms.pop() {
- Some(Term::Literal(_, Literal::Atom(atom))) => Some(atom),
- Some(term) => {
- self.terms.push(term);
+ TokenType::Term { heap_loc } => {
+ if heap_loc.is_ref() {
+ term_name(&self.terms, heap_loc.get_value() as usize)
+ } else {
None
}
- _ => None,
- },
+ }
_ => None,
}
}
- fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) {
- if let Some(arg2) = self.terms.pop() {
- if let Some(name) = self.get_term_name(td) {
- if let Some(arg1) = self.terms.pop() {
- let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]);
+ #[inline]
+ pub fn line_num(&self) -> usize {
+ self.lexer.line_num
+ }
+
+ #[inline]
+ pub fn col_num(&self) -> usize {
+ self.lexer.col_num
+ }
+
+ fn push_binary_op(
+ &mut self,
+ op: TokenDesc,
+ operand_1: TokenDesc,
+ operand_2: TokenDesc,
+ spec: Specifier,
+ ) {
+ if let TokenDesc {
+ tt: TokenType::Term { heap_loc: arg2 },
+ ..
+ } = operand_2
+ {
+ if let TokenDesc {
+ tt: TokenType::Term { heap_loc: arg1 },
+ ..
+ } = operand_1
+ {
+ if let Some(name) = self.get_term_name(op) {
+ let str_loc = self.terms.len();
+
+ self.terms.push(atom_as_cell!(name, 2));
+ self.terms.push(arg1);
+ self.terms.push(arg2);
+
+ self.terms.push(str_loc_as_cell!(str_loc));
- self.terms.push(term);
self.stack.push(TokenDesc {
- tt: TokenType::Term,
- priority: td.priority,
+ tt: TokenType::Term {
+ heap_loc: heap_loc_as_cell!(str_loc + 3),
+ },
+ priority: op.priority,
spec,
unfold_bounds: 0,
});
}
}
- fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: OpDeclSpec) {
- if let Some(mut arg1) = self.terms.pop() {
- if let Some(mut name) = self.terms.pop() {
- if assoc.is_postfix() {
- mem::swap(&mut arg1, &mut name);
- }
+ fn push_unary_op(&mut self, op: TokenDesc, operand: TokenDesc, spec: Specifier) {
+ // if is_postfix!(assoc) {
+ // mem::swap(&mut op, &mut operand);
+ // }
- if let Term::Literal(_, Literal::Atom(name)) = name {
- let term = Term::Clause(Cell::default(), name, vec![arg1]);
+ if let TokenDesc {
+ tt: TokenType::Term { heap_loc: arg1 },
+ ..
+ } = operand
+ {
+ if let TokenDesc {
+ tt: TokenType::Term { .. },
+ ..
+ } = op
+ {
+ if let Some(name) = self.get_term_name(op) {
+ let str_loc = self.terms.len();
+
+ self.terms.push(atom_as_cell!(name, 1));
+ self.terms.push(arg1);
+ self.terms.push(str_loc_as_cell!(str_loc));
- self.terms.push(term);
self.stack.push(TokenDesc {
- tt: TokenType::Term,
- priority: td.priority,
+ tt: TokenType::Term {
+ heap_loc: heap_loc_as_cell!(str_loc + 2),
+ },
+ priority: op.priority,
spec,
unfold_bounds: 0,
});
}
fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) {
- self.terms
- .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
+ let h = self.terms.len();
+ self.terms.push(atom_as_cell!(atom));
self.stack.push(TokenDesc {
- tt: TokenType::Term,
+ tt: TokenType::Term {
+ heap_loc: heap_loc_as_cell!(h),
+ },
priority,
spec: assoc,
unfold_bounds: 0,
}
fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
+ let heap_loc = heap_loc_as_cell!(self.terms.len());
+
let tt = match token {
Token::Literal(Literal::String(s))
if self.lexer.machine_st.flags.double_quotes.is_codes() =>
{
- let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
+ let mut list = empty_list_as_cell!();
for c in s.as_str().chars().rev() {
- list = Term::Cons(
- Cell::default(),
- Box::new(Term::Literal(
- Cell::default(),
- Literal::Fixnum(Fixnum::build_with(c as i64)),
- )),
- Box::new(list),
- );
+ let h = self.terms.len();
+
+ self.terms
+ .push(fixnum_as_cell!(Fixnum::build_with(c as i64)));
+ self.terms.push(list);
+
+ list = list_loc_as_cell!(h);
}
self.terms.push(list);
- TokenType::Term
+
+ TokenType::Term { heap_loc: list }
}
Token::Literal(Literal::String(s))
if self.lexer.machine_st.flags.double_quotes.is_chars() =>
{
- self.terms.push(Term::CompleteString(Cell::default(), s));
- TokenType::Term
+ if s.is_empty() {
+ self.terms.push(empty_list_as_cell!());
+ } else {
+ self.terms.push(string_as_cstr_cell!(s));
+ }
+
+ TokenType::Term { heap_loc }
+ }
+ Token::Literal(Literal::Char(c)) => {
+ // soon this will be gone due to chars being folded
+ // into atoms
+ self.terms.push(atom_as_cell!(atomize_literal(
+ &self.lexer.machine_st.atom_tbl,
+ Literal::Char(c),
+ ).unwrap()));
+
+ TokenType::Term { heap_loc }
}
Token::Literal(c) => {
- self.terms.push(Term::Literal(Cell::default(), c));
- TokenType::Term
+ self.terms.push(HeapCellValue::from(c));
+ TokenType::Term { heap_loc }
}
- Token::Var(v) => {
- if v.trim() == "_" {
- self.terms.push(Term::AnonVar);
- } else {
- self.terms.push(Term::Var(Cell::default(), VarPtr::from(v)));
+ Token::Var(var_string) => match self.var_names_to_locs.get(&var_string).cloned() {
+ Some(heap_loc) => {
+ let heap_idx = heap_loc.get_value() as usize;
+
+ self.var_locs.push_at_key(heap_idx, VarPtr::from(var_string));
+ self.terms.push(heap_loc);
+
+ TokenType::Term { heap_loc }
}
+ None => {
+ self.terms.push(heap_loc);
- TokenType::Term
- }
+ if var_string.trim() != "_" {
+ self.var_names_to_locs.insert(var_string.clone(), heap_loc);
+ }
+
+ self.var_locs.push_at_key(
+ heap_loc.get_value() as usize,
+ if var_string.trim() == "_" {
+ VarPtr::from(Var::Anon)
+ } else {
+ VarPtr::from(var_string)
+ },
+ );
+
+ TokenType::Term { heap_loc }
+ }
+ },
Token::Comma => TokenType::Comma,
Token::Open => TokenType::Open,
Token::Close => TokenType::Close,
if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1)
|| is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1)
{
- self.push_binary_op(desc2, LTERM);
+ self.push_binary_op(desc2, desc3, desc1, LTERM);
continue;
} else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) {
- self.push_binary_op(desc2, TERM);
+ self.push_binary_op(desc2, desc3, desc1, TERM);
continue;
} else {
self.stack.push(desc3);
}
if is_yf!(desc1.spec) && affirm_yf(desc1, desc2) {
- self.push_unary_op(desc1, LTERM, YF);
+ self.push_unary_op(desc1, desc2, LTERM);
continue;
} else if is_xf!(desc1.spec) && affirm_xf(desc1, desc2) {
- self.push_unary_op(desc1, LTERM, XF);
+ self.push_unary_op(desc1, desc2, LTERM);
continue;
} else if is_fy!(desc2.spec) && affirm_fy(priority, desc1, desc2) {
- self.push_unary_op(desc2, TERM, FY);
+ self.push_unary_op(desc2, desc1, TERM);
continue;
} else if is_fx!(desc2.spec) && affirm_fx(priority, desc1, desc2) {
- self.push_unary_op(desc2, TERM, FX);
+ self.push_unary_op(desc2, desc1, TERM);
continue;
} else {
self.stack.push(desc2);
None
}
+ fn term_from_stack(&self, idx: usize) -> Option<HeapCellValue> {
+ 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;
return false;
}
- if self.terms.len() < 1 + arity {
+ if self.terms.len() < arity {
return false;
}
let stack_len = self.stack.len() - 2 * arity - 1;
- let idx = self.terms.len() - arity;
+ let term_idx = self.terms.len();
- if TokenType::Term == self.stack[stack_len].tt
- && atomize_term(&self.lexer.machine_st.atom_tbl, &self.terms[idx - 1]).is_some()
- {
- self.stack.truncate(stack_len + 1);
+ let push_structure = |parser: &mut Self, name: Atom| -> TokenType {
+ parser.terms.push(atom_as_cell!(name, arity));
- let mut subterms: Vec<_> = self.terms.drain(idx..).collect();
+ for idx in (stack_len + 2..parser.stack.len()).step_by(2) {
+ let subterm = parser.term_from_stack(idx).unwrap();
+ parser.terms.push(subterm);
+ }
- if let Some(name) = self
- .terms
- .pop()
- .and_then(|t| atomize_term(&self.lexer.machine_st.atom_tbl, &t))
- {
+ let str_loc_idx = parser.terms.len();
+ parser.terms.push(str_loc_as_cell!(term_idx));
+
+ TokenType::Term {
+ heap_loc: heap_loc_as_cell!(str_loc_idx),
+ }
+ };
+
+ if let TokenDesc {
+ tt: TokenType::Term { heap_loc },
+ ..
+ } = self.stack[stack_len]
+ {
+ let idx = heap_loc.get_value() as usize;
+
+ if let Some(name) = term_name(&self.terms, idx) {
// reduce the '.' functor to a cons cell if it applies.
- if name == atom!(".") && subterms.len() == 2 {
- let tail = subterms.pop().unwrap();
- let head = subterms.pop().unwrap();
+ let new_tt = if name == atom!(".") && arity == 2 {
+ let head = self.term_from_stack(stack_len + 2).unwrap();
+ let tail = self.term_from_stack(stack_len + 4).unwrap();
- self.terms.push(match as_partial_string(head, tail) {
- Ok((string_buf, Some(tail))) => {
- Term::PartialString(Cell::default(), string_buf, tail)
+ match as_partial_string(&self.terms, head, tail) {
+ Some((string_buf, Some(tail))) => {
+ let atom =
+ AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
+
+ self.terms.push(string_as_pstr_cell!(atom));
+ self.terms.push(tail);
+ self.terms.push(pstr_loc_as_cell!(term_idx));
+
+ TokenType::Term {
+ heap_loc: heap_loc_as_cell!(term_idx + 2),
+ }
}
- Ok((string_buf, None)) => {
+ Some((string_buf, None)) => {
let atom =
AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
- Term::CompleteString(Cell::default(), atom)
+ TokenType::Term {
+ heap_loc: string_as_cstr_cell!(atom),
+ }
}
- Err(term) => term,
- });
+ None => {
+ self.terms.push(head);
+ self.terms.push(tail);
+ self.terms.push(list_loc_as_cell!(term_idx));
+
+ TokenType::Term {
+ heap_loc: heap_loc_as_cell!(term_idx + 2),
+ }
+ }
+ }
} else {
- self.terms
- .push(Term::Clause(Cell::default(), name, subterms));
- }
+ push_structure(self, name)
+ };
+
+ self.stack.truncate(stack_len + 1);
if let Some(&mut TokenDesc {
ref mut tt,
return false;
}
- *tt = TokenType::Term;
+ *tt = new_tt;
*priority = 0;
*spec = TERM;
*unfold_bounds = 0;
}
+ } else {
+ return false;
+ };
- return true;
- }
+ return true;
}
false
}
pub fn reset(&mut self) {
- self.stack.clear()
+ self.stack.clear();
+ self.var_names_to_locs.clear();
}
fn expand_comma_compacted_terms(&mut self, index: usize) -> usize {
- if let Some(mut term) = self.terms.pop() {
+ if let Some(term) = self.term_from_stack(index - 1) {
let mut op_desc = self.stack[index - 1];
-
- if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority {
+ let mut term = heap_bound_store(
+ &self.terms,
+ heap_bound_deref(
+ &self.terms,
+ term,
+ ),
+ );
+
+ if term.is_ref() &&
+ 0 < op_desc.priority && op_desc.priority < self.stack[index].priority
+ {
/* '|' is a head-tail separator here, not
* an operator, so expand the
* terms it compacted out again. */
- if let (Some(atom!(",")), 2) = (term.name(), term.arity()) {
+
+ let focus = term.get_value() as usize;
+ let name_opt = term_name(&self.terms, focus);
+ let arity = term_arity(&self.terms, focus);
+
+ if name_opt == Some(atom!(",")) && arity == 2 {
let terms = if op_desc.unfold_bounds == 0 {
- unfold_by_str(term, atom!(","))
+ unfold_by_str(&mut self.terms, term, atom!(","))
} else {
let mut terms = vec![];
- while let Some((fst, snd)) = unfold_by_str_once(&mut term, atom!(",")) {
+ while let Some(fst_loc) = unfold_by_str_once(
+ &mut self.terms,
+ term,
+ atom!(","),
+ ) {
+ let (_, snd) = subterm_index(&self.terms, fst_loc + 1);
+ let (_, fst) = subterm_index(&self.terms, fst_loc);
+
terms.push(fst);
term = snd;
};
let arity = terms.len() - 1;
-
- self.terms.extend(terms);
+ self.stack.extend(terms.into_iter().map(|heap_loc| {
+ TokenDesc {
+ tt: TokenType::Term { heap_loc },
+ priority: 0,
+ spec: 0,
+ unfold_bounds: 0,
+ }
+ }));
return arity;
}
}
-
- self.terms.push(term);
}
0
}
if let Some(ref mut td) = self.stack.last_mut() {
+ // parsed an empty list token
if td.tt == TokenType::OpenList {
+ let h = self.terms.len();
+ self.terms.push(empty_list_as_cell!());
+
td.spec = TERM;
- td.tt = TokenType::Term;
+ td.tt = TokenType::Term {
+ heap_loc: heap_loc_as_cell!(h),
+ };
td.priority = 0;
- self.terms
- .push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))));
return Ok(true);
}
}
// we know that self.stack.len() >= 2 by this point.
let idx = self.stack.len() - 2;
- let list_len = self.stack.len() - 2 * arity;
+ let list_start_idx = self.stack.len() - 2 * arity;
- let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator {
- Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))
+ let mut tail_term = if self.stack[idx].tt != TokenType::HeadTailSeparator {
+ empty_list_as_cell!()
} else {
- let term = match self.terms.pop() {
+ let tail_term = match self.term_from_stack(idx + 1) {
Some(term) => term,
- _ => {
+ None => {
return Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
- ))
+ self.lexer.loc_to_err_src(),
+ ));
}
};
+ self.stack.pop();
+
if self.stack[idx].priority > 1000 {
arity += self.expand_comma_compacted_terms(idx);
}
+ // decrement for the removal of tail term.
arity -= 1;
-
- term
+ tail_term
};
if arity > self.terms.len() {
return Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
+ self.lexer.loc_to_err_src(),
));
}
- let idx = self.terms.len() - arity;
+ let pre_terms_len = self.terms.len();
- let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| {
- Term::Cons(Cell::default(), Box::new(t), Box::new(acc))
- });
+ while let Some(token_desc) = self.stack.pop() {
+ let subterm = match token_desc.tt {
+ TokenType::Term { heap_loc } => {
+ heap_loc
+ }
+ _ => {
+ continue;
+ }
+ };
+
+ arity -= 1;
+
+ let link_cell = list_loc_as_cell!(self.terms.len() + 1);
+
+ self.terms.push(link_cell);
+ self.terms.push(subterm);
+ self.terms.push(tail_term);
+
+ tail_term = link_cell;
+
+ if arity == 0 {
+ break;
+ }
+ }
+
+ debug_assert_eq!(arity, 0);
+
+ self.stack.truncate(list_start_idx);
+
+ let list_loc = self.terms.len() - 3;
+
+ let head_term = self.terms[list_loc + 1];
+ let tail_term = self.terms[list_loc + 2];
+
+ let heap_loc = match as_partial_string(&self.terms, head_term, tail_term) {
+ Some((string_buf, Some(tail))) => {
+ self.terms.truncate(pre_terms_len);
- self.stack.truncate(list_len);
+ let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
+
+ self.terms.push(string_as_pstr_cell!(atom));
+ self.terms.push(tail);
+ self.terms.push(pstr_loc_as_cell!(pre_terms_len));
+
+ heap_loc_as_cell!(pre_terms_len + 2)
+ }
+ Some((string_buf, None)) => {
+ self.terms.truncate(pre_terms_len);
+ let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
+ self.terms.push(string_as_cstr_cell!(atom));
+
+ heap_loc_as_cell!(pre_terms_len)
+ }
+ None => {
+ heap_loc_as_cell!(list_loc) // head_term
+ }
+ };
self.stack.push(TokenDesc {
- tt: TokenType::Term,
+ tt: TokenType::Term { heap_loc },
priority: 0,
spec: TERM,
unfold_bounds: 0,
});
+ /*
self.terms.push(match list {
Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) {
Ok((string_buf, Some(tail))) => {
},
term => term,
});
+ */
Ok(true)
}
if let Some(ref mut td) = self.stack.last_mut() {
if td.tt == TokenType::OpenCurly {
- td.tt = TokenType::Term;
+ let h = self.terms.len();
+ self.terms.push(atom_as_cell!(atom!("{}")));
+
+ td.tt = TokenType::Term {
+ heap_loc: heap_loc_as_cell!(h),
+ };
td.priority = 0;
td.spec = TERM;
- let term = Term::Literal(Cell::default(), Literal::Atom(atom!("{}")));
-
- self.terms.push(term);
return Ok(true);
}
}
if self.stack.len() > 1 {
if let Some(td) = self.stack.pop() {
if let Some(ref mut oc) = self.stack.last_mut() {
- if td.tt != TokenType::Term {
+ if !matches!(td.tt, TokenType::Term { .. }) {
return Ok(false);
}
if oc.tt == TokenType::OpenCurly {
- oc.tt = TokenType::Term;
- oc.priority = 0;
- oc.spec = TERM;
-
- let term = match self.terms.pop() {
- Some(term) => term,
- _ => {
- return Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
- ))
- }
- };
-
- self.terms
- .push(Term::Clause(Cell::default(), atom!("{}"), vec![term]));
-
- return Ok(true);
+ if let TokenType::Term { heap_loc } = td.tt {
+ let curly_idx = self.terms.len();
+
+ oc.tt = TokenType::Term {
+ heap_loc: heap_loc_as_cell!(curly_idx + 2),
+ };
+ oc.priority = 0;
+ oc.spec = TERM;
+
+ self.terms.push(atom_as_cell!(atom!("{}"), 1));
+ self.terms.push(heap_loc);
+ self.terms.push(str_loc_as_cell!(curly_idx));
+
+ /*
+ let term = match self.terms.pop() {
+ Some(term) => term,
+ _ => {
+ return Err(ParserError::IncompleteReduction(
+ self.lexer.line_num,
+ self.lexer.col_num,
+ ))
+ }
+ };
+
+ self.terms
+ .push(Term::Clause(Cell::default(), atom!("{}"), vec![term]));
+ */
+
+ return Ok(true);
+ }
}
}
}
return false;
}
- if let Some(TokenType::Open | TokenType::OpenCT) = self.stack.last().map(|token| token.tt) {
- return false;
+ match self.stack.last().map(|token| token.tt) {
+ Some(TokenType::Open | TokenType::OpenCT) => return false,
+ _ => {}
}
let idx = self.stack.len() - 2;
return false;
}
- if let Some(atom) = self.sep_to_atom(self.stack[idx].tt) {
- self.terms
- .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
- }
+ let term = if self.stack[idx].tt.sep_to_atom().is_some() {
+ atom_as_cell!(atom!("|"))
+ // self.terms
+ // .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
+ } else {
+ self.term_from_stack(idx).unwrap()
+ };
self.stack[idx].spec = BTERM;
- self.stack[idx].tt = TokenType::Term;
+ self.stack[idx].tt = TokenType::Term { heap_loc: term };
self.stack[idx].priority = 0;
true
}) = get_op_desc(name, op_dir)
{
if (pre > 0 && inf + post > 0) || is_negate!(spec) {
- match self.tokens.last().ok_or(ParserError::unexpected_eof())? {
+ match self
+ .tokens
+ .last()
+ .ok_or(ParserError::unexpected_eof(self.lexer.loc_to_err_src()))?
+ {
// do this when layout hasn't been inserted,
// ie. why we don't match on Token::Open.
Token::OpenCT => {
Negator: Fn(N, &mut Arena) -> N,
ToLiteral: Fn(N, &mut Arena) -> Literal,
{
- if let Some(desc) = self.stack.last().cloned() {
- if let Some(term) = self.terms.last().cloned() {
- match term {
- Term::Literal(_, Literal::Atom(name))
- if name == atom!("-")
- && (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
- {
+ match self.stack.last().cloned() {
+ Some(
+ td @ TokenDesc {
+ tt: TokenType::Term { .. },
+ spec,
+ ..
+ },
+ ) => {
+ if let Some(name) = self.get_term_name(td) {
+ if name == atom!("-") && (is_prefix!(spec) || is_negate!(spec)) {
self.stack.pop();
- self.terms.pop();
let arena = &mut self.lexer.machine_st.arena;
let literal = constr(negator(n, arena), arena);
return;
}
- _ => {}
}
}
+ _ => {}
}
let literal = constr(n, &mut self.lexer.machine_st.arena);
|n, arena| Literal::from(float_alloc!(n, arena)),
),
Token::Literal(c) => {
- let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c);
+ let atomized = atomize_literal(&self.lexer.machine_st.atom_tbl, c);
if let Some(name) = atomized {
if !self.shift_op(name, op_dir)? {
Token::Close => {
if !self.reduce_term() && !self.reduce_brackets() {
return Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
+ self.lexer.loc_to_err_src(),
));
}
}
Token::CloseList => {
if !self.reduce_list()? {
return Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
+ self.lexer.loc_to_err_src(),
));
}
}
Token::CloseCurly => {
if !self.reduce_curly()? {
return Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
+ self.lexer.loc_to_err_src(),
));
}
}
| Some(TokenType::HeadTailSeparator)
| Some(TokenType::Comma) => {
return Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
+ self.lexer.loc_to_err_src(),
))
}
_ => {}
Ok(())
}
- #[inline]
- pub fn add_lines_read(&mut self, lines_read: usize) {
- self.lexer.line_num += lines_read;
- }
-
#[inline]
pub fn lines_read(&self) -> usize {
self.lexer.line_num
&mut self,
op_dir: &CompositeOpDir,
tokens: Tokens,
- ) -> Result<Term, ParserError> {
+ ) -> Result<FocusedHeap, ParserError> {
self.tokens = match tokens {
Tokens::Default => read_tokens(&mut self.lexer)?,
Tokens::Provided(tokens) => tokens,
self.reduce_op(1400);
- if self.terms.len() > 1 || self.stack.len() > 1 {
+ if self.stack.len() > 1 || self.terms.is_empty() {
return Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
+ self.lexer.loc_to_err_src(),
));
}
- match self.terms.pop() {
- Some(term) => {
- if self.terms.is_empty() {
- Ok(term)
- } else {
- Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
- ))
- }
- }
+ match self.stack.pop() {
+ Some(TokenDesc {
+ tt: TokenType::Term { heap_loc },
+ ..
+ }) => Ok(FocusedHeap {
+ heap: mem::replace(&mut self.terms, vec![]),
+ focus: heap_loc.get_value() as usize,
+ var_locs: mem::replace(&mut self.var_locs, VarLocs::default()),
+ }),
_ => Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
+ self.lexer.loc_to_err_src(),
)),
}
}
impl<T: RawBlockTraits> RawBlock<T> {
#[inline]
- fn empty_block() -> Self {
+ pub(crate) fn empty_block() -> Self {
RawBlock {
base: ptr::null(),
top: ptr::null(),
use crate::parser::parser::*;
use crate::atom_table::*;
-use crate::forms::*;
-use crate::iterators::*;
-use crate::machine::heap::*;
use crate::machine::machine_errors::*;
-use crate::machine::machine_indices::*;
-use crate::machine::machine_state::MachineState;
+use crate::machine::machine_state::{MachineState, copy_and_align_iter};
use crate::machine::streams::*;
use crate::parser::char_reader::*;
#[cfg(feature = "repl")]
use crate::repl_helper::Helper;
-use crate::types::*;
-
-use fxhash::FxBuildHasher;
#[cfg(feature = "repl")]
use rustyline::error::ReadlineError;
#[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<R: CharRead>(
parser: &mut Parser<'_, R>,
) -> Result<bool, ParserError> {
}
}
-pub(crate) fn error_after_read_term<R>(
+pub(crate) fn error_after_read_term(
err: ParserError,
prior_num_lines_read: usize,
- parser: &Parser<R>,
) -> CompilationError {
if err.is_unexpected_eof() {
- let line_num = parser.lexer.line_num;
- let col_num = parser.lexer.col_num;
+ let ParserErrorSrc { line_num, col_num } = err.err_src();
// rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here
if !(line_num == prior_num_lines_read && col_num == 0) {
- return CompilationError::from(ParserError::IncompleteReduction(line_num, col_num));
+ return CompilationError::from(ParserError::IncompleteReduction(err.err_src()));
}
}
CompilationError::from(err)
}
+impl FocusedHeap {
+ pub fn to_machine_heap(mut self, machine_st: &mut MachineState) -> TermWriteResult {
+ let heap_len = machine_st.heap.len();
+ machine_st.heap.extend(copy_and_align_iter(self.heap.drain(..), 0, heap_len as i64));
+
+ let mut var_locs = VarLocs::default();
+
+ for (var_loc, var_ptrs) in self.var_locs.drain(..) {
+ var_locs.insert(var_loc + heap_len, var_ptrs);
+ }
+
+ TermWriteResult {
+ heap_loc: self.focus + heap_len,
+ var_locs,
+ }
+ }
+}
+
impl MachineState {
- pub(crate) fn read(
+ pub(crate) fn read<R: CharRead>(
&mut self,
- mut inner: Stream,
+ inner: R,
op_dir: &OpDir,
- ) -> Result<TermWriteResult, CompilationError> {
- let (term, num_lines_read) = {
- let prior_num_lines_read = inner.lines_read();
- let mut parser = Parser::new(inner, self);
- let op_dir = CompositeOpDir::new(op_dir, None);
+ ) -> Result<(FocusedHeap, usize), ParserError> {
+ let mut parser = Parser::new(inner, self);
+ let op_dir = CompositeOpDir::new(op_dir, None);
- parser.add_lines_read(prior_num_lines_read);
+ let term_result = parser.read_term(&op_dir, Tokens::Default);
+ let lines_read = parser.lines_read();
- let term = parser
- .read_term(&op_dir, Tokens::Default)
- .map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from
+ term_result.map(|term| (term, lines_read))
+ }
- (term, parser.lines_read() - prior_num_lines_read)
+ pub(crate) fn read_to_heap(
+ &mut self,
+ mut inner: Stream,
+ op_dir: &OpDir,
+ ) -> Result<TermWriteResult, CompilationError> {
+ let prior_num_lines_read = inner.lines_read();
+ let term = match self.read(inner, op_dir) {
+ Ok((term, num_lines_read)) => {
+ inner.add_lines_read(num_lines_read);
+ term
+ }
+ Err(e) => {
+ return Err(error_after_read_term(e, prior_num_lines_read));
+ }
};
- inner.add_lines_read(num_lines_read);
- write_term_to_heap(&term, &mut self.heap, &self.atom_tbl)
+ Ok(term.to_machine_heap(self))
}
}
}
}
}
-
#[inline]
fn consume(&mut self, nread: usize) {
self.pending_input.consume(nread);
}
}
-#[inline]
-pub(crate) fn write_term_to_heap(
- term: &Term,
- heap: &mut Heap,
- atom_tbl: &AtomTable,
-) -> Result<TermWriteResult, CompilationError> {
- let term_writer = TermWriter::new(heap, atom_tbl);
- term_writer.write_term_to_heap(term)
-}
-
-#[derive(Debug)]
-struct TermWriter<'a, 'b> {
- heap: &'a mut Heap,
- atom_tbl: &'b AtomTable,
- queue: SubtermDeque,
- var_dict: HeapVarDict,
-}
-
#[derive(Debug)]
pub struct TermWriteResult {
pub heap_loc: usize,
- pub var_dict: HeapVarDict,
-}
-
-impl<'a, 'b> TermWriter<'a, 'b> {
- #[inline]
- fn new(heap: &'a mut Heap, atom_tbl: &'b AtomTable) -> Self {
- TermWriter {
- heap,
- atom_tbl,
- queue: SubtermDeque::new(),
- var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
- }
- }
-
- #[inline]
- fn modify_head_of_queue(&mut self, term: &TermRef, h: usize) {
- if let Some((arity, site_h)) = self.queue.pop_front() {
- self.heap[site_h] = self.term_as_addr(term, h);
-
- if arity > 1 {
- self.queue.push_front((arity - 1, site_h + 1));
- }
- }
- }
-
- #[inline]
- fn push_stub_addr(&mut self) {
- let h = self.heap.len();
- self.heap.push(heap_loc_as_cell!(h));
- }
-
- fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue {
- match term {
- &TermRef::Cons(..) => list_loc_as_cell!(h),
- &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
- TermRef::CompleteString(_, _, src) => {
- if src.as_str().is_empty() {
- empty_list_as_cell!()
- } else if self.heap[h].get_tag() == HeapCellValueTag::CStr {
- heap_loc_as_cell!(h)
- } else {
- pstr_loc_as_cell!(h)
- }
- }
- &TermRef::PartialString(..) => pstr_loc_as_cell!(h),
- &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal),
- &TermRef::Clause(_, _, _, subterms) if subterms.is_empty() => heap_loc_as_cell!(h),
- &TermRef::Clause(..) => str_loc_as_cell!(h),
- }
- }
-
- fn write_term_to_heap(mut self, term: &Term) -> Result<TermWriteResult, CompilationError> {
- let heap_loc = self.heap.len();
-
- for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
- let h = self.heap.len();
-
- match &term {
- &TermRef::Cons(Level::Root, ..) => {
- self.queue.push_back((2, h + 1));
- self.heap.push(list_loc_as_cell!(h + 1));
-
- self.push_stub_addr();
- self.push_stub_addr();
-
- continue;
- }
- &TermRef::Cons(..) => {
- self.queue.push_back((2, h));
-
- self.push_stub_addr();
- self.push_stub_addr();
- }
- &TermRef::Clause(Level::Root, _, name, subterms) => {
- if subterms.len() > MAX_ARITY {
- return Err(CompilationError::ExceededMaxArity);
- }
-
- self.heap.push(if subterms.is_empty() {
- heap_loc_as_cell!(heap_loc + 1)
- } else {
- str_loc_as_cell!(heap_loc + 1)
- });
-
- self.queue.push_back((subterms.len(), h + 2));
- let named = atom_as_cell!(name, subterms.len());
-
- self.heap.push(named);
-
- for _ in 0..subterms.len() {
- self.push_stub_addr();
- }
-
- continue;
- }
- &TermRef::Clause(_, _, name, subterms) => {
- self.queue.push_back((subterms.len(), h + 1));
- let named = atom_as_cell!(name, subterms.len());
-
- self.heap.push(named);
-
- for _ in 0..subterms.len() {
- self.push_stub_addr();
- }
- }
- &TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => {
- let addr = self.term_as_addr(&term, h);
- self.heap.push(addr);
- }
- &TermRef::Var(Level::Root, _, ref var_ptr) => {
- let addr = self.term_as_addr(&term, h);
- self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr);
- self.heap.push(addr);
- }
- &TermRef::AnonVar(_) => {
- if let Some((arity, site_h)) = self.queue.pop_front() {
- self.var_dict
- .insert(VarKey::AnonVar(h), heap_loc_as_cell!(site_h));
-
- if arity > 1 {
- self.queue.push_front((arity - 1, site_h + 1));
- }
- }
-
- continue;
- }
- TermRef::CompleteString(_, _, src) => {
- let src = src.as_str().to_owned();
- put_complete_string(self.heap, &src, self.atom_tbl);
- }
- &TermRef::PartialString(lvl, _, src, _) => {
- if let Level::Root = lvl {
- // Var tags can't refer directly to partial strings,
- // so a PStrLoc cell must be pushed.
- self.heap.push(pstr_loc_as_cell!(heap_loc + 1));
- }
-
- allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
-
- let h = self.heap.len();
- self.queue.push_back((1, h - 1));
-
- if let Level::Root = lvl {
- continue;
- }
- }
- TermRef::Var(.., var) => {
- if let Some((arity, site_h)) = self.queue.pop_front() {
- let var_key = VarKey::VarPtr(var.clone());
-
- if let Some(addr) = self.var_dict.get(&var_key).cloned() {
- self.heap[site_h] = addr;
- } else {
- self.var_dict.insert(var_key, heap_loc_as_cell!(site_h));
- }
-
- if arity > 1 {
- self.queue.push_front((arity - 1, site_h + 1));
- }
- }
-
- continue;
- }
- _ => {}
- };
-
- self.modify_head_of_queue(&term, h);
- }
-
- Ok(TermWriteResult {
- heap_loc,
- var_dict: self.var_dict,
- })
- }
+ pub var_locs: VarLocs,
}
use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
-use crate::iterators::*;
use crate::types::*;
pub(crate) struct FactInstruction;
pub(crate) struct QueryInstruction;
pub(crate) trait CompilationTarget<'a> {
- type Iterator: Iterator<Item = TermRef<'a>>;
-
- fn iter(term: &'a Term) -> Self::Iterator;
-
fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
fn to_list(lvl: Level, r: RegType) -> Instruction;
fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction;
}
impl<'a> CompilationTarget<'a> for FactInstruction {
- type Iterator = FactIterator<'a>;
-
- fn iter(term: &'a Term) -> Self::Iterator {
- breadth_first_iter(term, RootIterationPolicy::NotIterated)
- }
-
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
}
}
impl<'a> CompilationTarget<'a> for QueryInstruction {
- type Iterator = QueryIterator<'a>;
-
- fn iter(term: &'a Term) -> Self::Iterator {
- post_order_iter(term)
- }
-
fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction {
Instruction::PutStructure(name, arity, r)
}
\+ 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),
safety: VarSafetyStatus,
to_perm_var_num: Option<usize>,
},
- Perm(usize, PermVarAllocation), // stack offset, allocation info
+ Perm { reg: usize, allocation: PermVarAllocation }, // stack offset, allocation info
}
impl VarAlloc {
pub(crate) fn as_reg_type(&self) -> RegType {
match *self {
VarAlloc::Temp { temp_reg, .. } => RegType::Temp(temp_reg),
- VarAlloc::Perm(r, _) => RegType::Perm(r),
+ VarAlloc::Perm { reg, .. } => RegType::Perm(reg),
}
}
#[inline]
pub(crate) fn set_register(&mut self, reg_num: usize) {
match self {
- VarAlloc::Perm(ref mut p, _) => *p = reg_num,
+ VarAlloc::Perm { ref mut reg, .. } => *reg = reg_num,
VarAlloc::Temp {
ref mut temp_reg, ..
} => *temp_reg = reg_num,
impl Default for VariableRecord {
fn default() -> Self {
VariableRecord {
- allocation: VarAlloc::Perm(0, PermVarAllocation::Pending),
+ allocation: VarAlloc::Perm { reg: 0, allocation: PermVarAllocation::Pending },
num_occurrences: 0,
running_count: 0,
}
fn syntax_error() {
load_module_test(
"tests-pl/syntax_error.pl",
- " error(syntax_error(incomplete_reduction),read_term/3:6).\n",
+ " error(syntax_error(incomplete_reduction),read_term/3:3).\n",
);
}