use crate::forms::*; use crate::machine::loader::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::preprocessor::*; use crate::machine::term_stream::*; use crate::machine::*; use crate::parser::ast::*; use fxhash::FxBuildHasher; use indexmap::IndexSet; use ref_thread_local::RefThreadLocal; use std::collections::VecDeque; use std::fs::File; use std::mem; pub(super) type ModuleOpExports = Vec<(OpDecl, Option)>; pub(super) fn set_code_index( retraction_info: &mut RetractionInfo, compilation_target: &CompilationTarget, key: PredicateKey, mut code_index: CodeIndex, code_ptr: IndexPtr, ) { let record = match compilation_target { CompilationTarget::User => { if IndexPtrTag::Undefined == code_index.get().tag() { code_index.set(code_ptr); RetractionRecord::AddedUserPredicate(key) } else { let replaced = code_index.replace(code_ptr); RetractionRecord::ReplacedUserPredicate(key, replaced) } } CompilationTarget::Module(ref module_name) => { if IndexPtrTag::Undefined == code_index.get().tag() { code_index.set(code_ptr); RetractionRecord::AddedModulePredicate(*module_name, key) } else { let replaced = code_index.replace(code_ptr); RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced) } } }; 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 arena = &mut LS::machine_st(payload).arena; let target_code_index = code_dir .entry(key) .or_insert_with(|| CodeIndex::default(arena)) .clone(); set_code_index( &mut payload.retraction_info, compilation_target, key, target_code_index, src_code_index.get(), ); if src_code_index.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.clone(), meta_specs.clone()); } if let Some(src_code_index) = imported_module.code_dir.get(&key) { let arena = &mut LS::machine_st(payload).arena; let target_code_index = code_dir .entry(key) .or_insert_with(|| CodeIndex::default(arena)) .clone(); set_code_index( &mut payload.retraction_info, compilation_target, key, target_code_index, src_code_index.get(), ); } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name.clone(), (*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.clone(), meta_specs.clone()); } if let Some(src_code_index) = imported_module.code_dir.get(&key) { let arena = &mut LS::machine_st(payload).arena; let target_code_index = wam_prelude.indices.code_dir .entry(key.clone()) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)) .clone(); set_code_index( &mut payload.retraction_info, compilation_target, key, target_code_index, src_code_index.get(), ); } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name.clone(), (*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) { let arena = &mut LS::machine_st(payload).arena; let target_code_index = code_dir .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)) .clone(); set_code_index( &mut payload.retraction_info, &payload_compilation_target, key, target_code_index, src_code_index.get(), ); } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name.clone(), (*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, mem::replace(&mut skeleton.clause_clause_locs, VecDeque::new()), ), ); 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); } pub(super) fn try_term_to_tl( &mut self, term: Term, preprocessor: &mut Preprocessor, ) -> Result { let tl = preprocessor.try_term_to_tl(self, term)?; Ok(match tl { TopLevel::Fact(fact, var_data) => PredicateClause::Fact(fact, var_data), TopLevel::Rule(rule, var_data) => PredicateClause::Rule(rule, var_data), }) } #[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.remove(&module_name) { Some(module) => module, None => return, }; for (key, code_index) in removed_module.code_dir.iter_mut() { match removed_module .local_extensible_predicates .get(&(CompilationTarget::User, *key)) { Some(skeleton) if skeleton.is_multifile => continue, _ => {} } let old_index_ptr = code_index.replace(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.remove(&module_name) { Some(module) => module, None => return, }; fn remove_module_exports( removed_module: &Module, code_dir: &mut CodeDir, op_dir: &mut OpDir, retraction_info: &mut RetractionInfo, 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) => { match (removed_module.code_dir.get(key), code_dir.get_mut(key)) { (Some(module_code_index), Some(target_code_index)) if module_code_index.get() == target_code_index.get() => { let old_index_ptr = target_code_index.replace(IndexPtr::undefined()); retraction_info.push_record(predicate_retractor(*key, old_index_ptr)); } _ => {} } } ModuleExport::OpDecl(op_decl) => { let op_dir_value_opt = op_dir.remove(&(op_decl.name, fixity(op_decl.op_desc.get_spec() as u32))); if let Some(op_desc) = op_dir_value_opt { retraction_info.push_record(op_retractor(*op_decl, op_desc)); } } } } } match self.payload.compilation_target { CompilationTarget::User => { remove_module_exports( &removed_module, &mut self.wam_prelude.indices.code_dir, &mut self.wam_prelude.indices.op_dir, &mut self.payload.retraction_info, 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( &removed_module, &mut module.code_dir, &mut module.op_dir, &mut self.payload.retraction_info, 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, )) .clone(), 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, )) .clone(), None => { unreachable!() } } } } } pub(super) fn get_or_insert_code_index( &mut self, key: PredicateKey, compilation_target: CompilationTarget, ) -> CodeIndex { let arena = &mut LS::machine_st(&mut self.payload).arena; match compilation_target { CompilationTarget::User => self .wam_prelude .indices .code_dir .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)) .clone(), 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 arena = &mut LS::machine_st(&mut self.payload).arena; if module_name == atom!("user") { return self .wam_prelude .indices .code_dir .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)) .clone(); } 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.clone(), 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 { match self.wam_prelude.indices.modules.get_mut(&filename) { Some(ref mut module) => { op_decl.insert_into_op_dir(&mut module.op_dir); } None => {} } } 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.clone(), 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.clone(), meta_specs); } else { unreachable!() } self.payload.retraction_info .push_record(RetractionRecord::AddedMetaPredicate( module_name.clone(), key, )); } } } } } pub(super) fn add_dynamically_generated_module(&mut self, module_name: Atom) { let module_decl = ModuleDecl { name: module_name.clone(), 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.clone())); self.wam_prelude.indices.modules.insert(module_name.clone(), 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); match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(module) => { 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.clone(), }; 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, )); } None => {} } } pub(crate) fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) { self.reset_in_situ_module(module_decl.clone(), &listing_src); let module_name = module_decl.name; let mut module = match self.wam_prelude.indices.modules.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); } pub(super) fn import_module(&mut self, module_name: Atom) -> Result<(), SessionError> { if let Some(module) = self.wam_prelude.indices.modules.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.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.borrow().get(library.as_str()) { Some(code) => { if let Some(ref 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.borrow().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) } } } }