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)>; pub(super) fn set_code_index<'a, LS: LoadState<'a>>( payload: &mut >::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(ref 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(ref 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(ref 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::( 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(ref 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::( payload, compilation_target, key, target_code_index, src_code_ptr, ); } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name, (*name, *arity), )); } } ModuleExport::OpDecl(ref op_decl) => { add_op_decl_as_module_export::(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, 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::( payload, compilation_target, key, target_code_index, src_code_ptr, ); } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name, (*name, *arity), )); } } ModuleExport::OpDecl(ref 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, 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::( 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(ref op_decl) => { add_op_decl_as_module_export::(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, ) { 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>, 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, ) { 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 >::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(ref 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::( &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::( &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::( &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> { 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, ) { 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::( &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(ref op_decl) = export { add_op_decl_as_module_export::( &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::( &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(ref defining_module_name) => { match self .wam_prelude .indices .modules .get_mut(defining_module_name) { Some(ref mut target_module) => { import_module_exports_into_module::( &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, ) -> 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::( &mut self.payload, &payload_compilation_target, &module, &exports, &mut self.wam_prelude, ), CompilationTarget::Module(ref 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::( &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, ) -> 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) } } } }