Update cargo dependencies Apply cargo fix --edition Change cargo.toml edition property to `2024` ^ Conflicts: ^ Cargo.lock ^ src/ffi.rs ^ Conflicts: ^ src/offset_table.rs ^ src/raw_block.rs
1323 lines
47 KiB
Rust
1323 lines
47 KiB
Rust
use crate::forms::*;
|
|
use crate::machine::loader::*;
|
|
use crate::machine::machine_errors::*;
|
|
use crate::machine::machine_indices::*;
|
|
use crate::machine::term_stream::*;
|
|
use crate::machine::*;
|
|
use crate::parser::ast::*;
|
|
|
|
use fxhash::FxBuildHasher;
|
|
use indexmap::IndexSet;
|
|
|
|
use std::collections::VecDeque;
|
|
use std::fs::File;
|
|
use std::mem;
|
|
|
|
pub(super) type ModuleOpExports = Vec<(OpDecl, Option<OpDesc>)>;
|
|
|
|
pub(super) fn set_code_index<'a, LS: LoadState<'a>>(
|
|
payload: &mut <LS as LoadState<'a>>::LoaderFieldType,
|
|
compilation_target: &CompilationTarget,
|
|
key: PredicateKey,
|
|
code_idx: CodeIndex,
|
|
code_ptr: IndexPtr,
|
|
) {
|
|
let record = LS::machine_st(payload).arena.code_index_tbl.with_entry_mut(
|
|
code_idx.into(),
|
|
|code_idx_ptr| match compilation_target {
|
|
CompilationTarget::User => {
|
|
if IndexPtrTag::Undefined == code_idx_ptr.tag() {
|
|
*code_idx_ptr = code_ptr;
|
|
RetractionRecord::AddedUserPredicate(key)
|
|
} else {
|
|
let replaced = mem::replace(code_idx_ptr, code_ptr);
|
|
RetractionRecord::ReplacedUserPredicate(key, replaced)
|
|
}
|
|
}
|
|
CompilationTarget::Module(module_name) => {
|
|
if IndexPtrTag::Undefined == code_idx_ptr.tag() {
|
|
*code_idx_ptr = code_ptr;
|
|
RetractionRecord::AddedModulePredicate(*module_name, key)
|
|
} else {
|
|
let replaced = mem::replace(code_idx_ptr, code_ptr);
|
|
RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced)
|
|
}
|
|
}
|
|
},
|
|
);
|
|
|
|
payload.retraction_info.push_record(record);
|
|
}
|
|
|
|
fn add_op_decl_as_module_export<'a, LS: LoadState<'a>>(
|
|
payload: &mut LS::LoaderFieldType,
|
|
module_op_dir: &mut OpDir,
|
|
wam_op_dir: &mut OpDir,
|
|
op_decl: &OpDecl,
|
|
) {
|
|
/*
|
|
insert the operator at top-level so it can
|
|
inform the parser. it will be retracted
|
|
from the user-level op_dir when the load
|
|
succeeds.
|
|
*/
|
|
|
|
match op_decl.insert_into_op_dir(wam_op_dir) {
|
|
Some(op_desc) => {
|
|
payload
|
|
.retraction_info
|
|
.push_record(RetractionRecord::ReplacedUserOp(*op_decl, op_desc));
|
|
|
|
payload.module_op_exports.push((*op_decl, Some(op_desc)));
|
|
}
|
|
None => {
|
|
payload
|
|
.retraction_info
|
|
.push_record(RetractionRecord::AddedUserOp(*op_decl));
|
|
payload.module_op_exports.push((*op_decl, None));
|
|
}
|
|
}
|
|
|
|
let compilation_target = payload.compilation_target;
|
|
add_op_decl(
|
|
&mut payload.retraction_info,
|
|
&compilation_target,
|
|
module_op_dir,
|
|
op_decl,
|
|
);
|
|
}
|
|
|
|
pub(super) fn add_op_decl(
|
|
retraction_info: &mut RetractionInfo,
|
|
compilation_target: &CompilationTarget,
|
|
op_dir: &mut OpDir,
|
|
op_decl: &OpDecl,
|
|
) {
|
|
match op_decl.insert_into_op_dir(op_dir) {
|
|
Some(op_desc) => match &compilation_target {
|
|
CompilationTarget::User => {
|
|
retraction_info.push_record(RetractionRecord::ReplacedUserOp(*op_decl, op_desc));
|
|
}
|
|
CompilationTarget::Module(module_name) => {
|
|
retraction_info.push_record(RetractionRecord::ReplacedModuleOp(
|
|
*module_name,
|
|
*op_decl,
|
|
op_desc,
|
|
));
|
|
}
|
|
},
|
|
None => match &compilation_target {
|
|
CompilationTarget::User => {
|
|
retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
|
|
}
|
|
CompilationTarget::Module(module_name) => {
|
|
retraction_info
|
|
.push_record(RetractionRecord::AddedModuleOp(*module_name, *op_decl));
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
|
|
payload: &mut LS::LoaderFieldType,
|
|
compilation_target: &CompilationTarget,
|
|
imported_module: &Module,
|
|
code_dir: &mut CodeDir,
|
|
op_dir: &mut OpDir,
|
|
meta_predicates: &mut MetaPredicateDir,
|
|
) -> Result<(), SessionError> {
|
|
for export in imported_module.module_decl.exports.iter() {
|
|
match export {
|
|
ModuleExport::PredicateKey((name, arity)) => {
|
|
let key = (*name, *arity);
|
|
|
|
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
|
|
meta_predicates.insert(key, meta_specs.clone());
|
|
}
|
|
|
|
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
|
|
let code_idx_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
|
|
|
let target_code_index = *code_dir
|
|
.entry(key)
|
|
.or_insert_with(|| CodeIndex::default(code_idx_tbl));
|
|
|
|
let src_code_index_ptr = code_idx_tbl.get_entry(src_code_index.into());
|
|
|
|
set_code_index::<LS>(
|
|
payload,
|
|
compilation_target,
|
|
key,
|
|
target_code_index,
|
|
src_code_index_ptr,
|
|
);
|
|
|
|
if LS::machine_st(payload)
|
|
.arena
|
|
.code_index_tbl
|
|
.get_entry(src_code_index.into())
|
|
.is_dynamic_undefined()
|
|
{
|
|
code_dir.insert(key, src_code_index);
|
|
}
|
|
} else {
|
|
return Err(SessionError::ModuleDoesNotContainExport(
|
|
imported_module.module_decl.name,
|
|
key,
|
|
));
|
|
}
|
|
}
|
|
ModuleExport::OpDecl(op_decl) => {
|
|
add_op_decl(
|
|
&mut payload.retraction_info,
|
|
compilation_target,
|
|
op_dir,
|
|
op_decl,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn import_module_exports_into_module<'a, LS: LoadState<'a>>(
|
|
payload: &mut LS::LoaderFieldType,
|
|
compilation_target: &CompilationTarget,
|
|
imported_module: &Module,
|
|
code_dir: &mut CodeDir,
|
|
op_dir: &mut OpDir,
|
|
meta_predicates: &mut MetaPredicateDir,
|
|
wam_op_dir: &mut OpDir,
|
|
) -> Result<(), SessionError> {
|
|
for export in imported_module.module_decl.exports.iter() {
|
|
match export {
|
|
ModuleExport::PredicateKey((name, arity)) => {
|
|
let key = (*name, *arity);
|
|
|
|
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
|
|
meta_predicates.insert(key, meta_specs.clone());
|
|
}
|
|
|
|
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
|
|
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
|
|
|
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
|
|
let target_code_index = *code_dir
|
|
.entry(key)
|
|
.or_insert_with(|| CodeIndex::default(code_index_tbl));
|
|
|
|
set_code_index::<LS>(
|
|
payload,
|
|
compilation_target,
|
|
key,
|
|
target_code_index,
|
|
src_code_ptr,
|
|
);
|
|
} else {
|
|
return Err(SessionError::ModuleDoesNotContainExport(
|
|
imported_module.module_decl.name,
|
|
(*name, *arity),
|
|
));
|
|
}
|
|
}
|
|
ModuleExport::OpDecl(op_decl) => {
|
|
add_op_decl_as_module_export::<LS>(payload, op_dir, wam_op_dir, op_decl);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn import_qualified_module_exports<'a, LS: LoadState<'a>>(
|
|
payload: &mut LS::LoaderFieldType,
|
|
compilation_target: &CompilationTarget,
|
|
imported_module: &Module,
|
|
exports: &IndexSet<ModuleExport>,
|
|
wam_prelude: &mut MachinePreludeView,
|
|
) -> Result<(), SessionError> {
|
|
for export in imported_module.module_decl.exports.iter() {
|
|
if !exports.contains(export) {
|
|
continue;
|
|
}
|
|
|
|
match export {
|
|
ModuleExport::PredicateKey((name, arity)) => {
|
|
let key = (*name, *arity);
|
|
|
|
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
|
|
wam_prelude
|
|
.indices
|
|
.meta_predicates
|
|
.insert(key, meta_specs.clone());
|
|
}
|
|
|
|
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
|
|
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
|
|
|
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
|
|
let target_code_index =
|
|
*wam_prelude.indices.code_dir.entry(key).or_insert_with(|| {
|
|
CodeIndex::new(IndexPtr::undefined(), code_index_tbl)
|
|
});
|
|
|
|
set_code_index::<LS>(
|
|
payload,
|
|
compilation_target,
|
|
key,
|
|
target_code_index,
|
|
src_code_ptr,
|
|
);
|
|
} else {
|
|
return Err(SessionError::ModuleDoesNotContainExport(
|
|
imported_module.module_decl.name,
|
|
(*name, *arity),
|
|
));
|
|
}
|
|
}
|
|
ModuleExport::OpDecl(op_decl) => {
|
|
add_op_decl(
|
|
&mut payload.retraction_info,
|
|
compilation_target,
|
|
&mut wam_prelude.indices.op_dir,
|
|
op_decl,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>(
|
|
payload: &mut LS::LoaderFieldType,
|
|
imported_module: &Module,
|
|
exports: &IndexSet<ModuleExport>,
|
|
code_dir: &mut CodeDir,
|
|
op_dir: &mut OpDir,
|
|
meta_predicates: &mut MetaPredicateDir,
|
|
wam_op_dir: &mut OpDir,
|
|
) -> Result<(), SessionError> {
|
|
let payload_compilation_target = payload.compilation_target;
|
|
|
|
for export in imported_module.module_decl.exports.iter() {
|
|
if !exports.contains(export) {
|
|
continue;
|
|
}
|
|
|
|
match export {
|
|
ModuleExport::PredicateKey((name, arity)) => {
|
|
let key = (*name, *arity);
|
|
|
|
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
|
|
meta_predicates.insert(key, meta_specs.clone());
|
|
}
|
|
|
|
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
|
|
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
|
|
|
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
|
|
let target_code_index = *code_dir
|
|
.entry(key)
|
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl));
|
|
|
|
set_code_index::<LS>(
|
|
payload,
|
|
&payload_compilation_target,
|
|
key,
|
|
target_code_index,
|
|
src_code_ptr,
|
|
);
|
|
} else {
|
|
return Err(SessionError::ModuleDoesNotContainExport(
|
|
imported_module.module_decl.name,
|
|
(*name, *arity),
|
|
));
|
|
}
|
|
}
|
|
ModuleExport::OpDecl(op_decl) => {
|
|
add_op_decl_as_module_export::<LS>(payload, op_dir, wam_op_dir, op_decl);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|
pub(super) fn retract_local_clauses_impl(
|
|
&mut self,
|
|
compilation_target: CompilationTarget,
|
|
key: PredicateKey,
|
|
clause_locs: &VecDeque<usize>,
|
|
) {
|
|
let result_opt = self
|
|
.wam_prelude
|
|
.indices
|
|
.get_predicate_skeleton_mut(&compilation_target, &key)
|
|
.map(|skeleton| {
|
|
(
|
|
clause_locs
|
|
.iter()
|
|
.map(|clause_clause_loc| {
|
|
skeleton.target_pos_of_clause_clause_loc(*clause_clause_loc)
|
|
})
|
|
.collect(),
|
|
skeleton.core.is_dynamic,
|
|
)
|
|
});
|
|
|
|
if let Some((clause_target_poses, is_dynamic)) = result_opt {
|
|
self.retract_local_clauses_by_locs(
|
|
compilation_target,
|
|
key,
|
|
clause_target_poses,
|
|
is_dynamic,
|
|
);
|
|
}
|
|
}
|
|
|
|
pub(super) fn retract_local_clauses_by_locs(
|
|
&mut self,
|
|
compilation_target: CompilationTarget,
|
|
key: PredicateKey,
|
|
mut clause_target_poses: Vec<Option<usize>>,
|
|
is_dynamic: bool,
|
|
) {
|
|
let old_compilation_target =
|
|
mem::replace(&mut self.payload.compilation_target, compilation_target);
|
|
|
|
while let Some(target_pos_opt) = clause_target_poses.pop() {
|
|
match target_pos_opt {
|
|
Some(target_pos) if is_dynamic => {
|
|
self.retract_dynamic_clause(key, target_pos);
|
|
}
|
|
Some(target_pos) => {
|
|
self.retract_clause(key, target_pos);
|
|
}
|
|
None => {
|
|
// Here because the clause was been removed
|
|
// earlier, e.g., by retract, without updating the
|
|
// local skeleton. In this case, do nothing.
|
|
}
|
|
}
|
|
}
|
|
|
|
self.payload.compilation_target = old_compilation_target;
|
|
}
|
|
|
|
pub(super) fn retract_local_clause_clauses(
|
|
&mut self,
|
|
clause_clause_compilation_target: CompilationTarget,
|
|
clause_locs: &VecDeque<usize>,
|
|
) {
|
|
let key = (atom!("$clause"), 2);
|
|
let listing_src_file_name = self.listing_src_file_name();
|
|
|
|
match self.wam_prelude.indices.get_local_predicate_skeleton_mut(
|
|
self.payload.compilation_target,
|
|
clause_clause_compilation_target,
|
|
listing_src_file_name,
|
|
key,
|
|
) {
|
|
Some(skeleton) => {
|
|
let payload_compilation_target = self.payload.compilation_target;
|
|
|
|
self.payload.retraction_info.push_record(
|
|
RetractionRecord::RemovedLocalSkeletonClauseLocations(
|
|
payload_compilation_target,
|
|
clause_clause_compilation_target,
|
|
key,
|
|
std::mem::take(&mut skeleton.clause_clause_locs),
|
|
),
|
|
);
|
|
|
|
skeleton.reset();
|
|
}
|
|
None => {
|
|
// The local skeleton might be removed when reloading
|
|
// or redefining a module, in which case no retraction
|
|
// record is necessary.
|
|
}
|
|
};
|
|
|
|
self.retract_local_clauses_impl(clause_clause_compilation_target, key, clause_locs);
|
|
}
|
|
|
|
#[inline]
|
|
pub(super) fn remove_module_op_exports(&mut self) {
|
|
for (mut op_decl, record) in self.payload.module_op_exports.drain(0..) {
|
|
op_decl.remove(&mut self.wam_prelude.indices.op_dir);
|
|
|
|
if let Some(op_desc) = record {
|
|
op_decl.op_desc = op_desc;
|
|
op_decl.insert_into_op_dir(&mut self.wam_prelude.indices.op_dir);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn remove_replaced_in_situ_module(&mut self, module_name: Atom) {
|
|
let mut removed_module = match self.wam_prelude.indices.modules.swap_remove(&module_name) {
|
|
Some(module) => module,
|
|
None => return,
|
|
};
|
|
|
|
let mut skipped_local_predicates = IndexSet::with_hasher(FxBuildHasher::default());
|
|
|
|
for ((local_compilation_target, key), skeleton) in
|
|
removed_module.local_extensible_predicates.iter()
|
|
{
|
|
skipped_local_predicates.insert(key);
|
|
|
|
if skeleton.is_multifile {
|
|
continue;
|
|
}
|
|
|
|
if let Some(code_index) = removed_module.code_dir.get_mut(key) {
|
|
if let Some(global_skeleton) = self
|
|
.wam_prelude
|
|
.indices
|
|
.get_predicate_skeleton(local_compilation_target, key)
|
|
{
|
|
let old_index_ptr = code_index.replace(
|
|
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
|
|
if global_skeleton.core.is_dynamic {
|
|
IndexPtr::dynamic_undefined()
|
|
} else {
|
|
IndexPtr::undefined()
|
|
},
|
|
);
|
|
|
|
self.payload.retraction_info.push_record(
|
|
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (key, code_index) in removed_module.code_dir.iter_mut() {
|
|
if skipped_local_predicates.contains(key) {
|
|
continue;
|
|
}
|
|
|
|
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
|
|
let code_ptr = code_index_tbl.get_entry((*code_index).into());
|
|
|
|
if !code_ptr.is_undefined() && !code_ptr.is_dynamic_undefined() {
|
|
let old_index_ptr = code_index.replace(code_index_tbl, IndexPtr::undefined());
|
|
|
|
self.payload.retraction_info.push_record(
|
|
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
|
|
);
|
|
}
|
|
}
|
|
|
|
for (key, skeleton) in removed_module.extensible_predicates.drain(..) {
|
|
self.payload
|
|
.retraction_info
|
|
.push_record(RetractionRecord::RemovedSkeleton(
|
|
CompilationTarget::Module(module_name),
|
|
key,
|
|
skeleton,
|
|
));
|
|
}
|
|
|
|
self.wam_prelude
|
|
.indices
|
|
.modules
|
|
.insert(module_name, removed_module);
|
|
}
|
|
|
|
pub(super) fn remove_module_exports(&mut self, module_name: Atom) {
|
|
let removed_module = match self.wam_prelude.indices.modules.swap_remove(&module_name) {
|
|
Some(module) => module,
|
|
None => return,
|
|
};
|
|
|
|
fn remove_module_exports<'b, LS: LoadState<'b>>(
|
|
payload: &mut <LS as LoadState<'b>>::LoaderFieldType,
|
|
removed_module: &Module,
|
|
code_dir: &mut CodeDir,
|
|
op_dir: &mut OpDir,
|
|
predicate_retractor: impl Fn(PredicateKey, IndexPtr) -> RetractionRecord,
|
|
op_retractor: impl Fn(OpDecl, OpDesc) -> RetractionRecord,
|
|
) {
|
|
for export in removed_module.module_decl.exports.iter() {
|
|
match export {
|
|
ModuleExport::PredicateKey(key) => {
|
|
if let (Some(module_code_idx), Some(target_code_idx)) = (
|
|
removed_module.code_dir.get(key).cloned(),
|
|
code_dir.get_mut(key).cloned(),
|
|
) {
|
|
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
|
|
let module_code_ptr = code_index_tbl.get_entry(module_code_idx.into());
|
|
let target_code_ptr = code_index_tbl.get_entry(target_code_idx.into());
|
|
|
|
if module_code_ptr == target_code_ptr {
|
|
let old_index_ptr =
|
|
target_code_idx.replace(code_index_tbl, IndexPtr::undefined());
|
|
payload
|
|
.retraction_info
|
|
.push_record(predicate_retractor(*key, old_index_ptr));
|
|
}
|
|
}
|
|
}
|
|
ModuleExport::OpDecl(op_decl) => {
|
|
let op_dir_value_opt = op_dir
|
|
.swap_remove(&(op_decl.name, op_decl.op_desc.get_spec().fixity()));
|
|
|
|
if let Some(op_desc) = op_dir_value_opt {
|
|
payload
|
|
.retraction_info
|
|
.push_record(op_retractor(*op_decl, op_desc));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
match self.payload.compilation_target {
|
|
CompilationTarget::User => {
|
|
remove_module_exports::<LS>(
|
|
&mut self.payload,
|
|
&removed_module,
|
|
&mut self.wam_prelude.indices.code_dir,
|
|
&mut self.wam_prelude.indices.op_dir,
|
|
RetractionRecord::ReplacedUserPredicate,
|
|
RetractionRecord::ReplacedUserOp,
|
|
);
|
|
}
|
|
CompilationTarget::Module(target_module_name) if target_module_name != module_name => {
|
|
let predicate_retractor = |key, index_ptr| {
|
|
RetractionRecord::ReplacedModulePredicate(module_name, key, index_ptr)
|
|
};
|
|
|
|
let op_retractor = |op_decl, op_desc| {
|
|
RetractionRecord::ReplacedModuleOp(module_name, op_decl, op_desc)
|
|
};
|
|
|
|
if let Some(module) = self
|
|
.wam_prelude
|
|
.indices
|
|
.modules
|
|
.get_mut(&target_module_name)
|
|
{
|
|
remove_module_exports::<LS>(
|
|
&mut self.payload,
|
|
&removed_module,
|
|
&mut module.code_dir,
|
|
&mut module.op_dir,
|
|
predicate_retractor,
|
|
op_retractor,
|
|
);
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
CompilationTarget::Module(_) => {}
|
|
};
|
|
|
|
self.wam_prelude
|
|
.indices
|
|
.modules
|
|
.insert(module_name, removed_module);
|
|
}
|
|
|
|
fn get_or_insert_local_code_index(
|
|
&mut self,
|
|
module_name: Atom,
|
|
key: PredicateKey,
|
|
) -> CodeIndex {
|
|
match self.wam_prelude.indices.modules.get_mut(&module_name) {
|
|
Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| {
|
|
CodeIndex::new(
|
|
IndexPtr::undefined(),
|
|
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
|
|
)
|
|
}),
|
|
None => {
|
|
self.add_dynamically_generated_module(module_name);
|
|
|
|
match self.wam_prelude.indices.modules.get_mut(&module_name) {
|
|
Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| {
|
|
CodeIndex::new(
|
|
IndexPtr::undefined(),
|
|
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
|
|
)
|
|
}),
|
|
None => {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn get_or_insert_code_index(
|
|
&mut self,
|
|
key: PredicateKey,
|
|
compilation_target: CompilationTarget,
|
|
) -> CodeIndex {
|
|
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
|
|
|
|
match compilation_target {
|
|
CompilationTarget::User => *self
|
|
.wam_prelude
|
|
.indices
|
|
.code_dir
|
|
.entry(key)
|
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl)),
|
|
CompilationTarget::Module(module_name) => {
|
|
self.get_or_insert_local_code_index(module_name, key)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn get_or_insert_qualified_code_index(
|
|
&mut self,
|
|
module_name: Atom,
|
|
key: PredicateKey,
|
|
) -> CodeIndex {
|
|
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
|
|
|
|
if module_name == atom!("user") {
|
|
*self
|
|
.wam_prelude
|
|
.indices
|
|
.code_dir
|
|
.entry(key)
|
|
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl))
|
|
} else {
|
|
self.get_or_insert_local_code_index(module_name, key)
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub(super) fn add_extensible_predicate(
|
|
&mut self,
|
|
key: PredicateKey,
|
|
skeleton: PredicateSkeleton,
|
|
compilation_target: CompilationTarget,
|
|
) {
|
|
match compilation_target {
|
|
CompilationTarget::User => {
|
|
self.wam_prelude
|
|
.indices
|
|
.extensible_predicates
|
|
.insert(key, skeleton);
|
|
|
|
let record =
|
|
RetractionRecord::AddedExtensiblePredicate(CompilationTarget::User, key);
|
|
|
|
self.payload.retraction_info.push_record(record);
|
|
}
|
|
CompilationTarget::Module(module_name) => {
|
|
if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) {
|
|
module.extensible_predicates.insert(key, skeleton);
|
|
|
|
let record = RetractionRecord::AddedExtensiblePredicate(
|
|
CompilationTarget::Module(module_name),
|
|
key,
|
|
);
|
|
|
|
self.payload.retraction_info.push_record(record);
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub(super) fn add_local_extensible_predicate(
|
|
&mut self,
|
|
local_compilation_target: CompilationTarget,
|
|
key: PredicateKey,
|
|
skeleton: LocalPredicateSkeleton,
|
|
) {
|
|
let src_compilation_target = match self.listing_src_file_name() {
|
|
Some(filename) => CompilationTarget::Module(filename),
|
|
None => self.payload.compilation_target,
|
|
};
|
|
|
|
match src_compilation_target {
|
|
CompilationTarget::User => {
|
|
self.wam_prelude
|
|
.indices
|
|
.local_extensible_predicates
|
|
.insert((local_compilation_target, key), skeleton);
|
|
}
|
|
CompilationTarget::Module(module_name) => {
|
|
if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) {
|
|
module
|
|
.local_extensible_predicates
|
|
.insert((local_compilation_target, key), skeleton);
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn add_op_decl(&mut self, op_decl: &OpDecl) {
|
|
let listing_src_file_name = self.listing_src_file_name();
|
|
let payload_compilation_target = self.payload.compilation_target;
|
|
|
|
match payload_compilation_target {
|
|
CompilationTarget::User => {
|
|
if let Some(filename) = listing_src_file_name {
|
|
if let Some(ref mut module) =
|
|
self.wam_prelude.indices.modules.get_mut(&filename)
|
|
{
|
|
op_decl.insert_into_op_dir(&mut module.op_dir);
|
|
}
|
|
}
|
|
|
|
add_op_decl(
|
|
&mut self.payload.retraction_info,
|
|
&payload_compilation_target,
|
|
&mut self.wam_prelude.indices.op_dir,
|
|
op_decl,
|
|
);
|
|
}
|
|
CompilationTarget::Module(ref module_name) => {
|
|
match self.wam_prelude.indices.modules.get_mut(module_name) {
|
|
Some(ref mut module) => {
|
|
add_op_decl_as_module_export::<LS>(
|
|
&mut self.payload,
|
|
&mut module.op_dir,
|
|
&mut self.wam_prelude.indices.op_dir,
|
|
op_decl,
|
|
);
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType {
|
|
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
|
|
|
match ClauseType::from(name, arity, arena) {
|
|
ClauseType::Named(arity, name, _) => {
|
|
let payload_compilation_target = self.payload.compilation_target;
|
|
|
|
let idx = self.get_or_insert_code_index((name, arity), payload_compilation_target);
|
|
|
|
ClauseType::Named(arity, name, idx)
|
|
}
|
|
ct => ct,
|
|
}
|
|
}
|
|
|
|
pub(super) fn get_qualified_clause_type(
|
|
&mut self,
|
|
module_name: Atom,
|
|
name: Atom,
|
|
arity: usize,
|
|
) -> ClauseType {
|
|
let arena = &mut LS::machine_st(&mut self.payload).arena;
|
|
|
|
match ClauseType::from(name, arity, arena) {
|
|
ClauseType::Named(arity, name, _) => {
|
|
let key = (name, arity);
|
|
let idx = self.get_or_insert_qualified_code_index(module_name, key);
|
|
|
|
ClauseType::Named(arity, name, idx)
|
|
}
|
|
ct => ct,
|
|
}
|
|
}
|
|
|
|
pub(super) fn get_meta_specs(&self, name: Atom, arity: usize) -> Option<&Vec<MetaSpec>> {
|
|
self.wam_prelude.indices.get_meta_predicate_spec(
|
|
name,
|
|
arity,
|
|
&self.payload.compilation_target,
|
|
)
|
|
}
|
|
|
|
pub(super) fn add_meta_predicate_record(
|
|
&mut self,
|
|
module_name: Atom,
|
|
name: Atom,
|
|
meta_specs: Vec<MetaSpec>,
|
|
) {
|
|
let arity = meta_specs.len();
|
|
let key = (name, arity);
|
|
|
|
match module_name {
|
|
atom!("user") => {
|
|
match self
|
|
.wam_prelude
|
|
.indices
|
|
.meta_predicates
|
|
.insert(key, meta_specs)
|
|
{
|
|
Some(old_meta_specs) => {
|
|
self.payload.retraction_info.push_record(
|
|
RetractionRecord::ReplacedMetaPredicate(
|
|
module_name,
|
|
key.0,
|
|
old_meta_specs,
|
|
),
|
|
);
|
|
}
|
|
None => {
|
|
self.payload
|
|
.retraction_info
|
|
.push_record(RetractionRecord::AddedMetaPredicate(module_name, key));
|
|
}
|
|
}
|
|
}
|
|
_ => match self.wam_prelude.indices.modules.get_mut(&module_name) {
|
|
Some(ref mut module) => match module.meta_predicates.insert(key, meta_specs) {
|
|
Some(old_meta_specs) => {
|
|
self.payload.retraction_info.push_record(
|
|
RetractionRecord::ReplacedMetaPredicate(
|
|
module_name,
|
|
key.0,
|
|
old_meta_specs,
|
|
),
|
|
);
|
|
}
|
|
None => {
|
|
self.payload
|
|
.retraction_info
|
|
.push_record(RetractionRecord::AddedMetaPredicate(module_name, key));
|
|
}
|
|
},
|
|
None => {
|
|
self.add_dynamically_generated_module(module_name);
|
|
|
|
if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) {
|
|
module.meta_predicates.insert(key, meta_specs);
|
|
} else {
|
|
unreachable!()
|
|
}
|
|
|
|
self.payload
|
|
.retraction_info
|
|
.push_record(RetractionRecord::AddedMetaPredicate(module_name, key));
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
pub(super) fn add_dynamically_generated_module(&mut self, module_name: Atom) {
|
|
let module_decl = ModuleDecl {
|
|
name: module_name,
|
|
exports: vec![],
|
|
};
|
|
|
|
let listing_src = ListingSource::DynamicallyGenerated;
|
|
let mut module = Module::new(module_decl, listing_src);
|
|
|
|
self.import_builtins_in_module(
|
|
module_name,
|
|
&mut module.code_dir,
|
|
&mut module.op_dir,
|
|
&mut module.meta_predicates,
|
|
);
|
|
|
|
self.payload
|
|
.retraction_info
|
|
.push_record(RetractionRecord::AddedModule(module_name));
|
|
|
|
self.wam_prelude.indices.modules.insert(module_name, module);
|
|
}
|
|
|
|
fn import_builtins_in_module(
|
|
&mut self,
|
|
module_name: Atom,
|
|
code_dir: &mut CodeDir,
|
|
op_dir: &mut OpDir,
|
|
meta_predicates: &mut MetaPredicateDir,
|
|
) {
|
|
if let Some(builtins) = self.wam_prelude.indices.modules.get(&atom!("builtins")) {
|
|
let module_compilation_target = CompilationTarget::Module(module_name);
|
|
|
|
if CompilationTarget::Module(atom!("builtins")) == self.payload.compilation_target {
|
|
return;
|
|
}
|
|
|
|
import_module_exports::<LS>(
|
|
&mut self.payload,
|
|
&module_compilation_target,
|
|
builtins,
|
|
code_dir,
|
|
op_dir,
|
|
meta_predicates,
|
|
)
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
pub(crate) fn reset_in_situ_module(
|
|
&mut self,
|
|
module_decl: ModuleDecl,
|
|
listing_src: &ListingSource,
|
|
) {
|
|
let module_name = module_decl.name;
|
|
|
|
self.remove_module_exports(module_name);
|
|
self.remove_replaced_in_situ_module(module_name);
|
|
|
|
if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) {
|
|
let old_module_decl = mem::replace(&mut module.module_decl, module_decl.clone());
|
|
|
|
let local_extensible_predicates = mem::replace(
|
|
&mut module.local_extensible_predicates,
|
|
LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()),
|
|
);
|
|
|
|
for ((compilation_target, key), skeleton) in local_extensible_predicates.iter() {
|
|
self.retract_local_clauses_impl(
|
|
*compilation_target,
|
|
*key,
|
|
&skeleton.clause_clause_locs,
|
|
);
|
|
|
|
let is_dynamic = self
|
|
.wam_prelude
|
|
.indices
|
|
.get_predicate_skeleton(compilation_target, key)
|
|
.map(|skeleton| skeleton.core.is_dynamic)
|
|
.unwrap_or(false);
|
|
|
|
if is_dynamic {
|
|
let clause_clause_compilation_target = match compilation_target {
|
|
CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
|
|
module => *module,
|
|
};
|
|
|
|
self.retract_local_clause_clauses(
|
|
clause_clause_compilation_target,
|
|
&skeleton.clause_clause_locs,
|
|
);
|
|
}
|
|
}
|
|
|
|
self.payload
|
|
.retraction_info
|
|
.push_record(RetractionRecord::ReplacedModule(
|
|
old_module_decl,
|
|
listing_src.clone(),
|
|
local_extensible_predicates,
|
|
));
|
|
}
|
|
}
|
|
|
|
pub(crate) fn add_module(
|
|
&mut self,
|
|
module_decl: ModuleDecl,
|
|
listing_src: ListingSource,
|
|
) -> Result<(), SessionError> {
|
|
let module_name = module_decl.name;
|
|
|
|
if let Some(module) = self.wam_prelude.indices.modules.get(&module_name) {
|
|
if let ListingSource::DynamicallyGenerated = module.listing_src {
|
|
} else {
|
|
LS::err_on_builtin_module_overwrite(module_name)?;
|
|
}
|
|
}
|
|
|
|
self.reset_in_situ_module(module_decl.clone(), &listing_src);
|
|
|
|
let mut module = match self.wam_prelude.indices.modules.swap_remove(&module_name) {
|
|
Some(mut module) => {
|
|
module.listing_src = listing_src;
|
|
module
|
|
}
|
|
None => {
|
|
self.payload
|
|
.retraction_info
|
|
.push_record(RetractionRecord::AddedModule(module_name));
|
|
|
|
Module::new(module_decl, listing_src)
|
|
}
|
|
};
|
|
|
|
self.import_builtins_in_module(
|
|
module_name,
|
|
&mut module.code_dir,
|
|
&mut module.op_dir,
|
|
&mut module.meta_predicates,
|
|
);
|
|
|
|
for export in &module.module_decl.exports {
|
|
if let ModuleExport::OpDecl(op_decl) = export {
|
|
add_op_decl_as_module_export::<LS>(
|
|
&mut self.payload,
|
|
&mut module.op_dir,
|
|
&mut self.wam_prelude.indices.op_dir,
|
|
op_decl,
|
|
);
|
|
}
|
|
}
|
|
|
|
if let Some(load_context) = self.wam_prelude.load_contexts.last_mut() {
|
|
load_context.module = module_name;
|
|
}
|
|
|
|
self.wam_prelude.indices.modules.insert(module_name, module);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub(super) fn import_module(&mut self, module_name: Atom) -> Result<(), SessionError> {
|
|
if let Some(module) = self.wam_prelude.indices.modules.swap_remove(&module_name) {
|
|
let payload_compilation_target = self.payload.compilation_target;
|
|
|
|
match &payload_compilation_target {
|
|
CompilationTarget::User => {
|
|
import_module_exports::<LS>(
|
|
&mut self.payload,
|
|
&payload_compilation_target,
|
|
&module,
|
|
&mut self.wam_prelude.indices.code_dir,
|
|
&mut self.wam_prelude.indices.op_dir,
|
|
&mut self.wam_prelude.indices.meta_predicates,
|
|
)?;
|
|
}
|
|
CompilationTarget::Module(defining_module_name) => {
|
|
match self
|
|
.wam_prelude
|
|
.indices
|
|
.modules
|
|
.get_mut(defining_module_name)
|
|
{
|
|
Some(ref mut target_module) => {
|
|
import_module_exports_into_module::<LS>(
|
|
&mut self.payload,
|
|
&payload_compilation_target,
|
|
&module,
|
|
&mut target_module.code_dir,
|
|
&mut target_module.op_dir,
|
|
&mut target_module.meta_predicates,
|
|
&mut self.wam_prelude.indices.op_dir,
|
|
)?;
|
|
}
|
|
None => {
|
|
// we find ourselves here because we're trying to import
|
|
// a module into itself as it is being defined.
|
|
self.wam_prelude.indices.modules.insert(module_name, module);
|
|
return Err(SessionError::ModuleCannotImportSelf(module_name));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
self.wam_prelude.indices.modules.insert(module_name, module);
|
|
Ok(())
|
|
} else {
|
|
Err(SessionError::ExistenceError(ExistenceError::Module(
|
|
module_name,
|
|
)))
|
|
}
|
|
}
|
|
|
|
pub(super) fn import_qualified_module(
|
|
&mut self,
|
|
module_name: Atom,
|
|
exports: IndexSet<ModuleExport>,
|
|
) -> Result<(), SessionError> {
|
|
if let Some(module) = self.wam_prelude.indices.modules.swap_remove(&module_name) {
|
|
let payload_compilation_target = self.payload.compilation_target;
|
|
|
|
let result = match &payload_compilation_target {
|
|
CompilationTarget::User => import_qualified_module_exports::<LS>(
|
|
&mut self.payload,
|
|
&payload_compilation_target,
|
|
&module,
|
|
&exports,
|
|
&mut self.wam_prelude,
|
|
),
|
|
CompilationTarget::Module(defining_module_name) => {
|
|
match self
|
|
.wam_prelude
|
|
.indices
|
|
.modules
|
|
.get_mut(defining_module_name)
|
|
{
|
|
Some(ref mut target_module) => {
|
|
import_qualified_module_exports_into_module::<LS>(
|
|
&mut self.payload,
|
|
&module,
|
|
&exports,
|
|
&mut target_module.code_dir,
|
|
&mut target_module.op_dir,
|
|
&mut target_module.meta_predicates,
|
|
&mut self.wam_prelude.indices.op_dir,
|
|
)
|
|
}
|
|
None => Err(SessionError::ModuleCannotImportSelf(module_name)),
|
|
}
|
|
}
|
|
};
|
|
|
|
self.wam_prelude.indices.modules.insert(module_name, module);
|
|
result
|
|
} else {
|
|
Err(SessionError::ExistenceError(ExistenceError::Module(
|
|
module_name,
|
|
)))
|
|
}
|
|
}
|
|
|
|
pub(crate) fn use_module(&mut self, module_src: ModuleSource) -> Result<(), SessionError> {
|
|
let (stream, listing_src) = match module_src {
|
|
ModuleSource::File(filename) => {
|
|
let mut path_buf = PathBuf::from(&*filename.as_str());
|
|
path_buf.set_extension("pl");
|
|
|
|
let file = File::open(&path_buf)?;
|
|
|
|
(
|
|
Stream::from_file_as_input(
|
|
filename,
|
|
file,
|
|
&mut LS::machine_st(&mut self.payload).arena,
|
|
),
|
|
ListingSource::File(filename, path_buf),
|
|
)
|
|
}
|
|
ModuleSource::Library(library) => match libraries::get(&library.as_str()) {
|
|
Some(code) => {
|
|
if let Some(module) = self.wam_prelude.indices.modules.get(&library) {
|
|
if let ListingSource::DynamicallyGenerated = &module.listing_src {
|
|
(
|
|
Stream::from_static_string(
|
|
code,
|
|
&mut LS::machine_st(&mut self.payload).arena,
|
|
),
|
|
ListingSource::User,
|
|
)
|
|
} else {
|
|
return self.import_module(library);
|
|
}
|
|
} else {
|
|
(
|
|
Stream::from_static_string(
|
|
code,
|
|
&mut LS::machine_st(&mut self.payload).arena,
|
|
),
|
|
ListingSource::User,
|
|
)
|
|
}
|
|
}
|
|
None => {
|
|
return self.import_module(library);
|
|
}
|
|
},
|
|
};
|
|
|
|
let compilation_target = {
|
|
let term_stream = BootstrappingTermStream::from_char_reader(
|
|
stream,
|
|
LS::machine_st(&mut self.payload),
|
|
listing_src,
|
|
);
|
|
|
|
let subloader: Loader<'_, BootstrappingLoadState> = Loader {
|
|
payload: BootstrappingLoadState(LoadStatePayload::new(
|
|
self.wam_prelude.code.len(),
|
|
term_stream,
|
|
)),
|
|
wam_prelude: MachinePreludeView {
|
|
indices: self.wam_prelude.indices,
|
|
code: self.wam_prelude.code,
|
|
load_contexts: self.wam_prelude.load_contexts,
|
|
},
|
|
};
|
|
|
|
subloader.load()?
|
|
};
|
|
|
|
match compilation_target {
|
|
CompilationTarget::User => {
|
|
// nothing to do.
|
|
Ok(())
|
|
}
|
|
CompilationTarget::Module(module_name) => self.import_module(module_name),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn use_qualified_module(
|
|
&mut self,
|
|
module_src: ModuleSource,
|
|
exports: IndexSet<ModuleExport>,
|
|
) -> Result<(), SessionError> {
|
|
let (stream, listing_src) = match module_src {
|
|
ModuleSource::File(filename) => {
|
|
let mut path_buf = PathBuf::from(&*filename.as_str());
|
|
path_buf.set_extension("pl");
|
|
let file = File::open(&path_buf)?;
|
|
|
|
(
|
|
Stream::from_file_as_input(
|
|
filename,
|
|
file,
|
|
&mut LS::machine_st(&mut self.payload).arena,
|
|
),
|
|
ListingSource::File(filename, path_buf),
|
|
)
|
|
}
|
|
ModuleSource::Library(library) => match libraries::get(&library.as_str()) {
|
|
Some(code) => {
|
|
if self.wam_prelude.indices.modules.contains_key(&library) {
|
|
return self.import_qualified_module(library, exports);
|
|
} else {
|
|
(
|
|
Stream::from_static_string(
|
|
code,
|
|
&mut LS::machine_st(&mut self.payload).arena,
|
|
),
|
|
ListingSource::User,
|
|
)
|
|
}
|
|
}
|
|
None => {
|
|
return self.import_qualified_module(library, exports);
|
|
}
|
|
},
|
|
};
|
|
|
|
let compilation_target = {
|
|
let term_stream = BootstrappingTermStream::from_char_reader(
|
|
stream,
|
|
LS::machine_st(&mut self.payload),
|
|
listing_src,
|
|
);
|
|
|
|
let subloader: Loader<'_, BootstrappingLoadState> = Loader {
|
|
payload: BootstrappingLoadState(LoadStatePayload::new(
|
|
self.wam_prelude.code.len(),
|
|
term_stream,
|
|
)),
|
|
wam_prelude: MachinePreludeView {
|
|
indices: self.wam_prelude.indices,
|
|
code: self.wam_prelude.code,
|
|
load_contexts: self.wam_prelude.load_contexts,
|
|
},
|
|
};
|
|
|
|
subloader.load()?
|
|
};
|
|
|
|
match compilation_target {
|
|
CompilationTarget::User => {
|
|
// nothing to do.
|
|
Ok(())
|
|
}
|
|
CompilationTarget::Module(module_name) => {
|
|
self.import_qualified_module(module_name, exports)
|
|
}
|
|
}
|
|
}
|
|
}
|