}
impl PredicateClause {
- pub fn name(&self) -> &Atom {
+ pub fn first_arg(&self) -> Option<&Term> {
match self {
- &PredicateClause::Fact(ref t) => t.name().unwrap(),
- &PredicateClause::Rule(ref rule) => rule.head.0.name().unwrap()
+ &PredicateClause::Fact(ref term) => term.first_arg(),
+ &PredicateClause::Rule(ref rule) =>
+ if let &QueryTerm::Term(ref term) = &rule.head.0 {
+ term.first_arg()
+ } else {
+ None
+ }
}
}
- pub fn first_arg(&self) -> Option<&Term> {
+ pub fn arity(&self) -> usize {
match self {
- &PredicateClause::Fact(ref t) => t.first_arg(),
- &PredicateClause::Rule(ref rule) => rule.head.0.first_arg()
+ &PredicateClause::Fact(ref term) => term.arity(),
+ &PredicateClause::Rule(ref rule) => rule.head.0.arity()
}
}
- pub fn arity(&self) -> usize {
+ pub fn name(&self) -> Option<&Atom> {
match self {
- &PredicateClause::Fact(ref t) => t.arity(),
- &PredicateClause::Rule(ref rule) => rule.head.0.arity()
+ &PredicateClause::Fact(ref term) => term.name(),
+ &PredicateClause::Rule(ref rule) =>
+ if let &QueryTerm::Term(ref term) = &rule.head.0 {
+ term.name()
+ } else {
+ None
+ }
}
}
}
IncompleteReduction,
InconsistentDeclaration,
InconsistentPredicate,
+ InvalidRuleHead,
ParseBigInt,
ParseFloat(ParseFloatError),
// TokenTooLong,
}
impl QueryTerm {
- pub fn to_ref(&self) -> QueryTermRef {
+ pub fn arity(&self) -> usize {
match self {
- &QueryTerm::CallN(ref terms) =>
- QueryTermRef::CallN(terms),
- &QueryTerm::Catch(ref terms) =>
- QueryTermRef::Catch(terms),
- &QueryTerm::Cut =>
- QueryTermRef::Cut,
- &QueryTerm::Is(ref terms) =>
- QueryTermRef::Is(terms),
- &QueryTerm::IsAtomic(ref terms) =>
- QueryTermRef::IsAtomic(terms.first().unwrap()),
- &QueryTerm::IsVar(ref terms) =>
- QueryTermRef::IsVar(terms.first().unwrap()),
- &QueryTerm::Term(ref term) =>
- QueryTermRef::Term(term),
- &QueryTerm::Throw(ref t) =>
- QueryTermRef::Throw(t)
+ &QueryTerm::Catch(_) => 3,
+ &QueryTerm::Throw(_) => 1,
+ &QueryTerm::Is(_) => 2,
+ &QueryTerm::IsAtomic(_) => 1,
+ &QueryTerm::IsVar(_) => 1,
+ &QueryTerm::CallN(ref terms) => terms.len(),
+ &QueryTerm::Cut => 0,
+ &QueryTerm::Term(ref term) => term.arity(),
}
}
}
pub struct Rule {
- pub head: (Term, QueryTerm),
+ pub head: (QueryTerm, QueryTerm),
pub clauses: Vec<QueryTerm>
}
}
}
-#[derive(Clone, Copy)]
-pub enum QueryTermRef<'a> {
- CallN(&'a Vec<Box<Term>>),
- Catch(&'a Vec<Box<Term>>),
- Cut,
- Is(&'a Vec<Box<Term>>),
- IsAtomic(&'a Term),
- IsVar(&'a Term),
- Term(&'a Term),
- Throw(&'a Vec<Box<Term>>)
-}
-
-impl<'a> QueryTermRef<'a> {
- pub fn arity(self) -> usize {
- match self {
- QueryTermRef::Catch(_) => 3,
- QueryTermRef::Throw(_) => 1,
- QueryTermRef::Is(_) => 2,
- QueryTermRef::IsAtomic(_) => 1,
- QueryTermRef::IsVar(_) => 1,
- QueryTermRef::CallN(terms) => terms.len(),
- QueryTermRef::Cut => 0,
- QueryTermRef::Term(term) => term.arity(),
- }
- }
-}
-
pub enum ChoiceInstruction {
RetryMeElse(usize),
TrustMe,
}
}
- pub fn is_clause(&self) -> bool {
- if let &Term::Clause(_, _, _) = self {
- true
- } else {
- false
- }
- }
-
pub fn is_callable(&self) -> bool {
match self {
&Term::Clause(_, _, _) | &Term::Constant(_, Constant::Atom(_)) =>
let mut vs = VariableFixtures::new();
let at_rule_head = iter.at_rule_head();
- while let Some((chunk_num, last_term_arity, terms)) = iter.next() {
- for (i, term_or_cut_ref) in terms.iter().enumerate() {
+ while let Some((chunk_num, lt_arity, terms)) = iter.next() {
+ for (i, query_term) in terms.iter().enumerate() {
let term_loc = if chunk_num == 0 && i == 0 && at_rule_head {
GenContext::Head
} else if i < terms.len() - 1 {
GenContext::Last(chunk_num)
};
- self.update_var_count(term_or_cut_ref.post_order_iter());
- vs.mark_vars_in_chunk(term_or_cut_ref.post_order_iter(),
- last_term_arity,
- term_loc);
+ self.update_var_count(query_term.post_order_iter());
+ vs.mark_vars_in_chunk(query_term.post_order_iter(), lt_arity, term_loc);
}
}
ConjunctInfo::new(vs, num_of_chunks, has_deep_cut)
}
- fn add_conditional_call(compiled_query: &mut Code, qt: QueryTermRef, pvs: usize)
+ fn add_conditional_call(compiled_query: &mut Code, qt: &QueryTerm, pvs: usize)
{
match qt {
- QueryTermRef::CallN(terms) => {
+ &QueryTerm::CallN(ref terms) => {
let call = ControlInstruction::CallN(terms.len());
compiled_query.push(Line::Control(call));
},
- QueryTermRef::Catch(_) =>
+ &QueryTerm::Catch(_) =>
compiled_query.push(Line::Control(ControlInstruction::CatchCall)),
- QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) =>
+ &QueryTerm::IsAtomic(_) | &QueryTerm::IsVar(_) =>
compiled_query.push(proceed!()),
- QueryTermRef::Term(&Term::Constant(_, Constant::Atom(ref atom))) => {
+ &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref atom))) => {
let call = ControlInstruction::Call(atom.clone(), 0, pvs);
compiled_query.push(Line::Control(call));
},
- QueryTermRef::Term(&Term::Clause(_, ref atom, ref terms)) => {
+ &QueryTerm::Term(Term::Clause(_, ref atom, ref terms)) => {
let call = ControlInstruction::Call(atom.clone(), terms.len(), pvs);
compiled_query.push(Line::Control(call));
},
- QueryTermRef::Throw(_) =>
+ &QueryTerm::Throw(_) =>
compiled_query.push(Line::Control(ControlInstruction::ThrowCall)),
_ => {}
}
GenContext::Last(chunk_num)
};
- match term {
- &QueryTermRef::Cut if i + 1 < terms.len() => {
- code.push(if chunk_num == 0 {
- Line::Cut(CutInstruction::NeckCut(Terminal::Non))
+ match *term {
+ &QueryTerm::Cut => {
+ let term = if i + 1 < terms.len() {
+ Terminal::Non
} else {
- Line::Cut(CutInstruction::Cut(Terminal::Non))
- });
- },
- &QueryTermRef::Cut => {
+ Terminal::Terminal
+ };
+
code.push(if chunk_num == 0 {
- Line::Cut(CutInstruction::NeckCut(Terminal::Terminal))
+ Line::Cut(CutInstruction::NeckCut(term))
} else {
- Line::Cut(CutInstruction::Cut(Terminal::Terminal))
+ Line::Cut(CutInstruction::Cut(term))
});
},
- &QueryTermRef::Is(terms) => {
+ &QueryTerm::Is(ref terms) => {
let mut arith_code = {
let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings());
evaluator.eval(terms[1].as_ref())?
}
}
},
- &QueryTermRef::IsAtomic(inner_term) =>
- match inner_term {
+ &QueryTerm::IsAtomic(ref inner_term) =>
+ match inner_term[0].as_ref() {
&Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
code.push(fail!());
},
}
},
},
- &QueryTermRef::IsVar(inner_term) =>
- match inner_term {
+ &QueryTerm::IsVar(ref inner_term) =>
+ match inner_term[0].as_ref() {
&Term::Constant(_, _) | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
code.push(fail!());
},
let iter = term.post_order_iter();
code.push(Line::Query(self.compile_target(iter, term_loc, is_exposed)));
- Self::add_conditional_call(code, *term, conjunct_info.perm_vars());
+ Self::add_conditional_call(code, term, conjunct_info.perm_vars());
},
_ => {
let num_vars = conjunct_info.perm_vs.vars_above_threshold(i + 1);
- self.compile_query_line(*term, term_loc, code, num_vars, is_exposed);
+ self.compile_query_line(term, term_loc, code, num_vars, is_exposed);
},
};
}
}
- fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: QueryTermRef<'a>)
+ fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm)
{
//TODO: temporary workaround for inlined builtins.
match toc {
- QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) =>
+ &QueryTerm::IsAtomic(_) | &QueryTerm::IsVar(_) =>
code.push(proceed!()),
_ => {}
}
self.marker.advance(GenContext::Head, p0.arity());
self.compile_seq_prelude(&conjunct_info, &mut code);
- if p0.is_clause() {
- let iter = FactInstruction::iter(p0);
- code.push(Line::Fact(self.compile_target(iter, GenContext::Head, false)));
- }
-
- let iter = ChunkedIterator::from_rule_body(p1, clauses);
- try!(self.compile_seq(iter, &conjunct_info, &mut code, false));
+ if let &QueryTerm::Term(ref term) = p0 {
+ if let &Term::Clause(_, _, _) = term {
+ let iter = FactInstruction::iter(term);
+ code.push(Line::Fact(self.compile_target(iter, GenContext::Head, false)));
+ }
+
+ let iter = ChunkedIterator::from_rule_body(p1, clauses);
+ try!(self.compile_seq(iter, &conjunct_info, &mut code, false));
- if conjunct_info.allocates() {
- let index = if let &Line::Control(_) = code.last().unwrap() {
- code.len() - 2
- } else {
- code.len() - 1
- };
+ if conjunct_info.allocates() {
+ let index = if let &Line::Control(_) = code.last().unwrap() {
+ code.len() - 2
+ } else {
+ code.len() - 1
+ };
- if let &mut Line::Query(ref mut query) = &mut code[index] {
- conjunct_info.perm_vs.mark_unsafe_vars_in_rule(p0, query);
+ if let &mut Line::Query(ref mut query) = &mut code[index] {
+ conjunct_info.perm_vs.mark_unsafe_vars_in_rule(term, query);
+ }
}
- }
- Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1).to_ref());
- Ok(code)
+ Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
+ Ok(code)
+ } else {
+ Err(ParserError::InvalidRuleHead)
+ }
}
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact)
let mut code = Vec::new();
- if term.is_clause() {
+ if let &Term::Clause(_, _, _) = term {
let iter = FactInstruction::iter(term);
let mut compiled_fact = self.compile_target(iter, GenContext::Head, false);
}
fn compile_query_line(&mut self,
- term: QueryTermRef<'a>,
+ term: &'a QueryTerm,
term_loc: GenContext,
code: &mut Code,
index: usize,
}
}
- Self::compile_cleanup(&mut code, &conjunct_info, query.last().unwrap().to_ref());
+ if let Some(query_term) = query.last() {
+ Self::compile_cleanup(&mut code, &conjunct_info, query_term);
+ }
+
Ok(code)
}
fn populate_conflict_set(&mut self) {
if self.last_term_arity > 0 {
- let arity = self.last_term_arity;
+ let arity = self.last_term_arity;
let mut conflict_set : BTreeSet<usize> = (1..arity).collect();
for &(_, reg) in self.use_set.iter() {
var_count
}
- pub fn mark_vars_in_chunk<Iter>(&mut self,
- iter: Iter,
- last_term_arity: usize,
- term_loc: GenContext)
+ pub fn mark_vars_in_chunk<Iter>(&mut self, iter: Iter, lt_arity: usize, term_loc: GenContext)
where Iter: Iterator<Item=TermRef<'a>>
{
let chunk_num = term_loc.chunk_num();
for term_ref in iter {
if let TermRef::Var(lvl, cell, var) = term_ref {
let mut status = self.0.remove(var)
- .unwrap_or((VarStatus::Temp(chunk_num, TempVarData::new(last_term_arity)),
- Vec::new()));
+ .unwrap_or((VarStatus::Temp(chunk_num, TempVarData::new(lt_arity)), Vec::new()));
status.1.push(cell);
pub fn size(&self) -> usize {
self.0.len()
}
-
+
pub fn set_perm_vals(&self, has_deep_cuts: bool)
{
let mut values_vec : Vec<_> = self.values()
}
}
- fn record_unsafe_vars(&self, unsafe_vars: &mut HashMap<RegType, bool>) {
+ fn record_unsafe_vars(&self, unsafe_vars: &mut HashMap<RegType, bool>) {
for &(_, ref cb) in self.values() {
match cb.first() {
Some(index) => {
};
}
}
-
+
fn mark_head_vars_as_safe(&self, head: &Term, unsafe_vars: &mut HashMap<RegType, bool>)
- {
+ {
for term_ref in head.breadth_first_iter() {
match term_ref {
TermRef::Var(_, cell, _) => {
self.record_unsafe_vars(&mut unsafe_vars);
self.mark_unsafe_vars(&mut unsafe_vars, query);
}
-
+
pub fn mark_unsafe_vars_in_rule(&self, head: &Term, query: &mut CompiledQuery)
{
let mut unsafe_vars = HashMap::new();
- self.record_unsafe_vars(&mut unsafe_vars);
+ self.record_unsafe_vars(&mut unsafe_vars);
self.mark_head_vars_as_safe(head, &mut unsafe_vars);
self.mark_unsafe_vars(&mut unsafe_vars, query);
}
QueryIterator { state_stack: vec![state] }
}
- fn new(term: QueryTermRef<'a>) -> Self {
+ fn new(term: &'a QueryTerm) -> Self {
match term {
- QueryTermRef::CallN(terms) => {
+ &QueryTerm::CallN(ref terms) => {
let state = IteratorState::Clause(1, ClauseType::CallN, terms);
QueryIterator { state_stack: vec![state] }
},
- QueryTermRef::Catch(terms) => {
+ &QueryTerm::Catch(ref terms) => {
let state = IteratorState::Clause(0, ClauseType::Catch, terms);
QueryIterator { state_stack: vec![state] }
},
- QueryTermRef::Is(terms) => {
+ &QueryTerm::Is(ref terms) => {
let state = IteratorState::Clause(0, ClauseType::Is, terms);
QueryIterator { state_stack: vec![state] }
},
- QueryTermRef::IsAtomic(term) | QueryTermRef::IsVar(term) | QueryTermRef::Term(term) =>
+ &QueryTerm::IsAtomic(ref terms) | &QueryTerm::IsVar(ref terms) =>
+ Self::from_term(terms[0].as_ref()),
+ &QueryTerm::Term(ref term) =>
Self::from_term(term),
- QueryTermRef::Throw(term) => {
+ &QueryTerm::Throw(ref term) => {
let state = IteratorState::Clause(0, ClauseType::Throw, term);
QueryIterator { state_stack: vec![state] }
},
- QueryTermRef::Cut => QueryIterator { state_stack: vec![] }
+ &QueryTerm::Cut => QueryIterator { state_stack: vec![] }
}
}
}
-impl<'a> QueryTermRef<'a> {
- pub fn post_order_iter(self) -> QueryIterator<'a> {
+impl QueryTerm {
+ pub fn post_order_iter<'a>(&'a self) -> QueryIterator<'a> {
QueryIterator::new(self)
}
}
impl Term {
pub fn post_order_iter(&self) -> QueryIterator {
- QueryIterator::new(QueryTermRef::Term(self))
+ QueryIterator::from_term(self)
}
pub fn breadth_first_iter(&self) -> FactIterator {
pub struct ChunkedIterator<'a>
{
term_loc: GenContext,
- iter: Box<Iterator<Item=QueryTermRef<'a>> + 'a>,
+ iter: Box<Iterator<Item=&'a QueryTerm> + 'a>,
deep_cut_encountered: bool
}
{
pub fn from_term_sequence(terms: &'a [QueryTerm]) -> Self
{
- let iter = terms.iter().map(|c| c.to_ref());
-
ChunkedIterator {
term_loc: GenContext::Last(0),
- iter: Box::new(iter),
+ iter: Box::new(terms.iter()),
deep_cut_encountered: false
}
}
pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self
{
- let inner_iter = Box::new(once(p1.to_ref()));
- let iter = inner_iter.chain(clauses.iter().map(|c| c.to_ref()));
-
+ let inner_iter = Box::new(once(p1));
+ let iter = inner_iter.chain(clauses.iter());
+
ChunkedIterator {
term_loc: GenContext::Last(0),
iter: Box::new(iter),
{
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
- let iter = once(QueryTermRef::Term(p0));
- let inner_iter = Box::new(once(p1.to_ref()));
- let iter = iter.chain(inner_iter.chain(clauses.iter().map(|c| c.to_ref())));
+ let iter = once(p0);
+ let inner_iter = Box::new(once(p1));
+ let iter = iter.chain(inner_iter.chain(clauses.iter()));
ChunkedIterator {
term_loc: GenContext::Head,
iter: Box::new(iter),
- deep_cut_encountered: false
- }
+ deep_cut_encountered: false,
+ }
}
pub fn encountered_deep_cut(&self) -> bool {
self.term_loc.chunk_num()
}
- fn take_chunk(&mut self, term: QueryTermRef<'a>, mut result: Vec<QueryTermRef<'a>>)
- -> (usize, usize, Vec<QueryTermRef<'a>>)
+ fn take_chunk(&mut self, term: &'a QueryTerm) -> (usize, usize, Vec<&'a QueryTerm>)
{
let mut arity = 0;
let mut item = Some(term);
-
+ let mut result = Vec::new();
+
while let Some(term) = item {
match term {
- //TODO: This can refer to the term at the head of a
- // goal, not technically a QueryTerm (ie. a term in a
- // query). Think of a better name.
- QueryTermRef::Term(inner_term) => {
+ &QueryTerm::Term(ref inner_term) =>
if let GenContext::Head = self.term_loc {
result.push(term);
self.term_loc = GenContext::Last(0);
} else {
result.push(term);
-
+
if inner_term.is_callable() {
arity = inner_term.arity();
break;
}
- }
- },
- QueryTermRef::CallN(child_terms) => {
+ },
+ &QueryTerm::CallN(ref child_terms) => {
result.push(term);
arity = child_terms.len() + 1;
break;
},
- QueryTermRef::Catch(child_terms) | QueryTermRef::Throw(child_terms) => {
+ &QueryTerm::Catch(ref child_terms) | &QueryTerm::Throw(ref child_terms) => {
result.push(term);
arity = child_terms.len();
break;
},
- QueryTermRef::Is(_) => {
+ &QueryTerm::Is(_) => {
result.push(term);
arity = 2;
break;
},
- QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) =>
+ &QueryTerm::IsAtomic(_) | &QueryTerm::IsVar(_) =>
result.push(term),
- QueryTermRef::Cut => {
+ &QueryTerm::Cut => {
result.push(term);
if self.term_loc.chunk_num() > 0 {
impl<'a> Iterator for ChunkedIterator<'a>
{
// the chunk number, last term arity, and vector of references.
- type Item = (usize, usize, Vec<QueryTermRef<'a>>);
+ type Item = (usize, usize, Vec<&'a QueryTerm>);
fn next(&mut self) -> Option<Self::Item> {
- self.iter.next().map(|term| self.take_chunk(term, Vec::new()))
+ self.iter.next().map(|term| self.take_chunk(term))
}
}
pub fn add_fact<'a>(&mut self, fact: &Term, mut code: Code) -> EvalSession<'a>
{
- if let Some(name) = fact.name() {
- let p = self.code.len();
+ match fact {
+ &Term::Clause(_, ref name, _) | &Term::Constant(_, Constant::Atom(ref name)) => {
+ let p = self.code.len();
+ let arity = fact.arity();
- let name = name.clone();
- let arity = fact.arity();
-
- self.code.append(&mut code);
- self.add_user_code(name, arity, p)
- } else {
- EvalSession::NamelessEntry
+ self.code.append(&mut code);
+ self.add_user_code(name.clone(), arity, p)
+ },
+ _ => EvalSession::NamelessEntry
}
}
pub fn add_rule<'a>(&mut self, rule: &Rule, mut code: Code) -> EvalSession<'a>
{
- if let Some(name) = rule.head.0.name() {
- let p = self.code.len();
+ match &rule.head.0 {
+ &QueryTerm::Term(Term::Clause(_, ref name, _))
+ | &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref name))) => {
+ let p = self.code.len();
- let name = name.clone();
- let arity = rule.head.0.arity();
+ let name = name.clone();
+ let arity = rule.head.0.arity();
- self.code.append(&mut code);
- self.add_user_code(name, arity, p)
- } else {
- EvalSession::NamelessEntry
+ self.code.append(&mut code);
+ self.add_user_code(name, arity, p)
+ },
+ _ => EvalSession::NamelessEntry
}
}
pub fn add_predicate<'a>(&mut self, clauses: &Vec<PredicateClause>, mut code: Code)
- -> EvalSession<'a>
+ -> EvalSession<'a>
{
let p = self.code.len();
- let arity = clauses.first().unwrap().arity();
- let name = clauses.first().unwrap().name().clone();
+ if let Some(ref clause) = clauses.first() {
+ if let Some(name) = clause.name() {
+ let arity = clause.arity();
- self.code.append(&mut code);
- self.add_user_code(name, arity, p)
+ self.code.append(&mut code);
+ self.add_user_code(name.clone(), arity, p)
+ } else {
+ EvalSession::NamelessEntry
+ }
+ } else {
+ EvalSession::ImpermissibleEntry(String::from("predicate must have clauses."))
+ }
}
fn cached_query_size(&self) -> usize {
} else {
0
};
-
+
if and_gi <= or_fr.global_index {
self.e = or_fr.e;
- }
+ }
}
if self.e + 1 < self.and_stack.len() {
let index = self.e + 1;
-
+
self.and_stack[index].e = self.e;
self.and_stack[index].cp = self.cp;
-Subproject commit ebecfec050bb67730274fd07be94982cdf33321b
+Subproject commit f01fe4feab95bd50a3aefab448f540be5888a296