start enabling the dynamic database
This commit is contained in:
@@ -5,9 +5,10 @@ use prolog::instructions::*;
|
||||
use prolog::debray_allocator::*;
|
||||
use prolog::codegen::*;
|
||||
use prolog::machine::*;
|
||||
use prolog::machine::term_expansion::{ExpansionAdditionResult, TermStream};
|
||||
use prolog::machine::term_expansion::{ExpansionAdditionResult};
|
||||
use prolog::toplevel::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
@@ -36,7 +37,7 @@ fn print_code(code: &Code) {
|
||||
}
|
||||
}
|
||||
|
||||
type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>);
|
||||
pub type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>);
|
||||
|
||||
// throw errors if declaration or query found.
|
||||
fn compile_relation(tl: &TopLevel, non_counted_bt: bool, flags: MachineFlags)
|
||||
@@ -153,8 +154,9 @@ pub fn compile_term(wam: &mut Machine, packet: TopLevelPacket) -> EvalSession
|
||||
}
|
||||
}
|
||||
|
||||
struct GatherResult {
|
||||
worker_results: Vec<PredicateCompileQueue>,
|
||||
pub struct GatherResult {
|
||||
dynamic_clause_map: DynamicClauseMap,
|
||||
pub(crate) worker_results: Vec<PredicateCompileQueue>,
|
||||
toplevel_results: Vec<PredicateCompileQueue>,
|
||||
toplevel_indices: IndexStore,
|
||||
addition_results: ExpansionAdditionResult
|
||||
@@ -180,6 +182,32 @@ impl ListingCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Replace calls to self with a localized index cell, not available to the global CodeIndex.
|
||||
This is done to implement logical update semantics for dynamic database updates.
|
||||
*/
|
||||
fn localize_self_calls(&mut self, name: ClauseName, arity: usize, code: &mut Code, p: usize)
|
||||
{
|
||||
let self_idx = CodeIndex::default();
|
||||
set_code_index!(self_idx, IndexPtr::Index(p), self.get_module_name());
|
||||
|
||||
for instr in code.iter_mut() {
|
||||
if let &mut Line::Control(ControlInstruction::CallClause(ref mut ct, ..)) = instr {
|
||||
match ct {
|
||||
&mut ClauseType::Named(ref ct_name, ct_arity, ref mut idx)
|
||||
if ct_name == &name && arity == ct_arity => {
|
||||
*idx = self_idx.clone();
|
||||
},
|
||||
&mut ClauseType::Op(ref op_decl, ref mut idx)
|
||||
if op_decl.name() == name && op_decl.arity() == arity => {
|
||||
*idx = self_idx.clone();
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn use_module(&mut self, submodule: ClauseName, code_repo: &mut CodeRepo,
|
||||
flags: MachineFlags, wam_indices: &mut IndexStore,
|
||||
indices: &mut IndexStore)
|
||||
@@ -235,6 +263,49 @@ impl ListingCompiler {
|
||||
.unwrap_or(ClauseName::BuiltIn("user"))
|
||||
}
|
||||
|
||||
fn add_clause_code(&mut self, dynamic_clause_map: DynamicClauseMap, wam: &mut Machine)
|
||||
-> Result<(), SessionError>
|
||||
{
|
||||
let mut code = vec![];
|
||||
let mut pi_to_loc = HashMap::new();
|
||||
|
||||
// the name of this function is misleading. first we generate the clause code..
|
||||
for ((name, arity), heads_and_tails) in dynamic_clause_map {
|
||||
if heads_and_tails.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let predicate = Predicate(heads_and_tails.into_iter().map(|(head, tail)| {
|
||||
let clause = Term::Clause(Cell::default(), clause_name!("clause"),
|
||||
vec![Box::new(head), Box::new(tail)],
|
||||
None);
|
||||
PredicateClause::Fact(clause)
|
||||
}).collect());
|
||||
|
||||
let p = code.len() + wam.code_size();
|
||||
let mut decl_code = compile_relation(&TopLevel::Predicate(predicate), false,
|
||||
wam.machine_flags())?;
|
||||
|
||||
compile_appendix(&mut decl_code, &VecDeque::new(), false, wam.machine_flags())?;
|
||||
|
||||
pi_to_loc.insert((name, arity), p);
|
||||
code.extend(decl_code.into_iter());
|
||||
}
|
||||
|
||||
// now that we've reached this point without error, we are free to add to the WAM.
|
||||
wam.code_repo.code.extend(code.into_iter());
|
||||
|
||||
// ... then we add it to the wam.
|
||||
for ((name, arity), p) in pi_to_loc {
|
||||
let entry = wam.indices.dynamic_code_dir.entry((name, arity))
|
||||
.or_insert(DynamicPredicateInfo::default());
|
||||
entry.clauses_subsection_p = p;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn generate_code(&mut self, decls: Vec<PredicateCompileQueue>, wam: &Machine,
|
||||
code_dir: &mut CodeDir)
|
||||
-> Result<Code, SessionError>
|
||||
@@ -242,11 +313,7 @@ impl ListingCompiler {
|
||||
let mut code = vec![];
|
||||
|
||||
for (decl, queue) in decls {
|
||||
let (name, arity) = decl.0.first().and_then(|cl| {
|
||||
let arity = cl.arity();
|
||||
cl.name().map(|name| (name, arity))
|
||||
}).ok_or(SessionError::NamelessEntry)?;
|
||||
|
||||
let (name, arity) = decl.predicate_indicator().ok_or(SessionError::NamelessEntry)?;
|
||||
let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity));
|
||||
|
||||
let p = code.len() + wam.code_size();
|
||||
@@ -257,7 +324,8 @@ impl ListingCompiler {
|
||||
|
||||
let idx = code_dir.entry((name.clone(), arity)).or_insert(CodeIndex::default());
|
||||
set_code_index!(idx, IndexPtr::Index(p), self.get_module_name());
|
||||
|
||||
|
||||
self.localize_self_calls(name, arity, &mut decl_code, p);
|
||||
code.extend(decl_code.into_iter());
|
||||
}
|
||||
|
||||
@@ -354,26 +422,32 @@ impl ListingCompiler {
|
||||
Ok(self.module = Some(Module::new(module_decl, atom_tbl)))
|
||||
} else {
|
||||
Err(SessionError::from(ParserError::InvalidModuleDecl))
|
||||
}
|
||||
},
|
||||
Declaration::Dynamic(..) => Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn process_and_commit_decl<'a, R: Read>(&mut self, decl: Declaration,
|
||||
term_stream: &mut TermStream<'a, R>,
|
||||
worker: &mut TopLevelBatchWorker<'a, R>,
|
||||
indices: &mut IndexStore, flags: MachineFlags)
|
||||
-> Result<(), SessionError>
|
||||
{
|
||||
match &decl {
|
||||
&Declaration::Dynamic(ref name, arity) => {
|
||||
worker.dynamic_clause_map.entry((name.clone(), arity)).or_insert(vec![]);
|
||||
},
|
||||
&Declaration::Hook(hook, _, ref queue) if self.module.is_none() =>
|
||||
term_stream.incr_expansion_lens(hook.user_scope(), 1, queue.len()),
|
||||
worker.term_stream.incr_expansion_lens(hook.user_scope(), 1, queue.len()),
|
||||
&Declaration::Hook(hook, _, ref queue) if !hook.has_module_scope() =>
|
||||
term_stream.incr_expansion_lens(hook, 1, queue.len()),
|
||||
worker.term_stream.incr_expansion_lens(hook, 1, queue.len()),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
self.process_decl(decl, term_stream.code_repo, term_stream.indices, indices, flags)
|
||||
self.process_decl(decl, &mut worker.term_stream.code_repo,
|
||||
&mut worker.term_stream.indices, indices, flags)
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn gather_items<R: Read>(&mut self, wam: &mut Machine, src: R, indices: &mut IndexStore)
|
||||
-> Result<GatherResult, SessionError>
|
||||
{
|
||||
@@ -392,15 +466,13 @@ impl ListingCompiler {
|
||||
mem::swap(&mut worker.results, &mut toplevel_results);
|
||||
worker.in_module = true;
|
||||
|
||||
self.process_and_commit_decl(decl, &mut worker.term_stream,
|
||||
indices, flags)?;
|
||||
self.process_and_commit_decl(decl, &mut worker, indices, flags)?;
|
||||
|
||||
if let &Some(ref module) = &self.module {
|
||||
worker.term_stream.set_atom_tbl(module.atom_tbl.clone());
|
||||
}
|
||||
} else {
|
||||
self.process_and_commit_decl(decl, &mut worker.term_stream,
|
||||
indices, flags)?;
|
||||
self.process_and_commit_decl(decl, &mut worker, indices, flags)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,25 +480,23 @@ impl ListingCompiler {
|
||||
|
||||
Ok(GatherResult {
|
||||
worker_results: worker.results,
|
||||
dynamic_clause_map: worker.dynamic_clause_map,
|
||||
toplevel_results,
|
||||
toplevel_indices,
|
||||
addition_results
|
||||
})
|
||||
}
|
||||
|
||||
fn drop_expansions(&self, wam: &mut Machine, err: SessionError) -> SessionError {
|
||||
fn drop_expansions(&self, flags: MachineFlags, code_repo: &mut CodeRepo)
|
||||
{
|
||||
let (te_len, te_queue_len) = self.orig_term_expansion_lens;
|
||||
let (ge_len, ge_queue_len) = self.orig_goal_expansion_lens;
|
||||
|
||||
let flags = wam.machine_flags();
|
||||
code_repo.truncate_terms((clause_name!("term_expansion"), 2), te_len, te_queue_len);
|
||||
code_repo.truncate_terms((clause_name!("goal_expansion"), 2), ge_len, ge_queue_len);
|
||||
|
||||
wam.code_repo.truncate_terms((clause_name!("term_expansion"), 2), te_len, te_queue_len);
|
||||
wam.code_repo.truncate_terms((clause_name!("goal_expansion"), 2), ge_len, ge_queue_len);
|
||||
|
||||
discard_result!(wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags));
|
||||
discard_result!(wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion, flags));
|
||||
|
||||
err
|
||||
discard_result!(code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags));
|
||||
discard_result!(code_repo.compile_hook(CompileTimeHook::UserTermExpansion, flags));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +504,7 @@ fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src:
|
||||
mut indices: IndexStore)
|
||||
-> EvalSession
|
||||
{
|
||||
let mut results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
|
||||
let mut results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
|
||||
|
||||
let module_code = try_eval_session!(compiler.generate_code(results.worker_results, wam,
|
||||
&mut indices.code_dir));
|
||||
@@ -446,14 +516,16 @@ fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src:
|
||||
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));
|
||||
|
||||
let flags = wam.machine_flags();
|
||||
|
||||
try_eval_session!(wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion, flags));
|
||||
try_eval_session!(wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags));
|
||||
|
||||
try_eval_session!(compiler.add_code(wam, module_code, indices));
|
||||
try_eval_session!(compiler.add_code(wam, toplvl_code, results.toplevel_indices));
|
||||
|
||||
try_eval_session!(compiler.add_clause_code(results.dynamic_clause_map, wam));
|
||||
|
||||
EvalSession::EntrySuccess
|
||||
}
|
||||
|
||||
@@ -477,7 +549,10 @@ pub fn compile_listing<R: Read>(wam: &mut Machine, src: R, indices: IndexStore)
|
||||
let mut compiler = ListingCompiler::new(&wam.code_repo);
|
||||
|
||||
match compile_work(&mut compiler, wam, src, indices) {
|
||||
EvalSession::Error(e) => EvalSession::Error(compiler.drop_expansions(wam, e)),
|
||||
EvalSession::Error(e) => {
|
||||
compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo);
|
||||
EvalSession::Error(e)
|
||||
},
|
||||
result => result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,10 +175,12 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
HeapCellValue::NamedStr(..) =>
|
||||
self.scan += 1,
|
||||
HeapCellValue::Addr(addr) =>
|
||||
match addr.clone() {
|
||||
match addr {
|
||||
Addr::Lis(addr) =>
|
||||
self.copy_list(addr),
|
||||
Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) =>
|
||||
addr @ Addr::AttrVar(_)
|
||||
| addr @ Addr::HeapCell(_)
|
||||
| addr @ Addr::StackCell(..) =>
|
||||
self.copy_var(addr),
|
||||
Addr::Str(addr) =>
|
||||
self.copy_structure(addr),
|
||||
|
||||
@@ -129,7 +129,7 @@ impl HCValueOutputter for PrinterOutputter {
|
||||
|
||||
#[inline]
|
||||
fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool {
|
||||
arity == 1 && if let &ClauseType::Named(ref name, _) = ct {
|
||||
arity == 1 && if let &ClauseType::Named(ref name, ..) = ct {
|
||||
name.as_str() == "$VAR"
|
||||
} else {
|
||||
false
|
||||
|
||||
@@ -162,13 +162,21 @@ pub struct Rule {
|
||||
pub struct Predicate(pub Vec<PredicateClause>);
|
||||
|
||||
impl Predicate {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Predicate(vec![])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn clauses(self) -> Vec<PredicateClause> {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn predicate_indicator(&self) -> Option<(ClauseName, usize)> {
|
||||
self.0.first()
|
||||
.and_then(|clause| clause.name().map(|name| (name, clause.arity())))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -252,13 +260,16 @@ pub enum SystemClauseType {
|
||||
GetAttrVarQueueDelimiter,
|
||||
GetAttrVarQueueBeyond,
|
||||
GetBValue,
|
||||
GetClause,
|
||||
GetLiftedHeapFromOffset,
|
||||
GetLiftedHeapFromOffsetDiff,
|
||||
GetSCCCleaner,
|
||||
HeadIsDynamic,
|
||||
InstallSCCCleaner,
|
||||
InstallInferenceCounter,
|
||||
LiftedHeapLength,
|
||||
ModuleOf,
|
||||
NoSuchPredicate,
|
||||
RedoAttrVarBindings,
|
||||
RemoveCallPolicyCheck,
|
||||
RemoveInferenceCounter,
|
||||
@@ -307,12 +318,15 @@ impl SystemClauseType {
|
||||
&SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"),
|
||||
&SystemClauseType::GetLiftedHeapFromOffsetDiff => clause_name!("$get_lh_from_offset_diff"),
|
||||
&SystemClauseType::GetBValue => clause_name!("$get_b_value"),
|
||||
&SystemClauseType::GetClause => clause_name!("$get_clause"),
|
||||
&SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"),
|
||||
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
|
||||
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
|
||||
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
|
||||
&SystemClauseType::InstallInferenceCounter => clause_name!("$install_inference_counter"),
|
||||
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
|
||||
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
||||
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
||||
&SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"),
|
||||
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
||||
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
||||
@@ -356,14 +370,17 @@ impl SystemClauseType {
|
||||
("$truncate_if_no_lh_growth_diff", 2) => Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff),
|
||||
("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),
|
||||
("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
|
||||
("$get_clause", 2) => Some(SystemClauseType::GetClause),
|
||||
("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset),
|
||||
("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
|
||||
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
|
||||
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
|
||||
("$head_is_dynamic", 1) => Some(SystemClauseType::HeadIsDynamic),
|
||||
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
|
||||
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
|
||||
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
|
||||
("$module_of", 2) => Some(SystemClauseType::ModuleOf),
|
||||
("$no_such_predicate", 1) => Some(SystemClauseType::NoSuchPredicate),
|
||||
("$redo_attr_var_bindings", 0) => Some(SystemClauseType::RedoAttrVarBindings),
|
||||
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
||||
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
|
||||
@@ -469,7 +486,7 @@ pub enum ClauseType {
|
||||
CallN,
|
||||
Hook(CompileTimeHook),
|
||||
Inlined(InlinedClauseType),
|
||||
Named(ClauseName, CodeIndex),
|
||||
Named(ClauseName, usize, CodeIndex), // name, arity, index.
|
||||
Op(OpDecl, CodeIndex),
|
||||
System(SystemClauseType)
|
||||
}
|
||||
@@ -591,7 +608,7 @@ impl ClauseType {
|
||||
} else if name.as_str() == "call" {
|
||||
ClauseType::CallN
|
||||
} else {
|
||||
ClauseType::Named(name, CodeIndex::default())
|
||||
ClauseType::Named(name, arity, CodeIndex::default())
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -972,11 +989,33 @@ impl From<(usize, ClauseName)> for CodeIndex {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum DynamicAssertPlace {
|
||||
Back, Front
|
||||
}
|
||||
|
||||
impl DynamicAssertPlace {
|
||||
pub fn predicate_name(self) -> ClauseName {
|
||||
match self {
|
||||
DynamicAssertPlace::Back => clause_name!("assertz"),
|
||||
DynamicAssertPlace::Front => clause_name!("asserta")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum DynamicTransactionType {
|
||||
Abolish,
|
||||
Assert(DynamicAssertPlace),
|
||||
Retract(usize) // dynamic index of the clause to remove.
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum CodePtr {
|
||||
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
|
||||
CallN(usize, LocalCodePtr), // arity, local.
|
||||
Local(LocalCodePtr),
|
||||
DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
|
||||
VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
|
||||
}
|
||||
|
||||
@@ -987,6 +1026,7 @@ impl CodePtr {
|
||||
| &CodePtr::CallN(_, ref local)
|
||||
| &CodePtr::Local(ref local) => local.clone(),
|
||||
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
|
||||
&CodePtr::DynamicTransaction(_, p) => p
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1077,9 +1117,10 @@ impl Add<usize> for CodePtr {
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
p @ CodePtr::VerifyAttrInterrupt(_) => p,
|
||||
p @ CodePtr::VerifyAttrInterrupt(_)
|
||||
| p @ CodePtr::DynamicTransaction(..) => p,
|
||||
CodePtr::Local(local) => CodePtr::Local(local + rhs),
|
||||
CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) => CodePtr::Local(local + rhs),
|
||||
CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) => CodePtr::Local(local + rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1115,7 +1156,7 @@ impl<'a> TermIterState<'a> {
|
||||
let op_decl = OpDecl(spec.0, spec.1, name.clone());
|
||||
ClauseType::Op(op_decl, CodeIndex::default())
|
||||
} else {
|
||||
ClauseType::Named(name.clone(), CodeIndex::default())
|
||||
ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default())
|
||||
};
|
||||
|
||||
TermIterState::Clause(lvl, 0, cell, ct, subterms)
|
||||
@@ -1346,6 +1387,7 @@ impl SubModuleUser for Module {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Declaration {
|
||||
Dynamic(ClauseName, usize), // name, arity
|
||||
Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>),
|
||||
Module(ModuleDecl),
|
||||
NonCountedBacktracking(ClauseName, usize), // name, arity
|
||||
@@ -1522,6 +1564,16 @@ impl OpDecl {
|
||||
self.2.clone()
|
||||
}
|
||||
|
||||
pub fn arity(&self) -> usize {
|
||||
let spec = self.1;
|
||||
|
||||
if (spec | XFX != 0) || (spec | XFY != 0) || (spec | YFX != 0) {
|
||||
2
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submit(&self, module: ClauseName, op_dir: &mut OpDir) -> Result<(), SessionError>
|
||||
{
|
||||
let (prec, spec, name) = (self.0, self.1, self.2.clone());
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
(>)/2, (<)/2, (=\=)/2, (=:=)/2, (-)/1, (>=)/2, (=<)/2, (,)/2,
|
||||
(->)/2, (;)/2, (=..)/2, (==)/2, (\==)/2, (@=<)/2, (@>=)/2,
|
||||
(@<)/2, (@>)/2, (=@=)/2, (\=@=)/2, (:)/2, bagof/3,
|
||||
call_with_inference_limit/3, catch/3, current_prolog_flag/2,
|
||||
expand_goal/2, expand_term/2, findall/3, findall/4, once/1,
|
||||
repeat/0, set_prolog_flag/2, setof/3, setup_call_cleanup/3,
|
||||
term_variables/2, throw/1, true/0, false/0, write/1,
|
||||
write_canonical/1, writeq/1, write_term/2]).
|
||||
call_with_inference_limit/3, catch/3, clause/2,
|
||||
current_prolog_flag/2, expand_goal/2, expand_term/2,
|
||||
findall/3, findall/4, once/1, repeat/0, set_prolog_flag/2,
|
||||
setof/3, setup_call_cleanup/3, term_variables/2, throw/1,
|
||||
true/0, false/0, write/1, write_canonical/1, writeq/1,
|
||||
write_term/2]).
|
||||
|
||||
/* this is an implementation specific declarative operator used to implement call_with_inference_limit/3
|
||||
and setup_call_cleanup/3. switches to the default trust_me and retry_me_else. Indexing choice
|
||||
@@ -372,7 +373,7 @@ throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'.
|
||||
|
||||
truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength).
|
||||
|
||||
check_for_compat_list(L, PI) :-
|
||||
check_for_compat_list(L, PI) :-
|
||||
( nonvar(L), L \= [_|_], throw(error(type_error(list, L), PI))
|
||||
; true
|
||||
).
|
||||
@@ -453,3 +454,26 @@ setof(Template, Goal, Solution) :-
|
||||
keysort(PairedSolutions0, PairedSolutions),
|
||||
group_by_variants(PairedSolutions, GroupedSolutions),
|
||||
iterate_variants_and_sort(GroupedSolutions, Witnesses, Solution).
|
||||
|
||||
% Clause retrieval and information.
|
||||
|
||||
'$clause_body_is_valid'(B) :-
|
||||
( var(B) -> true
|
||||
; functor(B, Name, _) -> ( Name == '.' -> throw(error(type_error(callable, B), clause/2))
|
||||
; true
|
||||
)
|
||||
; throw(error(type_error(callable, B), clause/2))
|
||||
).
|
||||
|
||||
clause(H, B) :-
|
||||
( var(H) -> throw(error(instantiation_error, clause/2))
|
||||
; functor(H, Name, Arity) -> ( Name == '.' -> throw(error(type_error(callable, H), clause/2))
|
||||
%% '$no_such_predicate' fails if H is not callable.
|
||||
; '$no_such_predicate'(H) -> '$fail'
|
||||
; '$head_is_dynamic'(H) -> '$clause_body_is_valid'(B),
|
||||
'$get_clause'(H, B)
|
||||
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
||||
clause/2))
|
||||
)
|
||||
; throw(error(type_error(callable, H), clause/2))
|
||||
).
|
||||
|
||||
@@ -25,6 +25,13 @@ impl MachineError {
|
||||
functor!("/", 2, [name, heap_integer!(arity)], (400, YFX))
|
||||
}
|
||||
|
||||
pub(super) fn static_modification_error(perm_error: PermissionError, culprit: Addr) -> Self {
|
||||
let stub = functor!("permission_error", 3, [heap_atom!(perm_error.as_str()),
|
||||
heap_atom!("static_procedure"),
|
||||
HeapCellValue::Addr(culprit)]);
|
||||
MachineError { stub, from: ErrorProvenance::Received }
|
||||
}
|
||||
|
||||
pub(super) fn evaluation_error(eval_error: EvalError) -> Self {
|
||||
let stub = functor!("evaluation_error", 1, [heap_atom!(eval_error.as_str())]);
|
||||
MachineError { stub, from: ErrorProvenance::Received }
|
||||
@@ -153,6 +160,19 @@ impl ValidType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum PermissionError {
|
||||
Modify
|
||||
}
|
||||
|
||||
impl PermissionError {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
PermissionError::Modify => "modify"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum DomainError {
|
||||
NotLessThanZero
|
||||
|
||||
@@ -231,6 +231,7 @@ impl MachineState {
|
||||
self.p = dir_entry!(p);
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn execute_at_index(&mut self, arity: usize, p: usize)
|
||||
{
|
||||
self.num_of_args = arity;
|
||||
|
||||
@@ -2208,7 +2208,7 @@ impl MachineState {
|
||||
try_or_fail!(self, call_policy.compile_hook(self, hook)),
|
||||
&ClauseType::Inlined(ref ct) =>
|
||||
self.execute_inlined(ct),
|
||||
&ClauseType::Named(ref name, ref idx) | &ClauseType::Op(OpDecl(.., ref name), ref idx) =>
|
||||
&ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(OpDecl(.., ref name), ref idx) =>
|
||||
try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(),
|
||||
indices)),
|
||||
&ClauseType::System(ref ct) =>
|
||||
|
||||
@@ -23,11 +23,27 @@ use std::mem;
|
||||
use std::ops::Index;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub type InSituCodeDir = HashMap<PredicateKey, usize>;
|
||||
//pub type DynamicPredicateClauses = VecDeque<(PredicateClause, VecDeque<TopLevel>)>;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct DynamicPredicateInfo {
|
||||
pub(super) clauses_subsection_p: usize, // a LocalCodePtr::DirEntry value.
|
||||
// clauses: DynamicPredicateClauses
|
||||
}
|
||||
|
||||
impl Default for DynamicPredicateInfo {
|
||||
fn default() -> Self {
|
||||
DynamicPredicateInfo { clauses_subsection_p: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
pub type InSituCodeDir = HashMap<PredicateKey, usize>;
|
||||
pub type DynamicCodeDir = HashMap<PredicateKey, DynamicPredicateInfo>;
|
||||
|
||||
pub struct IndexStore {
|
||||
pub(super) atom_tbl: TabledData<Atom>,
|
||||
pub(super) code_dir: CodeDir,
|
||||
pub(super) dynamic_code_dir: DynamicCodeDir,
|
||||
pub(super) in_situ_code_dir: InSituCodeDir,
|
||||
pub(super) op_dir: OpDir,
|
||||
pub(super) modules: ModuleDir,
|
||||
@@ -48,6 +64,24 @@ impl<'a, T> RefOrOwned<'a, T> {
|
||||
}
|
||||
|
||||
impl IndexStore {
|
||||
pub fn predicate_exists(&self, name: ClauseName, arity: usize,
|
||||
op_spec: Option<(usize, Specifier)>)
|
||||
-> bool
|
||||
{
|
||||
match ClauseType::from(name, arity, op_spec) {
|
||||
ClauseType::Named(name, arity, _) =>
|
||||
self.code_dir.contains_key(&(name, arity)),
|
||||
ClauseType::Op(op_decl, ..) =>
|
||||
self.code_dir.contains_key(&(op_decl.name(), op_decl.arity())),
|
||||
_ => true
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_clause_subsection(&self, name: ClauseName, arity: usize) -> Option<DynamicPredicateInfo> {
|
||||
self.dynamic_code_dir.get(&(name, arity)).cloned()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn take_module(&mut self, name: ClauseName) -> Option<Module> {
|
||||
self.modules.remove(&name)
|
||||
@@ -63,6 +97,7 @@ impl IndexStore {
|
||||
IndexStore {
|
||||
atom_tbl: TabledData::new(Rc::new("user".to_string())),
|
||||
code_dir: CodeDir::new(),
|
||||
dynamic_code_dir: DynamicCodeDir::new(),
|
||||
in_situ_code_dir: InSituCodeDir::new(),
|
||||
op_dir: default_op_dir(),
|
||||
modules: ModuleDir::new(),
|
||||
@@ -204,7 +239,8 @@ impl CodeRepo {
|
||||
},
|
||||
&CodePtr::VerifyAttrInterrupt(p) =>
|
||||
Some(RefOrOwned::Borrowed(&self.code[p])),
|
||||
|
||||
&CodePtr::DynamicTransaction(..) =>
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,11 +431,11 @@ impl Machine {
|
||||
// ensure we don't try to overwrite an existing predicate from a different module.
|
||||
if !existing_idx.is_undefined() && !idx.is_undefined() {
|
||||
// allow the overwriting of user-level predicates by all other predicates.
|
||||
if existing_idx.module_name().as_str() == "user" {
|
||||
if existing_idx.module_name() == key.0.owning_module() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if existing_idx.module_name().as_str() != idx.module_name().as_str() {
|
||||
if existing_idx.module_name() != idx.module_name() {
|
||||
let err_str = format!("{}/{} from module {}", key.0, key.1,
|
||||
existing_idx.module_name().as_str());
|
||||
return Err(SessionError::CannotOverwriteImport(err_str));
|
||||
@@ -464,8 +500,7 @@ impl Machine {
|
||||
let mut heap_locs = HashMap::new();
|
||||
|
||||
self.code_repo.cached_query = code;
|
||||
self.machine_st.run_query(&mut self.indices, &mut self.policies, &mut self.code_repo,
|
||||
&alloc_locs, &mut heap_locs);
|
||||
self.run_query(&alloc_locs, &mut heap_locs);
|
||||
|
||||
if self.machine_st.fail {
|
||||
self.fail(&heap_locs)
|
||||
@@ -474,6 +509,67 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
fn record_var_places(&self, chunk_num: usize, alloc_locs: &AllocVarDict,
|
||||
heap_locs: &mut HeapVarDict)
|
||||
{
|
||||
for (var, var_data) in alloc_locs {
|
||||
match var_data {
|
||||
&VarData::Perm(p) if p > 0 =>
|
||||
if !heap_locs.contains_key(var) {
|
||||
let e = self.machine_st.e;
|
||||
let r = var_data.as_reg_type().reg_num();
|
||||
let addr = self.machine_st.and_stack[e][r].clone();
|
||||
|
||||
heap_locs.insert(var.clone(), addr);
|
||||
},
|
||||
&VarData::Temp(cn, _, _) if cn == chunk_num => {
|
||||
let r = var_data.as_reg_type();
|
||||
|
||||
if r.reg_num() != 0 {
|
||||
let addr = self.machine_st[r].clone();
|
||||
heap_locs.insert(var.clone(), addr);
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn run_query(&mut self, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict)
|
||||
{
|
||||
let end_ptr = top_level_code_ptr!(0, self.code_repo.size_of_cached_query());
|
||||
|
||||
while self.machine_st.p < end_ptr {
|
||||
if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.machine_st.p {
|
||||
match &self.code_repo[LocalCodePtr::TopLevel(cn, p)] {
|
||||
&Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
|
||||
self.record_var_places(cn, alloc_locs, heap_locs);
|
||||
cn += 1;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.machine_st.p = top_level_code_ptr!(cn, p);
|
||||
}
|
||||
|
||||
self.machine_st.query_stepper(&mut self.indices, &mut self.policies, &mut self.code_repo);
|
||||
|
||||
match self.machine_st.p {
|
||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {},
|
||||
CodePtr::DynamicTransaction(trans_type, p) => {},
|
||||
// self.dynamic_transaction(trans_type, p),
|
||||
_ => {
|
||||
if heap_locs.is_empty() {
|
||||
self.record_var_places(0, alloc_locs, heap_locs);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn continue_query(&mut self, alloc_l: &AllocVarDict, heap_l: &mut HeapVarDict) -> EvalSession
|
||||
{
|
||||
if !self.or_stack_is_empty() {
|
||||
@@ -484,8 +580,7 @@ impl Machine {
|
||||
return EvalSession::from(SessionError::QueryFailure);
|
||||
}
|
||||
|
||||
self.machine_st.run_query(&mut self.indices, &mut self.policies, &mut self.code_repo,
|
||||
alloc_l, heap_l);
|
||||
self.run_query(alloc_l, heap_l);
|
||||
|
||||
if self.machine_st.fail {
|
||||
self.fail(&heap_l)
|
||||
@@ -601,73 +696,12 @@ impl MachineState {
|
||||
self.fail = true,
|
||||
CodePtr::Local(LocalCodePtr::InSituDirEntry(p))
|
||||
if p < code_repo.in_situ_code.len() => {},
|
||||
CodePtr::Local(_) =>
|
||||
CodePtr::Local(_) | CodePtr::DynamicTransaction(..) =>
|
||||
break,
|
||||
CodePtr::VerifyAttrInterrupt(p) =>
|
||||
self.verify_attr_interrupt(p),
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn record_var_places(&self, chunk_num: usize, alloc_locs: &AllocVarDict,
|
||||
heap_locs: &mut HeapVarDict)
|
||||
{
|
||||
for (var, var_data) in alloc_locs {
|
||||
match var_data {
|
||||
&VarData::Perm(p) if p > 0 =>
|
||||
if !heap_locs.contains_key(var) {
|
||||
let e = self.e;
|
||||
let r = var_data.as_reg_type().reg_num(); // crashes here.
|
||||
let addr = self.and_stack[e][r].clone();
|
||||
|
||||
heap_locs.insert(var.clone(), addr);
|
||||
},
|
||||
&VarData::Temp(cn, _, _) if cn == chunk_num => {
|
||||
let r = var_data.as_reg_type();
|
||||
|
||||
if r.reg_num() != 0 {
|
||||
let addr = self[r].clone();
|
||||
heap_locs.insert(var.clone(), addr);
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn run_query(&mut self, indices: &mut IndexStore,
|
||||
policies: &mut MachinePolicies, code_repo: &mut CodeRepo,
|
||||
alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict)
|
||||
{
|
||||
let end_ptr = top_level_code_ptr!(0, code_repo.size_of_cached_query());
|
||||
|
||||
while self.p < end_ptr {
|
||||
if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.p {
|
||||
match &code_repo[LocalCodePtr::TopLevel(cn, p)] {
|
||||
&Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
|
||||
self.record_var_places(cn, alloc_locs, heap_locs);
|
||||
cn += 1;
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.p = top_level_code_ptr!(cn, p);
|
||||
}
|
||||
|
||||
self.query_stepper(indices, policies, code_repo);
|
||||
|
||||
match self.p {
|
||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {},
|
||||
_ => {
|
||||
if heap_locs.is_empty() {
|
||||
self.record_var_places(0, alloc_locs, heap_locs);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +244,21 @@ impl MachineState {
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::HeadIsDynamic => {
|
||||
let head = self[temp_v!(1)].clone();
|
||||
|
||||
self.fail = !match self.store(self.deref(head)) {
|
||||
Addr::Str(s) =>
|
||||
match self.heap[s].clone() {
|
||||
HeapCellValue::NamedStr(arity, name, ..) =>
|
||||
indices.get_clause_subsection(name, arity).is_some(),
|
||||
_ => unreachable!()
|
||||
},
|
||||
Addr::Con(Constant::Atom(name, _)) =>
|
||||
indices.get_clause_subsection(name, 0).is_some(),
|
||||
_ => unreachable!()
|
||||
};
|
||||
},
|
||||
&SystemClauseType::CopyToLiftedHeap =>
|
||||
// now, stagger everything down by the length of the heap + lh offset.
|
||||
match self.store(self.deref(self[temp_v!(1)].clone())) {
|
||||
@@ -562,6 +577,26 @@ impl MachineState {
|
||||
_ => self.fail = true
|
||||
};
|
||||
},
|
||||
&SystemClauseType::NoSuchPredicate => {
|
||||
let head = self[temp_v!(1)].clone();
|
||||
|
||||
self.fail = match self.store(self.deref(head)) {
|
||||
Addr::Str(s) =>
|
||||
match self.heap[s].clone() {
|
||||
HeapCellValue::NamedStr(arity, name, op_spec) =>
|
||||
indices.predicate_exists(name, arity, op_spec),
|
||||
_ => unreachable!()
|
||||
},
|
||||
Addr::Con(Constant::Atom(name, op_spec)) =>
|
||||
indices.predicate_exists(name, 0, op_spec),
|
||||
head => {
|
||||
let err = MachineError::type_error(ValidType::Callable, head);
|
||||
let stub = MachineError::functor_stub(clause_name!("clause"), 2);
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
}
|
||||
};
|
||||
},
|
||||
&SystemClauseType::RedoAttrVarBindings => {
|
||||
let mut bindings = mem::replace(&mut self.attr_var_init.bindings, vec![]);
|
||||
|
||||
@@ -727,6 +762,30 @@ impl MachineState {
|
||||
|
||||
self.unify(a1, a2);
|
||||
},
|
||||
&SystemClauseType::GetClause => {
|
||||
let head = self[temp_v!(1)].clone();
|
||||
let body = self[temp_v!(2)].clone();
|
||||
|
||||
let subsection = match self.store(self.deref(head)) {
|
||||
Addr::Str(s) =>
|
||||
match self.heap[s].clone() {
|
||||
HeapCellValue::NamedStr(arity, name, ..) =>
|
||||
indices.get_clause_subsection(name, arity),
|
||||
_ => unreachable!()
|
||||
},
|
||||
Addr::Con(Constant::Atom(name, _)) =>
|
||||
indices.get_clause_subsection(name, 0),
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
match subsection {
|
||||
Some(dynamic_predicate_info) => {
|
||||
self.execute_at_index(2, dynamic_predicate_info.clauses_subsection_p);
|
||||
return Ok(());
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
},
|
||||
&SystemClauseType::GetCutPoint => {
|
||||
let a1 = self[temp_v!(1)].clone();
|
||||
let a2 = Addr::Con(Constant::Usize(self.b0));
|
||||
|
||||
@@ -288,11 +288,16 @@ impl<'a, R: Read> TermStream<'a, R> {
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
fn print_with_locs(&self, target: usize, max_var_length: usize, var_dict: &HeapVarDict)
|
||||
-> PrinterOutputter
|
||||
pub(super)
|
||||
fn print_with_locs(&self, addr: Addr, var_dict: &HeapVarDict) -> PrinterOutputter
|
||||
{
|
||||
let output = PrinterOutputter::new();
|
||||
let mut printer = HCPrinter::from_heap_locs(&self, output, &var_dict);
|
||||
let mut printer = HCPrinter::from_heap_locs(&self, output, var_dict);
|
||||
let mut max_var_length = 0;
|
||||
|
||||
for var in var_dict.keys() {
|
||||
max_var_length = std::cmp::max(var.len(), max_var_length);
|
||||
}
|
||||
|
||||
printer.quoted = true;
|
||||
printer.numbervars = true;
|
||||
@@ -302,10 +307,12 @@ impl MachineState {
|
||||
// style variable names will be longer than the keys of the var_dict, and therefore
|
||||
// not equal to any of them.
|
||||
printer.numbervars_offset = pow(BigInt::from(10), max_var_length) * 26;
|
||||
|
||||
printer.see_all_locs();
|
||||
|
||||
printer.print(Addr::HeapCell(target))
|
||||
let mut output = printer.print(addr);
|
||||
|
||||
output.push_char('.');
|
||||
output
|
||||
}
|
||||
|
||||
fn try_expand_term(&mut self, indices: &mut IndexStore, policies: &mut MachinePolicies,
|
||||
@@ -322,16 +329,15 @@ impl MachineState {
|
||||
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
|
||||
|
||||
code_repo.cached_query = code;
|
||||
self.run_query(indices, policies, code_repo, &AllocVarDict::new(), &mut HeapVarDict::new());
|
||||
self.query_stepper(indices, policies, code_repo);
|
||||
|
||||
if self.fail {
|
||||
self.reset();
|
||||
None
|
||||
} else {
|
||||
let &TermWriteResult { heap_loc: _, max_var_length, ref var_dict } = &term_write_result;
|
||||
let mut output = self.print_with_locs(h, max_var_length, var_dict);
|
||||
let &TermWriteResult { heap_loc: _, ref var_dict } = &term_write_result;
|
||||
let output = self.print_with_locs(Addr::HeapCell(h), var_dict);
|
||||
|
||||
output.push_char('.');
|
||||
self.reset();
|
||||
Some(output.result())
|
||||
}
|
||||
|
||||
@@ -213,6 +213,7 @@ macro_rules! index_store {
|
||||
($atom_tbl:expr, $code_dir:expr, $op_dir:expr, $modules:expr) => (
|
||||
IndexStore { atom_tbl: $atom_tbl,
|
||||
code_dir: $code_dir,
|
||||
dynamic_code_dir: DynamicCodeDir::new(),
|
||||
in_situ_code_dir: InSituCodeDir::new(),
|
||||
op_dir: $op_dir,
|
||||
modules: $modules }
|
||||
|
||||
@@ -75,15 +75,13 @@ fn modify_head_of_queue(machine_st: &mut MachineState, queue: &mut SubtermDeque,
|
||||
|
||||
pub(crate) struct TermWriteResult {
|
||||
pub(crate) heap_loc: usize,
|
||||
pub(crate) max_var_length: usize, // maximum length of the variable names encountered.
|
||||
pub(crate) var_dict: HeapVarDict,
|
||||
pub(crate) var_dict: HeapVarDict,
|
||||
}
|
||||
|
||||
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult
|
||||
{
|
||||
let heap_loc = machine_st.heap.h;
|
||||
|
||||
let mut max_var_length = 0;
|
||||
let mut queue = SubtermDeque::new();
|
||||
let mut var_dict = HeapVarDict::new();
|
||||
|
||||
@@ -118,10 +116,8 @@ pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) ->
|
||||
},
|
||||
&TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) =>
|
||||
machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h))),
|
||||
&TermRef::Var(Level::Root, _, ref name) => {
|
||||
max_var_length = std::cmp::max(max_var_length, name.len());
|
||||
machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h)));
|
||||
},
|
||||
&TermRef::Var(Level::Root, _, ref name) =>
|
||||
machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h))),
|
||||
&TermRef::AnonVar(_) => {
|
||||
if let Some((arity, site_h)) = queue.pop_front() {
|
||||
if arity > 1 {
|
||||
@@ -144,7 +140,6 @@ pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) ->
|
||||
}
|
||||
}
|
||||
|
||||
max_var_length = std::cmp::max(max_var_length, var.len());
|
||||
continue;
|
||||
},
|
||||
_ => {}
|
||||
@@ -153,5 +148,5 @@ pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) ->
|
||||
modify_head_of_queue(machine_st, &mut queue, term, h);
|
||||
}
|
||||
|
||||
TermWriteResult { heap_loc, var_dict, max_var_length }
|
||||
TermWriteResult { heap_loc, var_dict }
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use prolog::machine::term_expansion::*;
|
||||
use prolog::num::*;
|
||||
|
||||
use std::borrow::BorrowMut;
|
||||
use std::collections::{HashSet, VecDeque};
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::cell::Cell;
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
@@ -58,9 +58,9 @@ impl<'a, 'b> CompositeIndices<'a, 'b>
|
||||
fn get_clause_type(&mut self, name: ClauseName, arity: usize, spec: Option<(usize, Specifier)>) -> ClauseType
|
||||
{
|
||||
match ClauseType::from(name, arity, spec) {
|
||||
ClauseType::Named(name, _) => {
|
||||
ClauseType::Named(name, arity, _) => {
|
||||
let idx = self.get_code_index(name.clone(), arity);
|
||||
ClauseType::Named(name, idx.clone())
|
||||
ClauseType::Named(name, arity, idx.clone())
|
||||
},
|
||||
ClauseType::Op(op_decl, _) => {
|
||||
let idx = self.get_code_index(op_decl.2.clone(), arity);
|
||||
@@ -112,16 +112,6 @@ fn is_compile_time_hook(name: &ClauseName, terms: &Vec<Box<Term>>) -> Option<Com
|
||||
|
||||
type CompileTimeHookCompileInfo = (CompileTimeHook, PredicateClause, VecDeque<TopLevel>);
|
||||
|
||||
fn setup_fact(term: Term) -> Result<Term, ParserError>
|
||||
{
|
||||
match term {
|
||||
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) =>
|
||||
Ok(term),
|
||||
_ =>
|
||||
Err(ParserError::InadmissibleFact)
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_op_decl(mut terms: Vec<Box<Term>>) -> Result<OpDecl, ParserError>
|
||||
{
|
||||
let name = match *terms.pop().unwrap() {
|
||||
@@ -155,7 +145,7 @@ fn setup_op_decl(mut terms: Vec<Box<Term>>) -> Result<OpDecl, ParserError>
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_predicate_export(mut term: Term) -> Result<PredicateKey, ParserError>
|
||||
fn setup_predicate_indicator(mut term: Term) -> Result<PredicateKey, ParserError>
|
||||
{
|
||||
match term {
|
||||
Term::Clause(_, ref name, ref mut terms, Some(_))
|
||||
@@ -185,7 +175,7 @@ fn setup_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleDecl, ParserErro
|
||||
let mut exports = Vec::new();
|
||||
|
||||
while let Term::Cons(_, t1, t2) = export_list {
|
||||
exports.push(setup_predicate_export(*t1)?);
|
||||
exports.push(setup_predicate_indicator(*t1)?);
|
||||
export_list = *t2;
|
||||
}
|
||||
|
||||
@@ -227,7 +217,7 @@ fn setup_qualified_import(mut terms: Vec<Box<Term>>) -> Result<UseModuleExport,
|
||||
let mut exports = Vec::new();
|
||||
|
||||
while let Term::Cons(_, t1, t2) = export_list {
|
||||
exports.push(setup_predicate_export(*t1)?);
|
||||
exports.push(setup_predicate_indicator(*t1)?);
|
||||
export_list = *t2;
|
||||
}
|
||||
|
||||
@@ -252,8 +242,11 @@ fn setup_declaration(term: Term) -> Result<Declaration, ParserError>
|
||||
let (name, exports) = setup_qualified_import(terms)?;
|
||||
Ok(Declaration::UseQualifiedModule(name, exports))
|
||||
} else if name.as_str() == "non_counted_backtracking" && terms.len() == 1 {
|
||||
let (name, arity) = setup_predicate_export(*terms.pop().unwrap())?;
|
||||
let (name, arity) = setup_predicate_indicator(*terms.pop().unwrap())?;
|
||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||
} else if name.as_str() == "dynamic" && terms.len() == 1 {
|
||||
let (name, arity) = setup_predicate_indicator(*terms.pop().unwrap())?;
|
||||
Ok(Declaration::Dynamic(name, arity))
|
||||
} else {
|
||||
Err(ParserError::InconsistentEntry)
|
||||
},
|
||||
@@ -387,12 +380,29 @@ pub enum TopLevelPacket {
|
||||
}
|
||||
|
||||
struct RelationWorker {
|
||||
dynamic_clauses: Vec<(Term, Term)>, // Head, Body.
|
||||
queue: VecDeque<VecDeque<Term>>,
|
||||
}
|
||||
|
||||
impl RelationWorker {
|
||||
fn new() -> Self {
|
||||
RelationWorker { queue: VecDeque::new() }
|
||||
RelationWorker { dynamic_clauses: vec![],
|
||||
queue: VecDeque::new() }
|
||||
}
|
||||
|
||||
fn setup_fact(&mut self, term: Term) -> Result<Term, ParserError>
|
||||
{
|
||||
match term {
|
||||
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
|
||||
let tail = Term::Constant(Cell::default(),
|
||||
Constant::Atom(clause_name!("true"), None));
|
||||
|
||||
self.dynamic_clauses.push((term.clone(), tail));
|
||||
Ok(term)
|
||||
},
|
||||
_ =>
|
||||
Err(ParserError::InadmissibleFact)
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_head(&self, term: &Term) -> Vec<Term>
|
||||
@@ -617,7 +627,7 @@ impl RelationWorker {
|
||||
match flatten_hook(term) {
|
||||
Term::Clause(r, name, terms, _) =>
|
||||
if name == hook.name() && terms.len() == hook.arity() {
|
||||
let term = setup_fact(Term::Clause(r, name, terms, None))?;
|
||||
let term = self.setup_fact(Term::Clause(r, name, terms, None))?;
|
||||
Ok((hook, PredicateClause::Fact(term), VecDeque::from(vec![])))
|
||||
} else if name.as_str() == ":-" && terms.len() == 2 {
|
||||
let rule = self.setup_rule(indices, terms, true)?;
|
||||
@@ -635,8 +645,14 @@ impl RelationWorker {
|
||||
blocks_cuts: bool)
|
||||
-> Result<Rule, ParserError>
|
||||
{
|
||||
let post_head_terms = terms.drain(1..).collect();
|
||||
let mut query_terms = try!(self.setup_query(indices, post_head_terms, blocks_cuts));
|
||||
let post_head_terms: Vec<_> = terms.drain(1 ..).collect();
|
||||
|
||||
let head = *terms.first().cloned().unwrap();
|
||||
let tail = *post_head_terms.first().cloned().unwrap();
|
||||
|
||||
self.dynamic_clauses.push((head, tail));
|
||||
|
||||
let mut query_terms = self.setup_query(indices, post_head_terms, blocks_cuts)?;
|
||||
let clauses = query_terms.drain(1 ..).collect();
|
||||
let qt = query_terms.pop().unwrap();
|
||||
|
||||
@@ -668,9 +684,9 @@ impl RelationWorker {
|
||||
Ok(TopLevel::Declaration(try!(setup_declaration(term))))
|
||||
} else {
|
||||
let term = Term::Clause(r, name, terms, fixity);
|
||||
Ok(TopLevel::Fact(try!(setup_fact(term))))
|
||||
Ok(TopLevel::Fact(try!(self.setup_fact(term))))
|
||||
},
|
||||
term => Ok(TopLevel::Fact(try!(setup_fact(term))))
|
||||
term => Ok(TopLevel::Fact(try!(self.setup_fact(term))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,6 +717,7 @@ impl RelationWorker {
|
||||
|
||||
fn absorb(&mut self, other: RelationWorker) {
|
||||
self.queue.extend(other.queue.into_iter());
|
||||
self.dynamic_clauses.extend(other.dynamic_clauses.into_iter());
|
||||
}
|
||||
|
||||
fn expand_queue_contents<'a, R>(&mut self, term_stream: &mut TermStream<'a, R>, op_dir: &OpDir)
|
||||
@@ -731,7 +748,8 @@ fn term_to_toplevel<'a, R>(term_stream: &mut TermStream<'a, R>, code_dir: &mut C
|
||||
let mut rel_worker = RelationWorker::new();
|
||||
let mut indices = composite_indices!(false, term_stream.indices, code_dir);
|
||||
|
||||
Ok((rel_worker.try_term_to_tl(&mut indices, term, true)?, rel_worker))
|
||||
let tl = rel_worker.try_term_to_tl(&mut indices, term, true)?;
|
||||
Ok((tl, rel_worker))
|
||||
}
|
||||
|
||||
pub
|
||||
@@ -757,10 +775,13 @@ fn string_to_toplevel<R: Read>(src: R, buffer: String, wam: &mut Machine)
|
||||
Ok(deque_to_packet(tl, queue))
|
||||
}
|
||||
|
||||
pub type DynamicClauseMap = HashMap<(ClauseName, usize), Vec<(Term, Term)>>;
|
||||
|
||||
pub struct TopLevelBatchWorker<'a, R: Read> {
|
||||
pub(crate) term_stream: TermStream<'a, R>,
|
||||
rel_worker: RelationWorker,
|
||||
pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
|
||||
pub(crate) dynamic_clause_map: DynamicClauseMap,
|
||||
pub(crate) in_module: bool
|
||||
}
|
||||
|
||||
@@ -776,6 +797,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
||||
TopLevelBatchWorker { term_stream,
|
||||
rel_worker: RelationWorker::new(),
|
||||
results: vec![],
|
||||
dynamic_clause_map: HashMap::new(),
|
||||
in_module: false }
|
||||
}
|
||||
|
||||
@@ -790,7 +812,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
||||
}
|
||||
|
||||
fn process_result(&mut self, indices: &mut IndexStore, preds: &mut Vec<PredicateClause>)
|
||||
-> Result<(Predicate, VecDeque<TopLevel>), SessionError>
|
||||
-> Result<(), SessionError>
|
||||
{
|
||||
self.rel_worker.expand_queue_contents(&mut self.term_stream, &indices.op_dir)?;
|
||||
|
||||
@@ -805,7 +827,26 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
||||
self.term_stream.code_repo.add_in_situ_result(&result, in_situ_code_dir,
|
||||
self.term_stream.flags)?;
|
||||
|
||||
Ok(result)
|
||||
Ok(self.results.push(result))
|
||||
}
|
||||
|
||||
fn take_dynamic_clauses(&mut self) {
|
||||
let (name, arity) = match self.rel_worker.dynamic_clauses.first() {
|
||||
Some((head, tail)) =>
|
||||
(head.name().unwrap(), head.arity()),
|
||||
None =>
|
||||
return
|
||||
};
|
||||
|
||||
match self.dynamic_clause_map.get_mut(&(name.clone(), arity)) {
|
||||
Some(ref mut entry) => {
|
||||
entry.clear(); // don't treat dynamic predicates as if they're discontiguous.
|
||||
entry.extend(self.rel_worker.dynamic_clauses.drain(0 ..));
|
||||
},
|
||||
_ => {
|
||||
self.rel_worker.dynamic_clauses.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume(&mut self, indices: &mut IndexStore) -> Result<Option<Declaration>, SessionError>
|
||||
@@ -818,8 +859,8 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
||||
|
||||
// if is_consistent is false, preds is non-empty.
|
||||
if !is_consistent(&tl, &preds) {
|
||||
let result = self.process_result(indices, &mut preds)?;
|
||||
self.results.push(result);
|
||||
self.process_result(indices, &mut preds)?;
|
||||
self.take_dynamic_clauses();
|
||||
}
|
||||
|
||||
self.rel_worker.absorb(new_rel_worker);
|
||||
@@ -834,8 +875,8 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
||||
}
|
||||
|
||||
if !preds.is_empty() {
|
||||
let result = self.process_result(indices, &mut preds)?;
|
||||
self.results.push(result);
|
||||
self.process_result(indices, &mut preds)?;
|
||||
self.take_dynamic_clauses();
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
|
||||
@@ -136,7 +136,8 @@ impl fmt::Display for ClauseType {
|
||||
match self {
|
||||
&ClauseType::System(SystemClauseType::SetCutPoint(r)) =>
|
||||
write!(f, "$set_cp({})", r),
|
||||
&ClauseType::Named(ref name, ref idx) | &ClauseType::Op(OpDecl(.., ref name), ref idx) =>
|
||||
&ClauseType::Named(ref name, _, ref idx)
|
||||
| &ClauseType::Op(OpDecl(.., ref name), ref idx) =>
|
||||
{
|
||||
let idx = idx.0.borrow();
|
||||
write!(f, "{}:{}/{}", idx.1, name, idx.0)
|
||||
|
||||
Reference in New Issue
Block a user