use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; use crate::machine::machine_indices::*; use crate::parser::ast::*; use std::cell::Cell; use std::collections::VecDeque; use std::fmt; use std::iter::*; use std::rc::Rc; use std::vec::Vec; #[derive(Debug, Clone)] pub(crate) enum TermRef<'a> { AnonVar(Level), Cons(Level, &'a Cell, &'a Term, &'a Term), Literal(Level, &'a Cell, &'a Literal), Clause(Level, &'a Cell, ClauseType, &'a Vec), PartialString(Level, &'a Cell, Atom, &'a Option>), Var(Level, &'a Cell, Rc), } 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, ..) => lvl, TermRef::PartialString(lvl, ..) => lvl, } } } #[derive(Debug)] pub(crate) enum TermIterState<'a> { AnonVar(Level), Literal(Level, &'a Cell, &'a Literal), Clause(Level, usize, &'a Cell, ClauseType, &'a Vec), InitialCons(Level, &'a Cell, &'a Term, &'a Term), FinalCons(Level, &'a Cell, &'a Term, &'a Term), InitialPartialString(Level, &'a Cell, Atom, &'a Option>), FinalPartialString(Level, &'a Cell, Atom, &'a Option>), Var(Level, &'a Cell, Rc), } 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) => { let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default()); TermIterState::Clause(lvl, 0, cell, ct, subterms) } Term::Cons(cell, head, tail) => { TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()) } Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant), Term::PartialString(cell, string_buf, tail) => { TermIterState::InitialPartialString(lvl, cell, *string_buf, tail) } Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()), } } } #[derive(Debug)] pub(crate) struct QueryIterator<'a> { state_stack: Vec>, } 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 from_rule_head_clause(terms: &'a Vec) -> Self { let state_stack = terms .iter() .rev() .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt)) .collect(); QueryIterator { state_stack } } fn from_term(term: &'a Term) -> Self { let state = match term { Term::AnonVar | Term::Cons(..) | Term::Literal(..) | Term::PartialString(..) => { return QueryIterator { state_stack: vec![], } } Term::Clause(r, name, terms) => TermIterState::Clause( Level::Root, 0, r, ClauseType::from(*name, terms.len()), terms, ), Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()), }; QueryIterator { state_stack: vec![state], } } fn new(term: &'a QueryTerm) -> Self { match term { &QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => { let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms); QueryIterator { state_stack: vec![state], } } &QueryTerm::Clause(ref cell, ref ct, ref terms, _) => { let state = TermIterState::Clause(Level::Root, 0, cell, ct.clone(), terms); QueryIterator { state_stack: vec![state], } } &QueryTerm::UnblockedCut(ref cell) => { let state = TermIterState::Var(Level::Root, cell, Rc::new("!".to_string())); QueryIterator { state_stack: vec![state], } } &QueryTerm::GetLevelAndUnify(ref cell, ref var) => { let state = TermIterState::Var(Level::Root, cell, var.clone()); QueryIterator { state_stack: vec![state], } } &QueryTerm::Jump(ref vars) => { let state_stack = vars .iter() .rev() .map(|t| TermIterState::subterm_to_state(Level::Shallow, t)) .collect(); QueryIterator { state_stack } } &QueryTerm::BlockedCut => QueryIterator { state_stack: vec![], }, } } } impl<'a> Iterator for QueryIterator<'a> { type Item = TermRef<'a>; fn next(&mut self) -> Option { while let Some(iter_state) = self.state_stack.pop() { match iter_state { TermIterState::AnonVar(lvl) => { return Some(TermRef::AnonVar(lvl)); } TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => { if child_num == child_terms.len() { match ct { ClauseType::CallN(_) => { self.push_subterm(Level::Shallow, &child_terms[0]); } ClauseType::Named(..) => { return match lvl { Level::Root => None, lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)), } } _ => { return None; } }; } else { self.state_stack.push(TermIterState::Clause( lvl, child_num + 1, cell, ct, 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)); 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)); if let Some(tail) = tail { self.push_subterm(lvl.child_level(), tail); } } TermIterState::FinalPartialString(lvl, cell, string, tail) => { return Some(TermRef::PartialString(lvl, cell, string, tail)); } 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) => { return Some(TermRef::Var(lvl, cell, var)); } }; } None } } #[derive(Debug)] pub(crate) struct FactIterator<'a> { state_queue: VecDeque>, iterable_root: bool, } impl<'a> FactIterator<'a> { fn push_subterm(&mut self, lvl: Level, term: &'a Term) { self.state_queue .push_back(TermIterState::subterm_to_state(lvl, term)); } pub(crate) fn from_rule_head_clause(terms: &'a Vec) -> Self { let state_queue = terms .iter() .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt)) .collect(); FactIterator { state_queue, iterable_root: false, } } fn new(term: &'a Term, iterable_root: bool) -> Self { let states = match term { Term::AnonVar => { vec![TermIterState::AnonVar(Level::Root)] } Term::Clause(cell, name, terms) => { let ct = ClauseType::from(*name, terms.len()); vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)] } Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons( Level::Root, cell, head.as_ref(), tail.as_ref(), )], Term::PartialString(cell, string_buf, tail_opt) => { vec![TermIterState::InitialPartialString( Level::Root, cell, *string_buf, tail_opt, )] } Term::Literal(cell, constant) => { vec![TermIterState::Literal(Level::Root, cell, constant)] } Term::Var(cell, var) => { vec![TermIterState::Var(Level::Root, cell, var.clone())] } }; FactIterator { state_queue: VecDeque::from(states), iterable_root, } } } impl<'a> Iterator for FactIterator<'a> { type Item = TermRef<'a>; fn next(&mut self) -> Option { while let Some(state) = self.state_queue.pop_front() { match state { TermIterState::AnonVar(lvl) => { return Some(TermRef::AnonVar(lvl)); } TermIterState::Clause(lvl, _, cell, ct, child_terms) => { for child_term in child_terms { self.push_subterm(lvl.child_level(), child_term); } match lvl { Level::Root if !self.iterable_root => continue, _ => return Some(TermRef::Clause(lvl, cell, ct, child_terms)), }; } TermIterState::InitialCons(lvl, cell, head, tail) => { self.push_subterm(Level::Deep, head); self.push_subterm(Level::Deep, tail); return Some(TermRef::Cons(lvl, cell, head, tail)); } TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => { if let Some(tail) = tail_opt { self.push_subterm(Level::Deep, tail); } return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt)); } TermIterState::Literal(lvl, cell, constant) => { return Some(TermRef::Literal(lvl, cell, constant)) } TermIterState::Var(lvl, cell, var) => { return Some(TermRef::Var(lvl, cell, var)); } _ => {} } } None } } pub(crate) fn post_order_iter<'a>(term: &'a Term) -> QueryIterator<'a> { QueryIterator::from_term(term) } pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: bool) -> FactIterator<'a> { FactIterator::new(term, iterable_root) } #[derive(Debug)] pub(crate) enum ChunkedTerm<'a> { HeadClause(Atom, &'a Vec), BodyTerm(&'a QueryTerm), } pub(crate) fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> QueryIterator<'a> { QueryIterator::new(query_term) } impl<'a> ChunkedTerm<'a> { pub(crate) fn post_order_iter(&self) -> QueryIterator<'a> { match self { &ChunkedTerm::BodyTerm(qt) => QueryIterator::new(qt), &ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms), } } } fn contains_cut_var<'a, Iter: Iterator>(terms: Iter) -> bool { for term in terms { if let &Term::Var(_, ref var) = term { if var.as_str() == "!" { return true; } } } false } pub(crate) struct ChunkedIterator<'a> { pub(crate) chunk_num: usize, iter: Box> + 'a>, deep_cut_encountered: bool, cut_var_in_head: bool, } impl<'a> fmt::Debug for ChunkedIterator<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("ChunkedIterator") .field("chunk_num", &self.chunk_num) // Hacky solution. .field("iter", &"Box> + 'a>") .field("deep_cut_encountered", &self.deep_cut_encountered) .field("cut_var_in_head", &self.cut_var_in_head) .finish() } } type ChunkedIteratorItem<'a> = (usize, usize, Vec>); type RuleBodyIteratorItem<'a> = (usize, usize, Vec<&'a QueryTerm>); impl<'a> ChunkedIterator<'a> { pub(crate) fn rule_body_iter(self) -> Box> + 'a> { Box::new(self.filter_map(|(cn, lt_arity, terms)| { let filtered_terms: Vec<_> = terms .into_iter() .filter_map(|ct| match ct { ChunkedTerm::BodyTerm(qt) => Some(qt), _ => None, }) .collect(); if filtered_terms.is_empty() { None } else { Some((cn, lt_arity, filtered_terms)) } })) } /* pub(crate) fn from_term_sequence(terms: &'a [QueryTerm]) -> Self { ChunkedIterator { chunk_num: 0, iter: Box::new(terms.iter().map(|t| ChunkedTerm::BodyTerm(t))), deep_cut_encountered: false, cut_var_in_head: false, } } */ pub(crate) fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec) -> Self { let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1))); let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t))); ChunkedIterator { chunk_num: 0, iter: Box::new(iter), deep_cut_encountered: false, cut_var_in_head: false, } } pub(crate) fn from_rule(rule: &'a Rule) -> Self { let &Rule { head: (ref name, ref args, ref p1), ref clauses, } = rule; let iter = once(ChunkedTerm::HeadClause(name.clone(), args)); let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1))); let iter = iter.chain(inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)))); ChunkedIterator { chunk_num: 0, iter: Box::new(iter), deep_cut_encountered: false, cut_var_in_head: false, } } pub(crate) fn encountered_deep_cut(&self) -> bool { self.deep_cut_encountered } fn take_chunk(&mut self, term: ChunkedTerm<'a>) -> (usize, usize, Vec>) { let mut arity = 0; let mut item = Some(term); let mut result = Vec::new(); while let Some(term) = item { match term { ChunkedTerm::HeadClause(_, terms) => { if contains_cut_var(terms.iter()) { self.cut_var_in_head = true; } result.push(term); } ChunkedTerm::BodyTerm(&QueryTerm::Jump(ref vars)) => { result.push(term); arity = vars.len(); if contains_cut_var(vars.iter()) && !self.cut_var_in_head { self.deep_cut_encountered = true; } break; } ChunkedTerm::BodyTerm(&QueryTerm::BlockedCut) => { result.push(term); if self.chunk_num > 0 { self.deep_cut_encountered = true; } } ChunkedTerm::BodyTerm(&QueryTerm::GetLevelAndUnify(..)) => { self.deep_cut_encountered = true; result.push(term); arity = 1; break; } ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => { self.deep_cut_encountered = true; result.push(term); } ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) => { result.push(term) } ChunkedTerm::BodyTerm(&QueryTerm::Clause( _, ClauseType::CallN(_), ref subterms, _, )) => { result.push(term); arity = subterms.len() + 1; break; } ChunkedTerm::BodyTerm(qt) => { result.push(term); arity = qt.arity(); break; } }; item = self.iter.next(); } let chunk_num = self.chunk_num; self.chunk_num += 1; (chunk_num, arity, result) } } impl<'a> Iterator for ChunkedIterator<'a> { // the chunk number, last term arity, and vector of references. type Item = ChunkedIteratorItem<'a>; fn next(&mut self) -> Option { self.iter.next().map(|term| self.take_chunk(term)) } }