use prolog::debray_allocator::*;
use prolog::codegen::*;
use prolog::machine::*;
+use prolog::machine::term_expansion::{ExpansionAdditionResult, TermStream};
use prolog::toplevel::*;
use std::collections::{HashMap, HashSet, VecDeque};
Ok(())
}
+impl CodeRepo {
+ pub fn compile_hook(&mut self, hook: CompileTimeHook, flags: MachineFlags)
+ -> Result<(), ParserError>
+ {
+ let key = (hook.name(), hook.arity());
+ match self.term_dir.get(&key) {
+ Some(preds) => {
+ let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
+ let mut code = cg.compile_predicate(&(preds.0).0)?;
+
+ compile_appendix(&mut code, &preds.1, false, flags)?;
+
+ Ok(match hook {
+ CompileTimeHook::TermExpansion =>
+ self.term_expanders = code,
+ CompileTimeHook::GoalExpansion =>
+ self.goal_expanders = code
+ })
+ },
+ None => Ok(())
+ }
+ }
+}
+
fn compile_query(terms: Vec<QueryTerm>, queue: VecDeque<TopLevel>, flags: MachineFlags)
-> Result<(Code, AllocVarDict), ParserError>
{
struct GatherResult {
worker_results: Vec<(Predicate, VecDeque<TopLevel>)>,
toplevel_results: Vec<(Predicate, VecDeque<TopLevel>)>,
- toplevel_indices: IndexStore
+ toplevel_indices: IndexStore,
+ addition_results: ExpansionAdditionResult
}
pub struct ListingCompiler {
}
}
- fn use_module(&mut self, submodule: ClauseName, wam_indices: &mut IndexStore, indices: &mut IndexStore)
+ fn use_module(&mut self, submodule: ClauseName, code_repo: &mut CodeRepo,
+ flags: MachineFlags, wam_indices: &mut IndexStore,
+ indices: &mut IndexStore)
-> Result<(), SessionError>
{
let mod_name = self.get_module_name();
if let Some(submodule) = wam_indices.take_module(submodule) {
- indices.use_module(&submodule)?;
+ indices.use_module(code_repo, flags, &submodule)?;
if let &mut Some(ref mut module) = &mut self.module {
module.remove_module(mod_name, &submodule);
- module.use_module(&submodule)?;
+ module.use_module(code_repo, flags, &submodule)?;
} else {
wam_indices.remove_module(clause_name!("user"), &submodule);
}
}
}
- fn use_qualified_module(&mut self, submodule: ClauseName, exports: &Vec<PredicateKey>,
+ fn use_qualified_module(&mut self, submodule: ClauseName, code_repo: &mut CodeRepo,
+ flags: MachineFlags, exports: &Vec<PredicateKey>,
wam_indices: &mut IndexStore, indices: &mut IndexStore)
-> Result<(), SessionError>
{
let mod_name = self.get_module_name();
if let Some(submodule) = wam_indices.take_module(submodule) {
- indices.use_qualified_module(&submodule, exports)?;
+ indices.use_qualified_module(code_repo, flags, &submodule, exports)?;
if let &mut Some(ref mut module) = &mut self.module {
module.remove_module(mod_name, &submodule);
- module.use_qualified_module(&submodule, exports)?;
+ module.use_qualified_module(code_repo, flags, &submodule, exports)?;
} else {
wam_indices.remove_module(clause_name!("user"), &submodule);
}
match decl {
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![])));
- (preds.0).0.push(clause);
- preds.1.extend(queue.into_iter());
-
- let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
- let mut code = cg.compile_predicate(&(preds.0).0)?;
-
- compile_appendix(&mut code, &preds.1, false, flags)?;
-
- match hook {
- CompileTimeHook::TermExpansion =>
- Ok(code_repo.term_expanders = code),
- CompileTimeHook::GoalExpansion =>
- Ok(code_repo.goal_expanders = code)
+ {
+ let preds = code_repo.term_dir.entry(key)
+ .or_insert((Predicate(vec![]), VecDeque::from(vec![])));
+
+ (preds.0).0.push(clause);
+ preds.1.extend(queue.into_iter());
}
+
+ code_repo.compile_hook(hook, flags)
+ .map_err(SessionError::from)
},
Declaration::NonCountedBacktracking(name, arity) =>
Ok(self.add_non_counted_bt_flag(name, arity)),
Declaration::Op(op_decl) =>
op_decl.submit(self.get_module_name(), &mut indices.op_dir),
Declaration::UseModule(name) =>
- self.use_module(name, wam_indices, indices),
+ self.use_module(name, code_repo, flags, wam_indices, indices),
Declaration::UseQualifiedModule(name, exports) =>
- self.use_qualified_module(name, &exports, wam_indices, indices),
+ self.use_qualified_module(name, code_repo, flags, &exports, wam_indices, indices),
Declaration::Module(module_decl) =>
if self.module.is_none() {
let module_name = module_decl.name.clone();
}
}
+ fn process_and_commit_decl<'a, R: Read>(&mut self, decl: Declaration,
+ term_stream: &mut TermStream<'a, R>,
+ indices: &mut IndexStore, flags: MachineFlags)
+ -> Result<(), SessionError>
+ {
+ match &decl {
+ &Declaration::Hook(hook, _, ref queue) if self.module.is_none() =>
+ term_stream.incr_expansion_lens(hook, 1, queue.len()),
+ _ => {}
+ };
+
+ self.process_decl(decl, term_stream.code_repo, term_stream.indices, indices, flags)
+ }
+
fn gather_items<R: Read>(&mut self, wam: &mut Machine, src: R, indices: &mut IndexStore)
-> Result<GatherResult, SessionError>
{
mem::swap(&mut worker.results, &mut toplevel_results);
worker.in_module = true;
- self.process_decl(decl, worker.term_stream.code_repo,
- worker.term_stream.indices,
- indices, flags)?;
+ self.process_and_commit_decl(decl, &mut worker.term_stream,
+ indices, flags)?;
if let &Some(ref module) = &self.module {
worker.term_stream.set_atom_tbl(module.atom_tbl.clone());
}
} else {
- self.process_decl(decl, worker.term_stream.code_repo,
- worker.term_stream.indices,
- indices, flags)?;
+ self.process_and_commit_decl(decl, &mut worker.term_stream,
+ indices, flags)?;
}
}
+ let addition_results = worker.term_stream.rollback_expansion_code()?;
+
Ok(GatherResult {
worker_results: worker.results,
toplevel_results,
- toplevel_indices
+ toplevel_indices,
+ addition_results
})
}
}
let toplvl_code = try_eval_session!(compiler.generate_code(results.toplevel_results, wam,
&mut results.toplevel_indices.code_dir));
+ if let Some(ref mut module) = &mut compiler.module {
+ module.term_expansions = results.addition_results.take_term_expansions();
+ module.goal_expansions = results.addition_results.take_goal_expansions();
+ }
+
try_eval_session!(compiler.add_code(wam, module_code, indices));
try_eval_session!(compiler.add_code(wam, toplvl_code, results.toplevel_indices));
EvalSession::EntrySuccess
}
-fn setup_indices(wam: &Machine, indices: &mut IndexStore) -> Result<(), SessionError> {
- if let Some(ref builtins) = wam.indices.modules.get(&clause_name!("builtins")) {
- indices.use_module(builtins)
+fn setup_indices(wam: &mut Machine, indices: &mut IndexStore) -> Result<(), SessionError> {
+ if let Some(builtins) = wam.indices.take_module(clause_name!("builtins")) {
+ let flags = wam.machine_flags();
+ let result = indices.use_module(&mut wam.code_repo, flags, &builtins);
+
+ wam.indices.insert_module(builtins);
+ result
} else {
Err(SessionError::ModuleNotFound)
}
pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession {
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
- try_eval_session!(setup_indices(&wam, &mut indices));
+ try_eval_session!(setup_indices(wam, &mut indices));
compile_listing(wam, src, indices)
}
// of vars (we get their adjoining cells this way).
pub type JumpStub = Vec<Term>;
+#[derive(Clone)]
pub enum QueryTerm {
// register, clause type, subterms, use default call policy.
Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>, bool),
}
}
+#[derive(Clone)]
pub struct Rule {
pub head: (ClauseName, Vec<Box<Term>>, QueryTerm),
pub clauses: Vec<QueryTerm>
}
+#[derive(Clone)]
pub struct Predicate(pub Vec<PredicateClause>);
impl Predicate {
+ pub fn new() -> Self {
+ Predicate(vec![])
+ }
+
pub fn clauses(self) -> Vec<PredicateClause> {
self.0
}
}
+#[derive(Clone)]
pub enum PredicateClause {
Fact(Term),
Rule(Rule)
pub type PredicateKey = (ClauseName, usize); // name, arity.
+pub struct CodeRepo {
+ pub(super) cached_query: Code,
+ pub(super) goal_expanders: Code,
+ pub(super) term_expanders: Code,
+ pub(super) code: Code,
+ pub(super) in_situ_code: Code,
+ pub(super) term_dir: TermDir
+}
+
+#[derive(Clone)]
pub struct ModuleDecl {
pub name: ClauseName,
pub exports: Vec<PredicateKey>
pub atom_tbl: TabledData<Atom>,
pub module_decl: ModuleDecl,
pub code_dir: ModuleCodeDir,
- pub op_dir: OpDir
+ pub op_dir: OpDir,
+ pub term_expansions: (Predicate, VecDeque<TopLevel>),
+ pub goal_expansions: (Predicate, VecDeque<TopLevel>),
}
#[derive(Copy, Clone, PartialEq)]
impl Module {
pub fn new(module_decl: ModuleDecl, atom_tbl: TabledData<Atom>) -> Self {
Module { module_decl, atom_tbl,
+ term_expansions: (Predicate::new(), VecDeque::from(vec![])),
+ goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
code_dir: ModuleCodeDir::new(),
op_dir: default_op_dir() }
}
+
+ pub fn dump_expansions(&self, code_repo: &mut CodeRepo, flags: MachineFlags)
+ -> Result<(), ParserError>
+ {
+ {
+ let te = code_repo.term_dir.entry((clause_name!("term_expansion"), 2))
+ .or_insert((Predicate::new(), VecDeque::from(vec![])));
+
+ (te.0).0.extend((self.term_expansions.0).0.iter().cloned());
+ te.1.extend(self.term_expansions.1.iter().cloned());
+ }
+
+ {
+ let ge = code_repo.term_dir.entry((clause_name!("goal_expansion"), 2))
+ .or_insert((Predicate::new(), VecDeque::from(vec![])));
+
+ (ge.0).0.extend((self.goal_expansions.0).0.iter().cloned());
+ ge.1.extend(self.goal_expansions.1.iter().cloned());
+ }
+
+ code_repo.compile_hook(CompileTimeHook::TermExpansion, flags)?;
+ code_repo.compile_hook(CompileTimeHook::GoalExpansion, flags)?;
+
+ Ok(())
+ }
}
pub fn as_module_code_dir(code_dir: CodeDir) -> ModuleCodeDir {
}
}
- fn use_qualified_module(&mut self, submodule: &Module, exports: &Vec<PredicateKey>)
- -> Result<(), SessionError>
- {
- for (name, arity) in exports.iter().cloned() {
- if !submodule.module_decl.exports.contains(&(name.clone(), arity)) {
- continue;
- }
+ fn use_qualified_module(&mut self, &mut CodeRepo, MachineFlags, &Module, &Vec<PredicateKey>)
+ -> Result<(), SessionError>;
+ fn use_module(&mut self, &mut CodeRepo, MachineFlags, &Module)
+ -> Result<(), SessionError>;
+}
- if !self.import_decl(name, arity, submodule) {
- return Err(SessionError::ModuleDoesNotContainExport);
- }
+pub fn use_qualified_module<User>(user: &mut User, submodule: &Module, exports: &Vec<PredicateKey>)
+ -> Result<(), SessionError>
+ where User: SubModuleUser
+{
+ for (name, arity) in exports.iter().cloned() {
+ if !submodule.module_decl.exports.contains(&(name.clone(), arity)) {
+ continue;
}
- Ok(())
+ if !user.import_decl(name, arity, submodule) {
+ return Err(SessionError::ModuleDoesNotContainExport);
+ }
}
- fn use_module(&mut self, submodule: &Module) -> Result<(), SessionError> {
- for (name, arity) in submodule.module_decl.exports.iter().cloned() {
- if !self.import_decl(name, arity, submodule) {
- return Err(SessionError::ModuleDoesNotContainExport);
- }
- }
+ Ok(())
+}
- Ok(())
+pub fn use_module<User: SubModuleUser>(user: &mut User, submodule: &Module)
+ -> Result<(), SessionError>
+{
+ for (name, arity) in submodule.module_decl.exports.iter().cloned() {
+ if !user.import_decl(name, arity, submodule) {
+ return Err(SessionError::ModuleDoesNotContainExport);
+ }
}
+
+ Ok(())
}
impl SubModuleUser for Module {
self.code_dir.remove(&key);
}
- fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex)
- {
+ fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
self.code_dir.insert((name, arity), idx);
}
+
+ fn use_qualified_module(&mut self, _: &mut CodeRepo, _: MachineFlags, submodule: &Module,
+ exports: &Vec<PredicateKey>)
+ -> Result<(), SessionError>
+ {
+ use_qualified_module(self, submodule, exports)?;
+
+ (self.term_expansions.0).0.extend((submodule.term_expansions.0).0.iter().cloned());
+ self.term_expansions.1.extend(submodule.term_expansions.1.iter().cloned());
+
+ (self.goal_expansions.0).0.extend((submodule.goal_expansions.0).0.iter().cloned());
+ self.goal_expansions.1.extend(submodule.goal_expansions.1.iter().cloned());
+
+ Ok(())
+ }
+
+ fn use_module(&mut self, _: &mut CodeRepo, _: MachineFlags, submodule: &Module)
+ -> Result<(), SessionError>
+ {
+ use_module(self, submodule)?;
+
+ (self.term_expansions.0).0.extend((submodule.term_expansions.0).0.iter().cloned());
+ self.term_expansions.1.extend(submodule.term_expansions.1.iter().cloned());
+
+ (self.goal_expansions.0).0.extend((submodule.goal_expansions.0).0.iter().cloned());
+ self.goal_expansions.1.extend(submodule.goal_expansions.1.iter().cloned());
+
+ Ok(())
+ }
}
+#[derive(Clone)]
pub enum Declaration {
Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>),
Module(ModuleDecl),
}
}
+#[derive(Clone)]
pub enum TopLevel {
Declaration(Declaration),
Fact(Term),
}
}
+#[derive(Clone)]
pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
impl OpDecl {
pub(super) code_dir: CodeDir,
pub(super) in_situ_code_dir: InSituCodeDir,
pub(super) op_dir: OpDir,
- pub(super) modules: ModuleDir
+ pub(super) modules: ModuleDir,
}
enum RefOrOwned<'a, T: 'a> {
pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
-pub struct CodeRepo {
- cached_query: Code,
- pub(super) goal_expanders: Code,
- pub(super) term_expanders: Code,
- pub(super) code: Code,
- pub(super) in_situ_code: Code,
- pub(super) term_dir: TermDir
-}
-
-impl CodeRepo {
+impl CodeRepo {
#[inline]
fn new() -> Self {
CodeRepo {
}
}
+ #[inline]
+ pub fn term_dir_entry_len(&self, key: PredicateKey) -> (usize, usize) {
+ self.term_dir.get(&key)
+ .map(|entry| ((entry.0).0.len(), entry.1.len()))
+ .unwrap_or((0,0))
+ }
+
+ #[inline]
+ pub fn truncate_terms(&mut self, key: PredicateKey, len: usize, queue_len: usize)
+ -> (Predicate, VecDeque<TopLevel>)
+ {
+ //TODO: fix this! this is causing a test to fail. because term_expansions, when
+ //removed by rollback_expansion_code, aren't jump-labeled properly by generate_code.
+ self.term_dir.get_mut(&key)
+ .map(|entry| (Predicate((entry.0).0.clone()[len ..].to_vec()), //drain(len ..).collect()),
+ entry.1.drain(queue_len ..).collect()))
+ .unwrap_or((Predicate(vec![]), VecDeque::from(vec![])))
+ }
+
pub fn add_in_situ_result(&mut self, result: &CompiledResult, in_situ_code_dir: &mut InSituCodeDir,
flags: MachineFlags)
-> Result<(), SessionError>
self.code_dir.insert((name, arity), CodeIndex::from(idx));
}
+
+ fn use_qualified_module(&mut self, code_repo: &mut CodeRepo, flags: MachineFlags,
+ submodule: &Module, exports: &Vec<PredicateKey>)
+ -> Result<(), SessionError>
+ {
+ use_qualified_module(self, submodule, exports)?;
+ submodule.dump_expansions(code_repo, flags).map_err(SessionError::from)
+ }
+
+ fn use_module(&mut self, code_repo: &mut CodeRepo, flags: MachineFlags, submodule: &Module)
+ -> Result<(), SessionError>
+ {
+ use_module(self, submodule)?;
+ submodule.dump_expansions(code_repo, flags).map_err(SessionError::from)
+ }
}
static LISTS: &str = include_str!("../lib/lists.pl");
term
}
+fn extract_from_list(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)
+ }
+}
+
pub struct TermStream<'a, R: Read> {
stack: Vec<Term>,
pub(crate) indices: &'a mut IndexStore,
pub(crate) code_repo: &'a mut CodeRepo,
parser: Parser<R>,
in_module: bool,
- pub(crate) flags: MachineFlags
+ pub(crate) flags: MachineFlags,
+ term_expansion_lens: (usize, usize),
+ goal_expansion_lens: (usize, usize),
+}
+
+pub struct ExpansionAdditionResult {
+ term_expansion_additions: (Predicate, VecDeque<TopLevel>),
+ goal_expansion_additions: (Predicate, VecDeque<TopLevel>)
+}
+
+impl ExpansionAdditionResult {
+ pub fn take_term_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
+ let tes = mem::replace(&mut self.term_expansion_additions.0, Predicate::new());
+ let teqs = mem::replace(&mut self.term_expansion_additions.1, VecDeque::from(vec![]));
+
+ (tes, teqs)
+ }
+
+ pub fn take_goal_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
+ let ges = mem::replace(&mut self.goal_expansion_additions.0, Predicate::new());
+ let geqs = mem::replace(&mut self.goal_expansion_additions.1, VecDeque::from(vec![]));
+
+ (ges, geqs)
+ }
}
impl<'a, R: Read> Drop for TermStream<'a, R> {
fn drop(&mut self) {
self.indices.in_situ_code_dir.clear();
- self.code_repo.in_situ_code.clear();
+ self.code_repo.in_situ_code.clear();
+ discard_result!(self.rollback_expansion_code());
}
}
{
TermStream {
stack: Vec::new(),
+ term_expansion_lens: code_repo.term_dir_entry_len((clause_name!("term_expansion"), 2)),
+ goal_expansion_lens: code_repo.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
+ code_repo,
indices,
policies,
- code_repo,
parser: Parser::new(src, atom_tbl, flags),
in_module: false,
flags
}
}
+ #[inline]
+ pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
+ match hook {
+ CompileTimeHook::TermExpansion => {
+ self.term_expansion_lens.0 += len;
+ self.term_expansion_lens.1 += queue_len;
+ },
+ CompileTimeHook::GoalExpansion => {
+ self.goal_expansion_lens.0 += len;
+ self.goal_expansion_lens.1 += queue_len;
+ }
+ }
+ }
+
#[inline]
pub fn set_atom_tbl(&mut self, atom_tbl: TabledData<Atom>) {
self.parser.set_atom_tbl(atom_tbl);
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;
+ pub fn rollback_expansion_code(&mut self) -> Result<ExpansionAdditionResult, ParserError> {
+ let te_len = self.term_expansion_lens.0;
+ let te_queue_len = self.term_expansion_lens.1;
- while let Term::Cons(_, head, next_tail) = tail {
- terms.push(*head);
- tail = *next_tail;
- }
+ let ge_len = self.goal_expansion_lens.0;
+ let ge_queue_len = self.goal_expansion_lens.1;
- if let Term::Constant(_, Constant::EmptyList) = tail {
- Ok(terms.into_iter().rev())
- } else {
- Err(ParserError::ExpectedTopLevelTerm)
- }
+ let term_expansion_additions =
+ self.code_repo.truncate_terms((clause_name!("term_expansion"), 2),
+ te_len, te_queue_len);
+ let goal_expansion_additions =
+ self.code_repo.truncate_terms((clause_name!("goal_expansion"), 2),
+ ge_len, ge_queue_len);
+
+ self.code_repo.compile_hook(CompileTimeHook::TermExpansion, self.flags)?;
+ self.code_repo.compile_hook(CompileTimeHook::GoalExpansion, self.flags)?;
+
+ Ok(ExpansionAdditionResult {
+ term_expansion_additions,
+ goal_expansion_additions
+ })
}
fn enqueue_term(&mut self, term: Term) -> Result<(), ParserError> {
match term {
Term::Cons(_, head, tail) => {
- let iter = self.extract_from_list(head, tail)?;
+ let iter = extract_from_list(head, tail)?;
Ok(self.stack.extend(iter))
},
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) =>
match term {
Term::Cons(_, head, tail) =>
- for term in self.extract_from_list(head, tail)? {
+ for term in extract_from_list(head, tail)? {
terms.push_front(term);
},
term =>
Line::Cut(CutInstruction::GetLevelAndUnify($r))
)
}
+
+macro_rules! discard_result {
+ ($f: expr) => (
+ match $f {
+ _ => ()
+ }
+ )
+}
}
#[inline]
-fn get_compile_time_hook(name: &str, arity: usize) -> Option<CompileTimeHook> {
+fn as_compile_time_hook(name: &str, arity: usize) -> Option<CompileTimeHook> {
match (name, arity) {
("term_expansion", 2) => Some(CompileTimeHook::TermExpansion),
("goal_expansion", 2) => Some(CompileTimeHook::GoalExpansion),
if name.as_str() == ":-" {
if let Some(ref term) = terms.first() {
if let &Term::Clause(_, ref name, ref terms, None) = term.as_ref() {
- return get_compile_time_hook(name.as_str(), terms.len());
+ return as_compile_time_hook(name.as_str(), terms.len());
}
}
}
- get_compile_time_hook(name.as_str(), terms.len())
+ as_compile_time_hook(name.as_str(), terms.len())
}
type CompileTimeHookCompileInfo = (CompileTimeHook, PredicateClause, VecDeque<TopLevel>);