From ded701436a8ce5b0abdea51764fa5e03deef1fe5 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 13 Nov 2017 13:18:05 -0700 Subject: [PATCH] separate handling of inlined query terms. --- src/prolog/ast.rs | 23 +++-- src/prolog/codegen.rs | 209 ++++++++++++++++++++++------------------ src/prolog/iterators.rs | 10 +- src/prolog/parser | 2 +- 4 files changed, 138 insertions(+), 106 deletions(-) diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 2dd8acba..e834a4b7 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -309,13 +309,26 @@ pub enum Term { Var(Cell, Var) } +pub enum InlinedQueryTerm { + Is(Vec>), + IsAtomic(Vec>), + IsVar(Vec>) +} + +impl InlinedQueryTerm { + pub fn arity(&self) -> usize { + match self { + &InlinedQueryTerm::Is(_) => 2, + _ => 1 + } + } +} + pub enum QueryTerm { CallN(Vec>), Catch(Vec>), Cut, - Is(Vec>), - IsAtomic(Vec>), - IsVar(Vec>), + Inlined(InlinedQueryTerm), Term(Term), Throw(Vec>) } @@ -325,9 +338,7 @@ impl QueryTerm { match self { &QueryTerm::Catch(_) => 3, &QueryTerm::Throw(_) => 1, - &QueryTerm::Is(_) => 2, - &QueryTerm::IsAtomic(_) => 1, - &QueryTerm::IsVar(_) => 1, + &QueryTerm::Inlined(ref term) => term.arity(), &QueryTerm::CallN(ref terms) => terms.len(), &QueryTerm::Cut => 0, &QueryTerm::Term(ref term) => term.arity(), diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index bafcea3e..9e332f3d 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -93,16 +93,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p), _ => { let mut target = Vec::new(); - + self.marker.reset_arg(arity); self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target); - + code.push(Line::Query(target)); vr.get().norm() - } + } } } - + fn add_or_increment_void_instr(target: &mut Vec) where Target: CompilationTarget<'a> { @@ -231,27 +231,36 @@ 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: &QueryTerm, pvs: usize) + fn add_conditional_call_inlined(term: &InlinedQueryTerm, code: &mut Code) + { + match term { + &InlinedQueryTerm::IsAtomic(_) | &InlinedQueryTerm::IsVar(_) => + code.push(proceed!()), + _ => {} + }; + } + + fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize) { match qt { &QueryTerm::CallN(ref terms) => { let call = ControlInstruction::CallN(terms.len()); - compiled_query.push(Line::Control(call)); + code.push(Line::Control(call)); }, &QueryTerm::Catch(_) => - compiled_query.push(Line::Control(ControlInstruction::CatchCall)), - &QueryTerm::IsAtomic(_) | &QueryTerm::IsVar(_) => - compiled_query.push(proceed!()), + code.push(Line::Control(ControlInstruction::CatchCall)), + &QueryTerm::Inlined(ref term) => + Self::add_conditional_call_inlined(term, code), &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref atom))) => { let call = ControlInstruction::Call(atom.clone(), 0, pvs); - compiled_query.push(Line::Control(call)); + code.push(Line::Control(call)); }, &QueryTerm::Term(Term::Clause(_, ref atom, ref terms)) => { let call = ControlInstruction::Call(atom.clone(), terms.len(), pvs); - compiled_query.push(Line::Control(call)); + code.push(Line::Control(call)); }, &QueryTerm::Throw(_) => - compiled_query.push(Line::Control(ControlInstruction::ThrowCall)), + code.push(Line::Control(ControlInstruction::ThrowCall)), _ => {} } } @@ -282,6 +291,87 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> dealloc_index } + fn compile_inlined(&mut self, term: &'a InlinedQueryTerm, term_loc: GenContext, code: &mut Code) + -> Result<(), ParserError> + { + match term { + &InlinedQueryTerm::Is(ref terms) => { + let mut arith_code = { + let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings()); + evaluator.eval(terms[1].as_ref())? + }; + + code.append(&mut arith_code); + + match terms[0].as_ref() { + &Term::Var(ref vr, ref name) => { + let r = self.mark_non_callable(name, + 2, + term_loc, + vr, + code); + + code.push(is_call!(r)); + }, + &Term::Constant(_, Constant::Float(fl)) => { + code.push(query![put_constant!(Level::Shallow, + Constant::Float(fl), + temp_v!(1))]); + code.push(is_call!(temp_v!(1))); + }, + &Term::Constant(_, Constant::Integer(ref bi)) => { + let bi = bi.clone(); + code.push(query![put_constant!(Level::Shallow, + Constant::Integer(bi), + temp_v!(1))]); + code.push(is_call!(temp_v!(1))); + }, + _ => { + return Err(ParserError::from(ArithmeticError::InvalidTerm)); + } + } + }, + &InlinedQueryTerm::IsAtomic(ref inner_term) => + match inner_term[0].as_ref() { + &Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => { + code.push(fail!()); + }, + &Term::Constant(_, _) => { + code.push(succeed!()); + }, + &Term::Var(ref vr, ref name) => { + let r = self.mark_non_callable(name, + 1, + term_loc, + vr, + code); + + code.push(is_atomic!(r)); + } + }, + &InlinedQueryTerm::IsVar(ref inner_term) => + match inner_term[0].as_ref() { + &Term::Constant(_, _) | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => { + code.push(fail!()); + }, + &Term::AnonVar => { + code.push(succeed!()); + }, + &Term::Var(ref vr, ref name) => { + let r = self.mark_non_callable(name, + 1, + term_loc, + vr, + code); + + code.push(is_var!(r)); + } + } + } + + Ok(()) + } + fn compile_seq(&mut self, iter: ChunkedIterator<'a>, conjunct_info: &ConjunctInfo<'a>, @@ -300,90 +390,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> match *term { &QueryTerm::Cut => { - let term = if i + 1 < terms.len() { + let is_terminal = if i + 1 < terms.len() { Terminal::Non } else { Terminal::Terminal }; code.push(if chunk_num == 0 { - Line::Cut(CutInstruction::NeckCut(term)) + Line::Cut(CutInstruction::NeckCut(is_terminal)) } else { - Line::Cut(CutInstruction::Cut(term)) + Line::Cut(CutInstruction::Cut(is_terminal)) }); }, - &QueryTerm::Is(ref terms) => { - let mut arith_code = { - let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings()); - evaluator.eval(terms[1].as_ref())? - }; - - code.append(&mut arith_code); - - match terms[0].as_ref() { - &Term::Var(ref vr, ref name) => { - let r = self.mark_non_callable(name, - term.arity(), - term_loc, - vr, - code); - - code.push(is_call!(r)); - }, - &Term::Constant(_, Constant::Float(fl)) => { - code.push(query![put_constant!(Level::Shallow, - Constant::Float(fl), - temp_v!(1))]); - code.push(is_call!(temp_v!(1))); - }, - &Term::Constant(_, Constant::Integer(ref bi)) => { - let bi = bi.clone(); - code.push(query![put_constant!(Level::Shallow, - Constant::Integer(bi), - temp_v!(1))]); - code.push(is_call!(temp_v!(1))); - }, - _ => { - return Err(ParserError::from(ArithmeticError::InvalidTerm)); - } - } - }, - &QueryTerm::IsAtomic(ref inner_term) => - match inner_term[0].as_ref() { - &Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => { - code.push(fail!()); - }, - &Term::Constant(_, _) => { - code.push(succeed!()); - }, - &Term::Var(ref vr, ref name) => { - let r = self.mark_non_callable(name, - term.arity(), - term_loc, - vr, - code); - - code.push(is_atomic!(r)); - } - }, - &QueryTerm::IsVar(ref inner_term) => - match inner_term[0].as_ref() { - &Term::Constant(_, _) | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => { - code.push(fail!()); - }, - &Term::AnonVar => { - code.push(succeed!()); - }, - &Term::Var(ref vr, ref name) => { - let r = self.mark_non_callable(name, - term.arity(), - term_loc, - vr, - code); - - code.push(is_var!(r)); - } - }, + &QueryTerm::Inlined(ref term) => + try!(self.compile_inlined(term, term_loc, code)), _ if chunk_num == 0 => { self.marker.reset_arg(term.arity()); @@ -419,12 +439,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm) { - //TODO: temporary workaround for inlined builtins. match toc { - &QueryTerm::IsAtomic(_) | &QueryTerm::IsVar(_) => - code.push(proceed!()), + &QueryTerm::Inlined(ref term) => + Self::add_conditional_call_inlined(term, code), _ => {} - } + }; let dealloc_index = Self::lco(code); @@ -444,12 +463,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> self.marker.reset_arg(p0.arity()); self.compile_seq_prelude(&conjunct_info, &mut code); - if let &QueryTerm::Term(ref term) = p0 { + 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)); @@ -469,7 +488,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> Ok(code) } else { Err(ParserError::InvalidRuleHead) - } + } } fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) @@ -568,7 +587,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> if let Some(query_term) = query.last() { Self::compile_cleanup(&mut code, &conjunct_info, query_term); } - + Ok(code) } diff --git a/src/prolog/iterators.rs b/src/prolog/iterators.rs index a2a96976..f8545cf9 100644 --- a/src/prolog/iterators.rs +++ b/src/prolog/iterators.rs @@ -40,11 +40,12 @@ impl<'a> QueryIterator<'a> { let state = IteratorState::Clause(0, ClauseType::Catch, terms); QueryIterator { state_stack: vec![state] } }, - &QueryTerm::Is(ref terms) => { + &QueryTerm::Inlined(InlinedQueryTerm::Is(ref terms)) => { let state = IteratorState::Clause(0, ClauseType::Is, terms); QueryIterator { state_stack: vec![state] } }, - &QueryTerm::IsAtomic(ref terms) | &QueryTerm::IsVar(ref terms) => + &QueryTerm::Inlined(InlinedQueryTerm::IsAtomic(ref terms)) + | &QueryTerm::Inlined(InlinedQueryTerm::IsVar(ref terms)) => Self::from_term(terms[0].as_ref()), &QueryTerm::Term(ref term) => Self::from_term(term), @@ -269,12 +270,13 @@ impl<'a> ChunkedIterator<'a> arity = child_terms.len(); break; }, - &QueryTerm::Is(_) => { + &QueryTerm::Inlined(InlinedQueryTerm::Is(_)) => { result.push(term); arity = 2; break; }, - &QueryTerm::IsAtomic(_) | &QueryTerm::IsVar(_) => + &QueryTerm::Inlined(InlinedQueryTerm::IsAtomic(_)) + | &QueryTerm::Inlined(InlinedQueryTerm::IsVar(_)) => result.push(term), &QueryTerm::Cut => { result.push(term); diff --git a/src/prolog/parser b/src/prolog/parser index f01fe4fe..41d2d7d2 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit f01fe4feab95bd50a3aefab448f540be5888a296 +Subproject commit 41d2d7d26fd855bcb4f486411333d3671c648aaa -- 2.54.0