eliminate QueryTermRef.

This commit is contained in:
Mark Thom
2017-11-11 18:57:23 -07:00
parent 1f19d5de95
commit e5a235cf80
6 changed files with 170 additions and 198 deletions

View File

@@ -39,26 +39,36 @@ pub enum PredicateClause {
}
impl PredicateClause {
pub fn name(&self) -> &Atom {
match self {
&PredicateClause::Fact(ref t) => t.name().unwrap(),
&PredicateClause::Rule(ref rule) => rule.head.0.name().unwrap()
}
}
pub fn first_arg(&self) -> Option<&Term> {
match self {
&PredicateClause::Fact(ref t) => t.first_arg(),
&PredicateClause::Rule(ref rule) => rule.head.0.first_arg()
&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 arity(&self) -> usize {
match self {
&PredicateClause::Fact(ref t) => t.arity(),
&PredicateClause::Fact(ref term) => term.arity(),
&PredicateClause::Rule(ref rule) => rule.head.0.arity()
}
}
pub fn name(&self) -> Option<&Atom> {
match self {
&PredicateClause::Fact(ref term) => term.name(),
&PredicateClause::Rule(ref rule) =>
if let &QueryTerm::Term(ref term) = &rule.head.0 {
term.name()
} else {
None
}
}
}
}
pub enum Declaration {
@@ -217,6 +227,7 @@ pub enum ParserError
IncompleteReduction,
InconsistentDeclaration,
InconsistentPredicate,
InvalidRuleHead,
ParseBigInt,
ParseFloat(ParseFloatError),
// TokenTooLong,
@@ -310,30 +321,22 @@ pub enum QueryTerm {
}
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>
}
@@ -378,33 +381,6 @@ impl<'a> TermRef<'a> {
}
}
#[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,
@@ -826,14 +802,6 @@ impl Term {
}
}
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(_)) =>

View File

@@ -181,8 +181,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
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 {
@@ -191,10 +191,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
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);
}
}
@@ -209,26 +207,26 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
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)),
_ => {}
}
@@ -276,22 +274,21 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
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))
Terminal::Terminal
};
code.push(if chunk_num == 0 {
Line::Cut(CutInstruction::NeckCut(term))
} else {
Line::Cut(CutInstruction::Cut(term))
});
},
&QueryTermRef::Cut => {
code.push(if chunk_num == 0 {
Line::Cut(CutInstruction::NeckCut(Terminal::Terminal))
} else {
Line::Cut(CutInstruction::Cut(Terminal::Terminal))
});
},
&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())?
@@ -335,8 +332,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
}
}
},
&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!());
},
@@ -361,8 +358,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
}
},
},
&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!());
},
@@ -392,11 +389,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
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);
},
};
@@ -420,11 +417,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
}
}
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!()),
_ => {}
}
@@ -447,28 +444,32 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
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 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 &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)));
}
}
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1).to_ref());
Ok(code)
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 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));
Ok(code)
} else {
Err(ParserError::InvalidRuleHead)
}
}
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact)
@@ -512,7 +513,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
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);
@@ -525,7 +526,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
}
fn compile_query_line(&mut self,
term: QueryTermRef<'a>,
term: &'a QueryTerm,
term_loc: GenContext,
code: &mut Code,
index: usize,
@@ -564,7 +565,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
}
}
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)
}

View File

@@ -171,10 +171,7 @@ impl<'a> VariableFixtures<'a>
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();
@@ -183,8 +180,7 @@ impl<'a> VariableFixtures<'a>
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);

View File

@@ -41,33 +41,35 @@ impl<'a> QueryIterator<'a> {
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)
}
}
@@ -183,7 +185,7 @@ impl<'a> Iterator for FactIterator<'a> {
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 {
@@ -194,7 +196,7 @@ impl Term {
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
}
@@ -202,19 +204,17 @@ impl<'a> ChunkedIterator<'a>
{
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),
@@ -227,14 +227,14 @@ impl<'a> ChunkedIterator<'a>
{
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,
}
}
@@ -250,18 +250,15 @@ impl<'a> ChunkedIterator<'a>
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);
@@ -272,26 +269,25 @@ impl<'a> ChunkedIterator<'a>
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 {
@@ -316,9 +312,9 @@ impl<'a> ChunkedIterator<'a>
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))
}
}

View File

@@ -239,44 +239,52 @@ impl Machine {
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 {