-> Result<(), SessionError>
{
match decl {
- Declaration::Hook(CompileTimeHook::TermExpansion, clause, queue) => {
- let key = (clause_name!("term_expansion"), 2);
+ Declaration::Hook(hook, clause, queue) => {
+ let key = (hook.name(), hook.arity());
let preds = code_repo.term_dir.entry(key)
.or_insert((Predicate(vec![]), VecDeque::from(vec![])));
let mut code = cg.compile_predicate(&(preds.0).0)?;
compile_appendix(&mut code, &preds.1, false, flags)?;
-
- Ok(code_repo.term_expanders = code)
+
+ match hook {
+ CompileTimeHook::TermExpansion =>
+ Ok(code_repo.term_expanders = code),
+ CompileTimeHook::GoalExpansion =>
+ Ok(code_repo.goal_expanders = code)
+ }
},
Declaration::NonCountedBacktracking(name, arity) =>
Ok(self.add_non_counted_bt_flag(name, arity)),
printer
}
+ #[inline]
+ pub fn see_all_locs(&mut self) {
+ for key in self.heap_locs.keys().cloned() {
+ self.printed_vars.insert(key);
+ }
+ }
+
fn enqueue_op(&mut self, ct: ClauseType, fixity: Fixity) {
match fixity {
Fixity::Post => {
#[derive(Clone, Copy)]
pub enum CompileTimeHook {
+ GoalExpansion,
TermExpansion
}
impl CompileTimeHook {
pub fn name(self) -> ClauseName {
- clause_name!("term_expansion")
+ match self {
+ CompileTimeHook::GoalExpansion => clause_name!("goal_expansion"),
+ CompileTimeHook::TermExpansion => clause_name!("term_expansion")
+ }
+ }
+
+ pub fn arity(self) -> usize {
+ match self {
+ CompileTimeHook::GoalExpansion => 2,
+ CompileTimeHook::TermExpansion => 2
+ }
}
}
pub enum LocalCodePtr {
DirEntry(usize), // offset.
TopLevel(usize, usize), // chunk_num, offset.
+ UserGoalExpansion(usize),
UserTermExpansion(usize)
}
match self {
LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs),
LocalCodePtr::TopLevel(cn, p) => LocalCodePtr::TopLevel(cn, p + rhs),
- LocalCodePtr::UserTermExpansion(p) => LocalCodePtr::UserTermExpansion(p + rhs)
+ LocalCodePtr::UserTermExpansion(p) => LocalCodePtr::UserTermExpansion(p + rhs),
+ LocalCodePtr::UserGoalExpansion(p) => LocalCodePtr::UserGoalExpansion(p + rhs),
}
}
}
impl AddAssign<usize> for LocalCodePtr {
fn add_assign(&mut self, rhs: usize) {
match self {
- &mut LocalCodePtr::UserTermExpansion(ref mut p)
+ &mut LocalCodePtr::UserGoalExpansion(ref mut p)
+ | &mut LocalCodePtr::UserTermExpansion(ref mut p)
| &mut LocalCodePtr::DirEntry(ref mut p)
| &mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs
}
}
}
- fn compile_hook(&mut self, machine_st: &mut MachineState, _: &CompileTimeHook) -> CallResult
+ fn compile_hook(&mut self, machine_st: &mut MachineState, hook: &CompileTimeHook) -> CallResult
{
machine_st.cp = LocalCodePtr::TopLevel(0, 0);
- machine_st.num_of_args = 2;
+ machine_st.num_of_args = hook.arity();
machine_st.b0 = machine_st.b;
- machine_st.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0));
+
+ machine_st.p = match hook {
+ CompileTimeHook::TermExpansion =>
+ CodePtr::Local(LocalCodePtr::UserTermExpansion(0)),
+ CompileTimeHook::GoalExpansion =>
+ CodePtr::Local(LocalCodePtr::UserGoalExpansion(0))
+ };
Ok(())
}
pub struct CodeRepo {
cached_query: Option<Code>,
+ pub(super) goal_expanders: Code,
pub(super) term_expanders: Code,
pub(super) code: Code,
pub(super) term_dir: TermDir
fn new() -> Self {
CodeRepo {
cached_query: None,
+ goal_expanders: Code::new(),
term_expanders: Code::new(),
code: Code::new(),
term_dir: TermDir::new()
&Some(ref query) => query.len(),
_ => 0
}
- }
+ }
fn lookup_instr<'a>(&'a self, last_call: bool, p: &CodePtr) -> Option<RefOrOwned<'a, Line>>
{
match p {
+ &CodePtr::Local(LocalCodePtr::UserGoalExpansion(p)) =>
+ if p < self.goal_expanders.len() {
+ Some(RefOrOwned::Borrowed(&self.goal_expanders[p]))
+ } else {
+ None
+ },
&CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) =>
if p < self.term_expanders.len() {
Some(RefOrOwned::Borrowed(&self.term_expanders[p]))
}
},
LocalCodePtr::DirEntry(p) => &self.code[p],
+ LocalCodePtr::UserGoalExpansion(p) => &self.goal_expanders[p],
LocalCodePtr::UserTermExpansion(p) => &self.term_expanders[p]
}
}
CodePtr::Local(LocalCodePtr::DirEntry(p)) if p < code_repo.code.len() => {},
CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) if p < code_repo.term_expanders.len() => {},
CodePtr::Local(LocalCodePtr::UserTermExpansion(_)) => self.fail = true,
+ CodePtr::Local(LocalCodePtr::UserGoalExpansion(p)) if p < code_repo.goal_expanders.len() => {},
+ CodePtr::Local(LocalCodePtr::UserGoalExpansion(_)) => self.fail = true,
CodePtr::Local(_) => break,
_ => {}
};
use prolog::machine::*;
use prolog::read::*;
+use std::cell::Cell;
+use std::collections::VecDeque;
use std::io::Read;
+use std::iter::Rev;
+use std::vec::IntoIter;
+
+fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)>
+{
+ if let &mut Term::Clause(_, ref name, ref mut subterms, _) = term {
+ if name.as_str() == s && subterms.len() == 2 {
+ let snd = *subterms.pop().unwrap();
+ let fst = *subterms.pop().unwrap();
+
+ return Some((fst, snd));
+ }
+ }
+
+ None
+}
+
+pub fn unfold_by_str(mut term: Term, s: &str) -> Vec<Term>
+{
+ let mut terms = vec![];
+
+ while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) {
+ terms.push(fst);
+ term = snd;
+ }
+
+ terms.push(term);
+ terms
+}
+
+pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
+ where I: DoubleEndedIterator<Item=Term>
+{
+ for prec in terms.rev() {
+ term = Term::Clause(Cell::default(), sym.clone(),
+ vec![Box::new(prec), Box::new(term)],
+ None);
+ }
+
+ term
+}
pub struct TermStream<'a, R: Read> {
stack: Vec<Term>,
pub(crate) code_repo: &'a mut CodeRepo,
parser: Parser<R>,
in_module: bool,
- flags: MachineFlags
+ flags: MachineFlags
}
impl<'a, R: Read> TermStream<'a, R> {
Ok(self.stack.is_empty() && self.parser.eof()?)
}
+ fn extract_from_list(&mut self, head: Box<Term>, tail: Box<Term>)
+ -> Result<Rev<IntoIter<Term>>, ParserError>
+ {
+ let mut terms = vec![*head];
+ let mut tail = *tail;
+
+ while let Term::Cons(_, head, next_tail) = tail {
+ terms.push(*head);
+ tail = *next_tail;
+ }
+
+ if let Term::Constant(_, Constant::EmptyList) = tail {
+ Ok(terms.into_iter().rev())
+ } else {
+ Err(ParserError::ExpectedTopLevelTerm)
+ }
+ }
+
fn enqueue_term(&mut self, term: Term) -> Result<(), ParserError> {
match term {
Term::Cons(_, head, tail) => {
- let mut terms = vec![*head];
- let mut tail = *tail;
-
- while let Term::Cons(_, head, next_tail) = tail {
- terms.push(*head);
- tail = *next_tail;
- }
-
- if let Term::Constant(_, Constant::EmptyList) = tail {
- Ok(self.stack.extend(terms.into_iter().rev()))
- } else {
- Err(ParserError::ExpectedTopLevelTerm)
- }
+ let iter = self.extract_from_list(head, tail)?;
+ Ok(self.stack.extend(iter))
},
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) =>
Ok(self.stack.push(term)),
}
}
- fn parse_expansion_output(&mut self, term_string: &str, op_dir: &OpDir) -> Result<Term, ParserError> {
- let mut parser = Parser::new(term_string.trim().as_bytes(), self.indices.atom_tbl.clone(), self.flags);
- parser.read_term(composite_op!(self.in_module,
- &self.indices.op_dir,
- op_dir))
+ fn parse_expansion_output(&mut self, term_string: &str, op_dir: &OpDir)
+ -> Result<Term, ParserError>
+ {
+ let mut parser = Parser::new(term_string.trim().as_bytes(), self.indices.atom_tbl.clone(),
+ self.flags);
+ parser.read_term(composite_op!(self.in_module, &self.indices.op_dir, op_dir))
}
-
+
pub fn read_term(&mut self, machine_st: &mut MachineState, op_dir: &OpDir)
-> Result<Term, ParserError>
{
loop {
while let Some(term) = self.stack.pop() {
- match machine_st.try_expand_term(self.indices, self.policies, self.code_repo, &term)
+ match machine_st.try_expand_term(self.indices, self.policies, self.code_repo,
+ &term, CompileTimeHook::TermExpansion)
{
Some(term_string) => {
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
self.enqueue_term(term)?
},
- None => return Ok(term)
+ None => {
+ let term = self.run_goal_expanders(machine_st, op_dir, term)?;
+ return Ok(term);
+ }
};
}
self.parser.reset();
- let term = self.parser.read_term(composite_op!(self.in_module,
- &self.indices.op_dir,
+ let term = self.parser.read_term(composite_op!(self.in_module, &self.indices.op_dir,
op_dir))?;
self.stack.push(term);
}
}
+
+ fn run_goal_expanders(&mut self, machine_st: &mut MachineState, op_dir: &OpDir, term: Term)
+ -> Result<Term, ParserError>
+ {
+ match term {
+ Term::Clause(cell, name, mut terms, arity) => {
+ let mut new_terms = {
+ let old_terms = if name.as_str() == ":-" && terms.len() == 2 {
+ let comma_term = *terms.pop().unwrap();
+ unfold_by_str(comma_term, ",")
+ } else if name.as_str() == "?-" && terms.len() == 1 {
+ let comma_term = *terms.pop().unwrap();
+ unfold_by_str(comma_term, ",")
+ } else {
+ return Ok(Term::Clause(cell, name, terms, arity));
+ };
+
+ self.expand_goals(machine_st, op_dir, VecDeque::from(old_terms))?
+ };
+
+ let initial_term = new_terms.pop().unwrap();
+
+ terms.push(Box::new(fold_by_str(new_terms.into_iter(), initial_term,
+ clause_name!(","))));
+ Ok(Term::Clause(cell, name, terms, None))
+ },
+ _ =>
+ Ok(term)
+ }
+ }
+
+ fn expand_goals(&mut self, machine_st: &mut MachineState, op_dir: &OpDir,
+ mut terms: VecDeque<Term>)
+ -> Result<Vec<Term>, ParserError>
+ {
+ let mut results = vec![];
+
+ while let Some(term) = terms.pop_front() {
+ match machine_st.try_expand_term(self.indices, self.policies, self.code_repo,
+ &term, CompileTimeHook::GoalExpansion)
+ {
+ Some(term_string) => {
+ let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
+
+ match term {
+ Term::Cons(_, head, tail) =>
+ for term in self.extract_from_list(head, tail)? {
+ terms.push_front(term);
+ },
+ term =>
+ terms.push_front(term)
+ };
+ },
+ None => results.push(term)
+ }
+ }
+
+ Ok(results)
+ }
}
impl MachineState {
fn try_expand_term(&mut self, indices: &mut IndexStore, policies: &mut MachinePolicies,
- code_repo: &mut CodeRepo, term: &Term)
+ code_repo: &mut CodeRepo, term: &Term, hook: CompileTimeHook)
-> Option<String>
{
- let term_h = write_term_to_heap(term, self);
+ let (term_h, var_dict) = write_term_to_heap(term, self);
let h = self.heap.h;
self[temp_v!(1)] = Addr::HeapCell(term_h);
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self[temp_v!(2)] = Addr::HeapCell(h);
- let code = vec![call_clause!(ClauseType::Hook(CompileTimeHook::TermExpansion), 2, 0, true)];
+ let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
code_repo.cached_query = Some(code);
self.run_query(indices, policies, code_repo, &AllocVarDict::new(), &mut HeapVarDict::new());
None
} else {
let mut output = {
- let mut printer = HCPrinter::new(&self, PrinterOutputter::new());
-
+ let output = PrinterOutputter::new();
+ let mut printer = HCPrinter::from_heap_locs(&self, output, &var_dict);
+
printer.quoted = true;
printer.numbervars = true;
-
+
+ printer.see_all_locs();
+
printer.print(Addr::HeapCell(h))
};
let mut parser = Parser::new(inner, atom_tbl, self.flags);
let term = parser.read_term(composite_op!(op_dir))?;
- Ok(write_term_to_heap(&term, self))
+ Ok(write_term_to_heap(&term, self).0)
}
}
}
}
-pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> usize {
+pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> (usize, HeapVarDict) {
let h = machine_st.heap.h;
let mut queue = SubtermDeque::new();
modify_head_of_queue(machine_st, &mut queue, term, h);
}
- h
+ (h, var_dict)
}
}
#[inline]
-fn is_term_expansion(name: &ClauseName, terms: &Vec<Box<Term>>) -> bool {
+fn get_compile_time_hook(name: &str, arity: usize) -> Option<CompileTimeHook> {
+ match (name, arity) {
+ ("term_expansion", 2) => Some(CompileTimeHook::TermExpansion),
+ ("goal_expansion", 2) => Some(CompileTimeHook::GoalExpansion),
+ _ => None
+ }
+}
+
+#[inline]
+fn is_compile_time_hook(name: &ClauseName, terms: &Vec<Box<Term>>) -> Option<CompileTimeHook> {
if name.as_str() == ":-" {
if let Some(ref term) = terms.first() {
if let &Term::Clause(_, ref name, ref terms, None) = term.as_ref() {
- return (name.as_str(), terms.len()) == ("term_expansion", 2);
+ return get_compile_time_hook(name.as_str(), terms.len());
}
}
- } else if name.as_str() == "term_expansion" {
- return terms.len() == 2;
}
-
- false
+
+ get_compile_time_hook(name.as_str(), terms.len())
}
type CompileTimeHookCompileInfo = (CompileTimeHook, PredicateClause, VecDeque<TopLevel>);
Predicate(mem::replace(preds, vec![]))
}
-fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)>
-{
- if let &mut Term::Clause(_, ref name, ref mut subterms, _) = term {
- if name.as_str() == s && subterms.len() == 2 {
- let snd = *subterms.pop().unwrap();
- let fst = *subterms.pop().unwrap();
-
- return Some((fst, snd));
- }
- }
-
- None
-}
-
-fn unfold_by_str(mut term: Term, s: &str) -> Vec<Term>
-{
- let mut terms = vec![];
-
- while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) {
- terms.push(fst);
- term = snd;
- }
-
- terms.push(term);
- terms
-}
-
-fn fold_by_str(mut terms: Vec<Term>, mut term: Term, sym: ClauseName) -> Term
-{
- while let Some(prec) = terms.pop() {
- term = Term::Clause(Cell::default(), sym.clone(),
- vec![Box::new(prec), Box::new(term)],
- None);
- }
-
- term
-}
-
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
for term in terms.iter_mut() {
match term {
cut_var_found = mark_cut_variables(&mut subterms);
let term = subterms.pop().unwrap();
- fold_by_str(subterms, term, clause_name!(","))
+ fold_by_str(subterms.into_iter(), term, clause_name!(","))
}).collect();
if cut_var_found {
let body_term = Term::Clause(Cell::default(), comma_sym.clone(),
vec![front_term, back_term], None);
- self.fabricate_rule(fold_by_str(prec_seq, body_term, comma_sym))
+ self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
}
fn to_query_term(&mut self, indices: &mut CompositeIndices, term: Term) -> Result<QueryTerm, ParserError>
Ok(query_terms)
}
- fn setup_hook(&mut self, indices: &mut CompositeIndices, term: Term)
+ fn setup_hook(&mut self, hook: CompileTimeHook, indices: &mut CompositeIndices, term: Term)
-> Result<CompileTimeHookCompileInfo, ParserError>
{
match term {
Term::Clause(r, name, terms, _) =>
- if name.as_str() == "term_expansion" && terms.len() == 2 {
+ if name == hook.name() && terms.len() == hook.arity() {
let term = setup_fact(Term::Clause(r, name, terms, None))?;
-
- Ok((CompileTimeHook::TermExpansion, PredicateClause::Fact(term),
- VecDeque::from(vec![])))
+ Ok((hook, PredicateClause::Fact(term), VecDeque::from(vec![])))
} else if name.as_str() == ":-" {
let rule = self.setup_rule(indices, terms, true)?;
let results_queue = self.parse_queue(indices)?;
-
- Ok((CompileTimeHook::TermExpansion, PredicateClause::Rule(rule),
- results_queue))
+
+ Ok((hook, PredicateClause::Rule(rule), results_queue))
} else {
Err(ParserError::InvalidHook)
},
{
match term {
Term::Clause(r, name, mut terms, fixity) =>
- if is_term_expansion(&name, &terms) {
+ if let Some(hook) = is_compile_time_hook(&name, &terms) {
let term = Term::Clause(r, name, terms, fixity);
- let (hook, clause, queue) = self.setup_hook(indices, term)?;
+ let (hook, clause, queue) = self.setup_hook(hook, indices, term)?;
Ok(TopLevel::Declaration(Declaration::Hook(hook, clause, queue)))
} else if name.as_str() == "?-" {
}
impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
- pub fn new(inner: R,
- atom_tbl: TabledData<Atom>,
- flags: MachineFlags,
- indices: &'a mut IndexStore,
- policies: &'a mut MachinePolicies,
- code_repo: &'a mut CodeRepo)
+ pub fn new(inner: R, atom_tbl: TabledData<Atom>,
+ flags: MachineFlags, indices: &'a mut IndexStore,
+ policies: &'a mut MachinePolicies, code_repo: &'a mut CodeRepo)
-> Self
{
let term_stream = TermStream::new(inner, atom_tbl, flags,