From: Mark Thom Date: Wed, 17 Feb 2021 03:54:51 +0000 (-0700) Subject: support discontiguous and multifile declarations X-Git-Tag: v0.9.0~150^2~50 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=6b6666be47e3b6f9b30fea2567e7e4da489f7b92;p=scryer-prolog.git support discontiguous and multifile declarations --- diff --git a/src/clause_types.rs b/src/clause_types.rs index 33294fa4..660a74a8 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -340,9 +340,15 @@ impl SystemClauseType { &SystemClauseType::WorkingDirectory => clause_name!("$working_directory"), &SystemClauseType::PathCanonical => clause_name!("$path_canonical"), &SystemClauseType::FileTime => clause_name!("$file_time"), + &SystemClauseType::REPL(REPLCodePtr::AddDiscontiguousPredicate) => { + clause_name!("$add_discontiguous_predicate") + } &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => { clause_name!("$add_dynamic_predicate") } + &SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate) => { + clause_name!("$add_multifile_predicate") + } &SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) => { clause_name!("$add_goal_expansion_clause") } @@ -582,9 +588,15 @@ impl SystemClauseType { pub fn from(name: &str, arity: usize) -> Option { match (name, arity) { ("$abolish_clause", 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)), - ("$add_dynamic_predicate", 3) => { + ("$add_dynamic_predicate", 4) => { Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate)) } + ("$add_multifile_predicate", 4) => { + Some(SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate)) + } + ("$add_discontiguous_predicate", 4) => { + Some(SystemClauseType::REPL(REPLCodePtr::AddDiscontiguousPredicate)) + } ("$add_goal_expansion_clause", 4) => { Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause)) } diff --git a/src/forms.rs b/src/forms.rs index fc63e7e5..ad401cd4 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -28,7 +28,6 @@ pub type JumpStub = Vec; #[derive(Debug, Clone)] pub enum TopLevel { - Declaration(Declaration), Fact(Term), // Term, line_num, col_num Predicate(Predicate), Query(Vec), @@ -117,7 +116,7 @@ impl ListingSource { pub trait ClauseInfo { fn is_consistent(&self, clauses: &PredicateQueue) -> bool { match clauses.first() { - Some(cl) => self.name() == cl.name() && self.arity() == cl.arity(), + Some(cl) => self.name() == ClauseInfo::name(cl) && self.arity() == ClauseInfo::arity(cl), None => true, } } @@ -212,33 +211,6 @@ impl PredicateClause { } } } - - pub fn arity(&self) -> usize { - match self { - &PredicateClause::Fact(ref term, ..) => term.arity(), - &PredicateClause::Rule(ref rule, ..) => { - if rule.head.0.as_str() == ":" && rule.head.1.len() == 2 { - match (rule.head.1)[0].as_ref() { - &Term::Constant(_, Constant::Atom(..)) => {} - _ => { - return 2; - } - } - - (rule.head.1)[1].arity() - } else { - rule.head.1.len() - } - } - } - } - - pub fn name(&self) -> Option { - match self { - &PredicateClause::Fact(ref term, ..) => term.name(), - &PredicateClause::Rule(ref rule, ..) => Some(rule.head.0.clone()), - } - } } #[derive(Debug, Clone)] @@ -447,7 +419,6 @@ pub struct Module { pub local_extensible_predicates: LocalExtensiblePredicates, pub is_impromptu_module: bool, pub listing_src: ListingSource, - pub clause_assert_margin: usize, } // Module's and related types are defined in forms. @@ -462,7 +433,6 @@ impl Module { extensible_predicates: ExtensiblePredicates::new(), local_extensible_predicates: LocalExtensiblePredicates::new(), listing_src, - clause_assert_margin: 0, } } } @@ -643,7 +613,7 @@ impl AddAssign for OptArgIndexKey { } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct ClauseIndexInfo { pub clause_start: usize, pub opt_arg_index_key: OptArgIndexKey, @@ -660,6 +630,41 @@ impl ClauseIndexInfo { } } +#[derive(Clone, Copy, Debug)] +pub struct PredicateInfo { + pub is_extensible: bool, + pub is_discontiguous: bool, + pub is_dynamic: bool, + pub is_multifile: bool, + pub has_clauses: bool, +} + +impl Default for PredicateInfo { + #[inline] + fn default() -> Self { + PredicateInfo { + is_extensible: false, + is_discontiguous: false, + is_dynamic: false, + is_multifile: false, + has_clauses: false, + } + } +} + +impl PredicateInfo { + #[inline] + pub fn compile_incrementally(&self) -> bool { + let base = self.is_extensible && self.has_clauses; + base && (self.is_discontiguous || self.is_multifile) + } + + #[inline] + pub fn must_retract_local_clauses(&self) -> bool { + self.is_extensible && !self.is_discontiguous + } +} + #[derive(Debug)] pub struct PredicateSkeleton { pub is_discontiguous: bool, @@ -667,6 +672,7 @@ pub struct PredicateSkeleton { pub is_multifile: bool, pub clauses: SliceDeque, pub clause_clause_locs: SliceDeque, + pub clause_assert_margin: usize, } impl PredicateSkeleton { @@ -678,57 +684,41 @@ impl PredicateSkeleton { is_multifile: false, clauses: sdeq![], clause_clause_locs: sdeq![], + clause_assert_margin: 0, } } - /* - #[inline] - pub fn set_discontiguous(self, is_discontiguous: bool) -> Self { - PredicateSkeleton { - is_discontiguous, - is_dynamic: self.is_dynamic, - is_multifile: self.is_multifile, - clauses: self.clauses, - } - } - */ - #[inline] - pub fn set_dynamic(self, is_dynamic: bool) -> Self { - PredicateSkeleton { + pub fn predicate_info(&self) -> PredicateInfo { + PredicateInfo { + is_extensible: true, is_discontiguous: self.is_discontiguous, - is_dynamic, + is_dynamic: self.is_dynamic, is_multifile: self.is_multifile, - clauses: self.clauses, - clause_clause_locs: self.clause_clause_locs, + has_clauses: !self.clauses.is_empty(), } } - /* #[inline] - pub fn set_multifile(self, is_multifile: bool) -> Self { - PredicateSkeleton { - is_discontiguous: self.is_discontiguous, - is_dynamic: self.is_dynamic, - is_multifile, - clauses: self.clauses, - } + pub fn reset(&mut self) { + self.clauses.clear(); + self.clause_clause_locs.clear(); + self.clause_assert_margin = 0; } - */ pub fn target_pos_of_clause_clause_loc( &self, clause_clause_loc: usize, - clause_assert_margin: usize, - ) -> usize { - let search_result = self.clause_clause_locs[0..clause_assert_margin] + ) -> Option { + let search_result = self.clause_clause_locs[0..self.clause_assert_margin] .binary_search_by(|loc| clause_clause_loc.cmp(&loc)); - search_result.unwrap_or_else(|_| { - self.clause_clause_locs[clause_assert_margin..] + match search_result { + Ok(loc) => Some(loc), + Err(_) => self.clause_clause_locs[self.clause_assert_margin..] .binary_search_by(|loc| loc.cmp(&clause_clause_loc)) - .unwrap() - + clause_assert_margin - }) + .map(|loc| loc + self.clause_assert_margin) + .ok() + } } } diff --git a/src/loader.pl b/src/loader.pl index 475bb4b7..548d0e46 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -257,9 +257,38 @@ compile_declaration(module(Module, Exports), Evacuable) :- type_error(atom, Module, load/1) ). compile_declaration(dynamic(Name/Arity), Evacuable) :- + !, + must_be(atom, Name), + must_be(integer, Arity), + prolog_load_context(module, Module), + '$add_dynamic_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(dynamic(Module:Name/Arity), Evacuable) :- + must_be(atom, Module), + must_be(atom, Name), + must_be(integer, Arity), + '$add_dynamic_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(multifile(Name/Arity), Evacuable) :- + !, + must_be(atom, Name), + must_be(integer, Arity), + prolog_load_context(module, Module), + '$add_multifile_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(multifile(Module:Name/Arity), Evacuable) :- + must_be(atom, Module), + must_be(atom, Name), + must_be(integer, Arity), + '$add_multifile_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(discontiguous(Name/Arity), Evacuable) :- + !, + must_be(atom, Name), + must_be(integer, Arity), + prolog_load_context(module, Module), + '$add_discontiguous_predicate'(Module, Name, Arity, Evacuable). +compile_declaration(discontiguous(Module:Name/Arity), Evacuable) :- + must_be(atom, Module), must_be(atom, Name), must_be(integer, Arity), - '$add_dynamic_predicate'(Name, Arity, Evacuable). + '$add_discontiguous_predicate'(Module, Name, Arity, Evacuable). compile_declaration(initialization(Goal), Evacuable) :- prolog_load_context(module, Module), assertz(Module:'$initialization_goals'(Goal)). @@ -388,7 +417,7 @@ check_predicate_property(dynamic, Module, Name, Arity, dynamic) :- '$cpp_dynamic_property'(Module, Name, Arity). check_predicate_property(multifile, Module, Name, Arity, multifile) :- '$cpp_multifile_property'(Module, Name, Arity). -check_predicate_property(discontiguous, Module, Name, Arity, multifile) :- +check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :- '$cpp_discontiguous_property'(Module, Name, Arity). @@ -408,7 +437,7 @@ load_context(Module) :- predicate_property(Callable, Property) :- ( var(Callable) -> instantiation_error(load/1) - ; functor(Callable, (:), 2), % Callable =.. [(:), Module, Callable0], + ; functor(Callable, (:), 2), arg(1, Callable, Module), arg(2, Callable, Callable0), atom(Module) -> diff --git a/src/machine/compile.rs b/src/machine/compile.rs index e75259a6..3c7f9eb8 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -3,9 +3,9 @@ use prolog_parser::clause_name; use crate::codegen::*; use crate::debray_allocator::*; use crate::indexing::{merge_clause_index, remove_index}; -use crate::machine::load_state::set_code_index; -use crate::machine::load_state::LoadState; +use crate::machine::load_state::*; use crate::machine::loader::*; +use crate::machine::preprocessor::*; use crate::machine::term_stream::*; use crate::machine::*; @@ -45,7 +45,7 @@ pub(super) fn compile_relation( tl: &TopLevel, ) -> Result { match tl { - &TopLevel::Declaration(_) | &TopLevel::Query(_) => Err(CompilationError::ExpectedRel), + &TopLevel::Query(_) => Err(CompilationError::ExpectedRel), &TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses), &TopLevel::Fact(ref fact, ..) => Ok(cg.compile_fact(fact)), &TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule), @@ -54,16 +54,15 @@ pub(super) fn compile_relation( pub(super) fn compile_appendix( code: &mut Code, - queue: &VecDeque, + mut queue: VecDeque, jmp_by_locs: Vec, non_counted_bt: bool, atom_tbl: TabledData, ) -> Result<(), CompilationError> { let mut jmp_by_locs = VecDeque::from(jmp_by_locs); - for tl in queue.iter() { + while let Some(jmp_by_offset) = jmp_by_locs.pop_front() { let code_len = code.len(); - let jmp_by_offset = jmp_by_locs.pop_front().unwrap(); match &mut code[jmp_by_offset] { &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) => { @@ -76,9 +75,10 @@ pub(super) fn compile_appendix( // false because the inner predicate is a one-off, hence not extensible. let settings = CodeGenSettings::new(false, non_counted_bt); - let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); - let decl_code = compile_relation(&mut cg, tl)?; + + let tl = queue.pop_front().unwrap(); + let decl_code = compile_relation(&mut cg, &tl)?; jmp_by_locs.extend(cg.jmp_by_locs.into_iter().map(|offset| offset + code.len())); code.extend(decl_code.into_iter()); @@ -109,29 +109,6 @@ fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) 0 } -fn compile_standalone_clause( - clause: PredicateClause, - queue: VecDeque, - settings: CodeGenSettings, - atom_tbl: TabledData, -) -> Result { - let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); - let mut clause_code = cg.compile_predicate(&vec![clause])?; - - compile_appendix( - &mut clause_code, - &queue, - cg.jmp_by_locs, - settings.non_counted_bt, - atom_tbl, - )?; - - Ok(StandaloneCompileResult { - clause_code, - standalone_skeleton: cg.skeleton, - }) -} - fn derelictize_try_me_else( code: &mut Code, index: usize, @@ -341,17 +318,21 @@ fn merge_indexed_subsequences( None } -fn delete_from_dynamic_skeleton( +fn delete_from_skeleton( compilation_target: CompilationTarget, key: PredicateKey, skeleton: &mut PredicateSkeleton, target_pos: usize, retraction_info: &mut RetractionInfo, ) -> usize { - let clause_clause_loc = skeleton.clause_clause_locs.remove(target_pos); let clause_index_info = skeleton.clauses.remove(target_pos); + let clause_clause_loc = skeleton.clause_clause_locs.remove(target_pos); + + if target_pos < skeleton.clause_assert_margin { + skeleton.clause_assert_margin -= 1; + } - retraction_info.push_record(RetractionRecord::RemovedDynamicSkeletonClause( + retraction_info.push_record(RetractionRecord::RemovedSkeletonClause( compilation_target, key, target_pos, @@ -585,7 +566,7 @@ fn finalize_retract( index_ptr_opt: Option, retraction_info: &mut RetractionInfo, ) -> usize { - let clause_clause_loc = delete_from_dynamic_skeleton( + let clause_clause_loc = delete_from_skeleton( compilation_target.clone(), key.clone(), skeleton, @@ -1007,13 +988,40 @@ fn mergeable_indexed_subsequences( } impl<'a> LoadState<'a> { + fn compile_standalone_clause( + &mut self, + term: Term, + settings: CodeGenSettings, + atom_tbl: TabledData, + ) -> Result { + let mut preprocessor = Preprocessor::new(self.wam.machine_st.flags); + let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); + + let clause = self.try_term_to_tl(term, &mut preprocessor)?; + let queue = preprocessor.parse_queue(self)?; + + let mut clause_code = cg.compile_predicate(&vec![clause])?; + + compile_appendix( + &mut clause_code, + queue, + cg.jmp_by_locs, + settings.non_counted_bt, + atom_tbl, + )?; + + Ok(StandaloneCompileResult { + clause_code, + standalone_skeleton: cg.skeleton, + }) + } + fn compile( &mut self, key: PredicateKey, - predicates: &PredicateQueue, // &Vec, - queue: &VecDeque, + predicates: &mut PredicateQueue, settings: CodeGenSettings, - ) -> Result { + ) -> Result<(), SessionError> { let code_index = self.get_or_insert_code_index( key.clone(), predicates.compilation_target.clone(), @@ -1025,7 +1033,15 @@ impl<'a> LoadState<'a> { let mut cg = CodeGenerator::::new(self.wam.machine_st.atom_tbl.clone(), settings); - let mut code = cg.compile_predicate(&predicates.predicates)?; + let mut clauses = vec![]; + let mut preprocessor = Preprocessor::new(self.wam.machine_st.flags); + + for term in predicates.predicates.drain(0 ..) { + clauses.push(self.try_term_to_tl(term, &mut preprocessor)?); + } + + let queue = preprocessor.parse_queue(self)?; + let mut code = cg.compile_predicate(&clauses)?; compile_appendix( &mut code, @@ -1036,9 +1052,13 @@ impl<'a> LoadState<'a> { )?; if settings.is_extensible { + let mut clause_clause_locs = sdeq![]; + for clause_index_info in cg.skeleton.clauses.iter_mut() { clause_index_info.clause_start += code_len; clause_index_info.opt_arg_index_key += code_len; + + clause_clause_locs.push_back(clause_index_info.clause_start); } match &mut code[0] { @@ -1062,8 +1082,15 @@ impl<'a> LoadState<'a> { )); skeleton.clauses.extend(cg.skeleton.clauses.into_iter()); + skeleton.clause_clause_locs.extend_from_slice( + &clause_clause_locs[0 ..] + ); } None => { + cg.skeleton.clause_clause_locs.extend_from_slice( + &clause_clause_locs[0 ..] + ); + self.add_extensible_predicate( key.clone(), cg.skeleton, @@ -1071,6 +1098,15 @@ impl<'a> LoadState<'a> { ); } } + + let mut skeleton = PredicateSkeleton::new(); + skeleton.clause_clause_locs = clause_clause_locs; + + self.add_local_extensible_predicate( + predicates.compilation_target.clone(), + key.clone(), + skeleton, + ); } set_code_index( @@ -1082,7 +1118,7 @@ impl<'a> LoadState<'a> { ); self.wam.code_repo.code.extend(code.into_iter()); - Ok(code_index.get()) + Ok(()) } fn record_incremental_compile( @@ -1119,24 +1155,23 @@ impl<'a> LoadState<'a> { pub(super) fn incremental_compile_clause( &mut self, key: PredicateKey, - clause: PredicateClause, - queue: VecDeque, + clause: Term, compilation_target: CompilationTarget, non_counted_bt: bool, append_or_prepend: AppendOrPrepend, - ) -> Result { + ) -> Result<(), SessionError> { self.record_incremental_compile( key.clone(), compilation_target.clone(), append_or_prepend, ); - let skeleton = match self + match self .wam .indices .get_predicate_skeleton_mut(&compilation_target, &key) { - Some(skeleton) if !skeleton.clauses.is_empty() => skeleton, + Some(skeleton) if !skeleton.clauses.is_empty() => {}, _ => { // true because this predicate is extensible. let settings = CodeGenSettings::new(true, non_counted_bt); @@ -1144,7 +1179,7 @@ impl<'a> LoadState<'a> { let mut predicate_queue = predicate_queue![clause]; predicate_queue.compilation_target = compilation_target; - return self.compile(key, &predicate_queue, &queue, settings); + return self.compile(key, &mut predicate_queue, settings); } }; @@ -1154,13 +1189,25 @@ impl<'a> LoadState<'a> { let StandaloneCompileResult { clause_code, mut standalone_skeleton, - } = compile_standalone_clause(clause, queue, settings, atom_tbl)?; + } = self.compile_standalone_clause(clause, settings, atom_tbl)?; + + let code_len = self.wam.code_repo.code.len(); + + let skeleton = match self + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) if !skeleton.clauses.is_empty() => skeleton, + _ => unreachable!() + }; match append_or_prepend { AppendOrPrepend::Append => { - skeleton - .clauses - .push_back(standalone_skeleton.clauses.pop_back().unwrap()); + let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap(); + skeleton.clauses.push_back(clause_index_info); + + skeleton.clause_clause_locs.push_back(code_len); self.retraction_info .push_record(RetractionRecord::SkeletonClausePopBack( @@ -1175,6 +1222,38 @@ impl<'a> LoadState<'a> { &mut self.retraction_info, ); + match self + .wam + .indices + .get_local_predicate_skeleton_mut( + &self.compilation_target, + compilation_target.clone(), + key.clone(), + ) + { + Some(skeleton) => { + self.retraction_info.push_record( + RetractionRecord::SkeletonLocalClauseClausePopBack( + self.compilation_target.clone(), + compilation_target.clone(), + key.clone(), + ), + ); + + skeleton.clause_clause_locs.push_back(code_len); + } + None => { + let mut skeleton = PredicateSkeleton::new(); + skeleton.clause_clause_locs.push_back(code_len); + + self.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + } + let code_index = self.get_or_insert_code_index( key.clone(), compilation_target.clone(), @@ -1190,12 +1269,14 @@ impl<'a> LoadState<'a> { ); } - Ok(code_index.get()) + Ok(()) } AppendOrPrepend::Prepend => { - skeleton - .clauses - .push_front(standalone_skeleton.clauses.pop_back().unwrap()); + let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap(); + skeleton.clauses.push_front(clause_index_info); + + skeleton.clause_clause_locs.push_front(code_len); + skeleton.clause_assert_margin += 1; self.retraction_info .push_record(RetractionRecord::SkeletonClausePopFront( @@ -1212,6 +1293,38 @@ impl<'a> LoadState<'a> { &mut self.retraction_info, ); + match self + .wam + .indices + .get_local_predicate_skeleton_mut( + &self.compilation_target, + compilation_target.clone(), + key.clone(), + ) + { + Some(skeleton) => { + self.retraction_info.push_record( + RetractionRecord::SkeletonLocalClauseClausePopFront( + self.compilation_target.clone(), + compilation_target.clone(), + key.clone(), + ), + ); + + skeleton.clause_clause_locs.push_front(code_len); + } + None => { + let mut skeleton = PredicateSkeleton::new(); + skeleton.clause_clause_locs.push_front(code_len); + + self.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + } + let code_index = self.get_or_insert_code_index( key.clone(), compilation_target.clone(), @@ -1225,7 +1338,7 @@ impl<'a> LoadState<'a> { IndexPtr::Index(threaded_choice_instr_loc), ); - Ok(IndexPtr::Index(threaded_choice_instr_loc)) + Ok(()) } } } @@ -1309,7 +1422,7 @@ impl<'a> LoadState<'a> { skeleton.clauses[target_pos + 1].clause_start = skeleton.clauses[target_pos].clause_start; - return delete_from_dynamic_skeleton( + return delete_from_skeleton( self.compilation_target.clone(), key, skeleton, @@ -1530,12 +1643,12 @@ impl<'a, TS: TermStream> Loader<'a, TS> { append_or_prepend: AppendOrPrepend, ) -> Result<(), SessionError> { let clause_predicates = clause_clauses.map(|(head, body)| { - PredicateClause::Fact(Term::Clause( + Term::Clause( Cell::default(), clause_name!("$clause"), vec![Box::new(head), Box::new(body)], None, - )) + ) }); let clause_clause_compilation_target = match compilation_target { @@ -1543,93 +1656,68 @@ impl<'a, TS: TermStream> Loader<'a, TS> { _ => compilation_target.clone(), }; - let mut clause_clause_locs = sdeq![]; - - for clause_predicate in clause_predicates { - clause_clause_locs.push_back(self.load_state.wam.code_repo.code.len()); + let mut num_clause_predicates = 0; + for clause_term in clause_predicates { self.load_state.incremental_compile_clause( (clause_name!("$clause"), 2), - clause_predicate, - VecDeque::new(), + clause_term, clause_clause_compilation_target.clone(), false, // non_counted_bt is false. append_or_prepend, )?; + + num_clause_predicates += 1; } - match self.load_state.wam.indices.get_predicate_skeleton_mut( - &clause_clause_compilation_target, - &(clause_name!("$clause"), 2), - ) { + let locs_vec: Vec<_> = match self + .load_state + .wam + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { Some(skeleton) if append_or_prepend.is_append() => { - self.load_state.retraction_info.push_record( - RetractionRecord::SkeletonClauseClausesTruncateBack( - clause_clause_compilation_target.clone(), - (clause_name!("$clause"), 2), - skeleton.clause_clause_locs.len(), - ), - ); - - skeleton - .clause_clause_locs - .extend_from_slice(&clause_clause_locs[0..]); + let tail_num = skeleton.clause_clause_locs.len() - num_clause_predicates; + skeleton.clause_clause_locs[tail_num ..] + .iter() + .cloned() + .collect() } Some(skeleton) => { - self.load_state.retraction_info.push_record( - RetractionRecord::SkeletonClauseClausesTruncateFront( - clause_clause_compilation_target.clone(), - (clause_name!("$clause"), 2), - skeleton.clause_clause_locs.len(), - ), - ); - - for loc in clause_clause_locs.iter() { - skeleton.clause_clause_locs.push_front(*loc); - } + skeleton.clause_clause_locs[0 .. num_clause_predicates] + .iter() + .cloned() + .collect() } None => { - unreachable!(); + unreachable!() } - } + }; - match self - .load_state - .wam - .indices - .get_predicate_skeleton_mut(&compilation_target, &key) - { + match self.load_state.wam.indices.get_predicate_skeleton_mut( + &clause_clause_compilation_target, + &(clause_name!("$clause"), 2), + ) { Some(skeleton) if append_or_prepend.is_append() => { - self.load_state.retraction_info.push_record( - RetractionRecord::SkeletonClauseClausesTruncateBack( - compilation_target.clone(), - key.clone(), - skeleton.clause_clause_locs.len(), - ), - ); + for _ in 0 .. num_clause_predicates { + skeleton.clause_clause_locs.pop_back(); + } - skeleton.clause_clause_locs.append(&mut clause_clause_locs); + for loc in locs_vec { + skeleton.clause_clause_locs.push_back(loc); + } } Some(skeleton) => { - self.load_state.retraction_info.push_record( - RetractionRecord::SkeletonClauseClausesTruncateFront( - compilation_target.clone(), - key.clone(), - skeleton.clause_clause_locs.len(), - ), - ); - - for loc in clause_clause_locs.iter() { - skeleton.clause_clause_locs.push_front(*loc); + for _ in 0 .. num_clause_predicates { + skeleton.clause_clause_locs.pop_front(); } - self.load_state.increment_clause_assert_margin( - clause_clause_compilation_target, - clause_clause_locs.len(), - ); + for loc in locs_vec.into_iter().rev() { + skeleton.clause_clause_locs.push_front(loc); + } } None => { - unreachable!() + unreachable!(); } } @@ -1637,38 +1725,124 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> { - let queue = self.preprocessor.parse_queue(&mut self.load_state)?; - let key = self .predicates .first() .and_then(|cl| { - let arity = cl.arity(); - cl.name().map(|name| (name, arity)) + let arity = ClauseInfo::arity(cl); + ClauseInfo::name(cl).map(|name| (name, arity)) }) .ok_or(SessionError::NamelessEntry)?; - let (is_dynamic, is_extensible) = self + let mut predicate_info = self .load_state .wam .indices .get_predicate_skeleton(&self.predicates.compilation_target, &key) - .map(|skeleton| (skeleton.is_dynamic, true)) - .unwrap_or((false, false)); + .map(|skeleton| skeleton.predicate_info()) + .unwrap_or_default(); + let local_predicate_info = self + .load_state + .wam + .indices + .get_local_predicate_skeleton( + &self.load_state.compilation_target, + self.predicates.compilation_target.clone(), + key.clone(), + ) + .map(|skeleton| skeleton.predicate_info()) + .unwrap_or_default(); + + if predicate_info.must_retract_local_clauses() { + self.retract_local_clauses(&key, predicate_info.is_dynamic); + } + + let do_incremental_compile = + if self.load_state.compilation_target == self.predicates.compilation_target { + predicate_info.compile_incrementally() + } else { + local_predicate_info.is_multifile && predicate_info.compile_incrementally() + }; + + let predicates_len = self.predicates.len(); let non_counted_bt = self.non_counted_bt_preds.contains(&key); - let settings = CodeGenSettings::new(is_extensible, non_counted_bt); - self.load_state - .compile(key.clone(), &self.predicates, &queue, settings)?; + if do_incremental_compile { + for term in self.predicates.predicates.drain(0 ..) { + self.load_state.incremental_compile_clause( + key.clone(), + term, + self.predicates.compilation_target.clone(), + non_counted_bt, + AppendOrPrepend::Append, + )?; + } + } else { + if self.load_state.compilation_target != self.predicates.compilation_target { + if !local_predicate_info.is_extensible { + if predicate_info.is_multifile { + println!("Warning: overwriting multifile predicate {}:{}/{} because \ + it was not locally declared multifile.", + self.predicates.compilation_target, key.0, key.1); + } + + if let Some(skeleton) = self.load_state + .wam + .indices + .remove_predicate_skeleton( + &self.predicates.compilation_target, + &key, + ) + { + if predicate_info.is_dynamic { + let clause_clause_compilation_target = + match &self.predicates.compilation_target { + CompilationTarget::User => { + CompilationTarget::Module(clause_name!("builtins")) + } + module => { + module.clone() + } + }; + + self.load_state.retract_local_clauses_by_locs( + clause_clause_compilation_target, + (clause_name!("$clause"), 2), + (0 .. skeleton.clauses.len()).map(Some).collect(), + ); + + predicate_info.is_dynamic = false; + } + + self.load_state.retraction_info.push_record( + RetractionRecord::RemovedSkeleton( + self.predicates.compilation_target.clone(), + key.clone(), + skeleton, + ), + ); + } + } + } - if is_dynamic { - let iter = mem::replace(&mut self.clause_clauses, vec![]).into_iter(); - let compilation_target = self.predicates.compilation_target.clone(); + let settings = CodeGenSettings::new(predicate_info.is_extensible, non_counted_bt); + self.load_state.compile(key.clone(), &mut self.predicates, settings)?; + } + + if predicate_info.is_dynamic { + let clauses_vec: Vec<_> = self.clause_clauses + .drain(0 .. predicates_len) + .collect(); - self.compile_clause_clauses(key, compilation_target, iter, AppendOrPrepend::Append)?; + self.compile_clause_clauses( + key, + self.predicates.compilation_target.clone(), + clauses_vec.into_iter(), + AppendOrPrepend::Append, + )?; } - Ok(self.predicates.clear()) + Ok(()) } } diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 81427d05..c0e22473 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -1,11 +1,13 @@ use crate::machine::machine_indices::*; +use crate::machine::preprocessor::*; use crate::machine::*; +use crate::machine::term_stream::*; + use prolog_parser::clause_name; -use crate::machine::term_stream::*; use indexmap::IndexSet; - use ref_thread_local::RefThreadLocal; +use slice_deque::{sdeq, SliceDeque}; type ModuleOpExports = Vec<(OpDecl, Option<(usize, Specifier)>)>; @@ -328,28 +330,120 @@ fn import_qualified_module_exports_into_module( } impl<'a> LoadState<'a> { - #[inline] - pub(super) fn increment_clause_assert_margin( + pub(super) fn retract_local_clauses( &mut self, compilation_target: CompilationTarget, - incr: usize, + key: PredicateKey, + clause_locs: &SliceDeque, ) { - match compilation_target { - CompilationTarget::User => {} - CompilationTarget::Module(module_name) => { - self.wam - .indices - .modules - .get_mut(&module_name) - .map(|module| module.clause_assert_margin += incr); + let clause_target_poses: Vec<_> = self + .wam + .indices + .get_predicate_skeleton(&compilation_target, &key) + .map(|skeleton| { + clause_locs + .iter() + .map(|clause_clause_loc| { + skeleton.target_pos_of_clause_clause_loc( + *clause_clause_loc, + ) + }) + .collect() + }).unwrap(); + + self.retract_local_clauses_by_locs( + compilation_target, + key, + clause_target_poses, + ); + } - self.retraction_info - .push_record(RetractionRecord::IncreasedClauseAssertMargin( - module_name, - incr, - )); + pub(super) fn retract_local_clauses_by_locs( + &mut self, + compilation_target: CompilationTarget, + key: PredicateKey, + mut clause_target_poses: Vec>, + ) { + let old_compilation_target = mem::replace( + &mut self.compilation_target, + compilation_target, + ); + + while let Some(target_pos_opt) = clause_target_poses.pop() { + match target_pos_opt { + Some(target_pos) => { + self.retract_clause(key.clone(), 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.compilation_target = old_compilation_target; + } + + pub(super) fn retract_local_clause_clauses( + &mut self, + clause_clause_compilation_target: CompilationTarget, + clause_locs: &SliceDeque, + ) { + let key = (clause_name!("$clause"), 2); + + match self + .wam + .indices + .get_local_predicate_skeleton_mut( + &self.compilation_target, + clause_clause_compilation_target.clone(), + key.clone(), + ) + { + Some(skeleton) => { + self.retraction_info.push_record( + RetractionRecord::RemovedLocalSkeletonClauseLocations( + self.compilation_target.clone(), + clause_clause_compilation_target.clone(), + key.clone(), + mem::replace(&mut skeleton.clause_clause_locs, sdeq![]), + ), + ); + + 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( + 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, + CutContext::BlocksCuts, + )?; + + Ok(match tl { + TopLevel::Fact(fact) => PredicateClause::Fact(fact), + TopLevel::Rule(rule) => PredicateClause::Rule(rule), + TopLevel::Query(_) => return Err(SessionError::QueryCannotBeDefinedAsFact), + _ => unreachable!(), + }) } #[inline] @@ -451,16 +545,51 @@ impl<'a> LoadState<'a> { .extensible_predicates .insert(key.clone(), skeleton); - self.retraction_info - .push_record(RetractionRecord::AddedUserExtensiblePredicate(key)); + let record = RetractionRecord::AddedExtensiblePredicate( + CompilationTarget::User, + key, + ); + + self.retraction_info.push_record(record); } CompilationTarget::Module(module_name) => { if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { - module.extensible_predicates.insert(key.clone(), skeleton); + module + .extensible_predicates + .insert(key.clone(), skeleton); - self.retraction_info.push_record( - RetractionRecord::AddedModuleExtensiblePredicate(module_name, key), + let record = RetractionRecord::AddedExtensiblePredicate( + CompilationTarget::Module(module_name), + key, ); + + self.retraction_info.push_record(record); + } else { + unreachable!() + } + } + } + } + + #[inline] + pub(super) fn add_local_extensible_predicate( + &mut self, + local_compilation_target: CompilationTarget, + key: PredicateKey, + skeleton: PredicateSkeleton, + ) { + match self.compilation_target.clone() { + CompilationTarget::User => { + self.wam + .indices + .local_extensible_predicates + .insert((local_compilation_target.clone(), key.clone()), skeleton); + } + CompilationTarget::Module(module_name) => { + if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + module + .local_extensible_predicates + .insert((local_compilation_target.clone(), key.clone()), skeleton); } else { unreachable!() } @@ -604,32 +733,40 @@ impl<'a> LoadState<'a> { } } None => { - 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.add_dynamically_generated_module(&module_name); - module.meta_predicates.insert(key.clone(), meta_specs); + if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + module.meta_predicates.insert(key.clone(), meta_specs); + } else { + unreachable!() + } self.retraction_info .push_record(RetractionRecord::AddedMetaPredicate( module_name.clone(), key, )); - - self.retraction_info - .push_record(RetractionRecord::AddedModule(module_name.clone())); - - self.wam.indices.modules.insert(module_name, module); } } } } } + pub(super) fn add_dynamically_generated_module(&mut self, module_name: &ClauseName) { + let module_decl = ModuleDecl { + name: module_name.clone(), + exports: vec![], + }; + + let listing_src = ListingSource::DynamicallyGenerated; + let module = Module::new(module_decl, listing_src); + + self.retraction_info + .push_record(RetractionRecord::AddedModule(module_name.clone())); + + self.wam.indices.modules.insert(module_name.clone(), module); + } + fn import_builtins_in_module( &mut self, code_dir: &mut CodeDir, @@ -651,16 +788,57 @@ impl<'a> LoadState<'a> { pub(crate) fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) { let module_name = module_decl.name.clone(); - let mut module = match self.wam.indices.modules.remove(&module_name) { - Some(mut module) => { - let old_module_decl = mem::replace(&mut module.module_decl, module_decl); + match self.wam.indices.modules.get_mut(&module_name) { + Some(module) => { + let old_module_decl = mem::replace(&mut module.module_decl, module_decl.clone()); - self.retraction_info - .push_record(RetractionRecord::ReplacedModule( - old_module_decl, - listing_src.clone(), - )); + let local_extensible_predicates = mem::replace( + &mut module.local_extensible_predicates, + LocalExtensiblePredicates::new(), + ); + + for ((compilation_target, key), skeleton) in local_extensible_predicates.iter() { + self.retract_local_clauses( + compilation_target.clone(), + key.clone(), + &skeleton.clause_clause_locs, + ); + + let is_dynamic = self + .wam + .indices + .get_predicate_skeleton(&compilation_target, &key) + .map(|skeleton| skeleton.is_dynamic) + .unwrap_or(false); + + if is_dynamic { + let clause_clause_compilation_target = match compilation_target { + CompilationTarget::User => { + CompilationTarget::Module(clause_name!("builtins")) + } + module => { + module.clone() + } + }; + + self.retract_local_clause_clauses( + clause_clause_compilation_target, + &skeleton.clause_clause_locs, + ); + } + } + self.retraction_info.push_record(RetractionRecord::ReplacedModule( + old_module_decl, + listing_src.clone(), + local_extensible_predicates, + )); + } + None => {} + } + + let mut module = match self.wam.indices.modules.remove(&module_name) { + Some(mut module) => { module.listing_src = listing_src; module } diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 7046fa1e..3ece45ba 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -9,6 +9,7 @@ use crate::machine::preprocessor::*; use crate::machine::*; use indexmap::IndexSet; +use slice_deque::{sdeq, SliceDeque}; use std::cell::Cell; use std::convert::TryFrom; @@ -28,10 +29,10 @@ use std::rc::Rc; * compiling inline disjunctions. * * Since the loader can operate incrementally, it uses an intermittent - * structure to rebuild the loader between - * invocations. TopLevelBatchWorker needs access to a &'a mut Machine - * for as long as it lives, and we can't have copies of &'a mut - * Machine distributed among multiple owners. + * structure to rebuild the loader between invocations. Preprocessor + * needs access to a &'a mut Machine for as long as it lives, and we + * can't have copies of &'a mut Machine distributed among multiple + * owners. * * When loading a module, we modify the records of the WAM with the * location of new predicates, with new meta-predicate information, @@ -46,19 +47,19 @@ pub(crate) enum RetractionRecord { AddedMetaPredicate(ClauseName, PredicateKey), ReplacedMetaPredicate(ClauseName, ClauseName, Vec), AddedModule(ClauseName), - ReplacedModule(ModuleDecl, ListingSource), - AddedModuleDynamicPredicate(ClauseName, PredicateKey), - AddedModuleExtensiblePredicate(ClauseName, PredicateKey), + ReplacedModule(ModuleDecl, ListingSource, LocalExtensiblePredicates), AppendedModuleExtensiblePredicate(ClauseName, PredicateKey), PrependedModuleExtensiblePredicate(ClauseName, PredicateKey), AddedModuleOp(ClauseName, OpDecl), ReplacedModuleOp(ClauseName, OpDecl, usize, Specifier), AddedModulePredicate(ClauseName, PredicateKey), ReplacedModulePredicate(ClauseName, PredicateKey, IndexPtr), - AddedUserDynamicPredicate(PredicateKey), + AddedDiscontiguousPredicate(CompilationTarget, PredicateKey), + AddedDynamicPredicate(CompilationTarget, PredicateKey), + AddedMultifilePredicate(CompilationTarget, PredicateKey), AddedUserOp(OpDecl), ReplacedUserOp(OpDecl, usize, Specifier), - AddedUserExtensiblePredicate(PredicateKey), + AddedExtensiblePredicate(CompilationTarget, PredicateKey), AppendedUserExtensiblePredicate(PredicateKey), PrependedUserExtensiblePredicate(PredicateKey), AddedUserPredicate(PredicateKey), @@ -71,14 +72,13 @@ pub(crate) enum RetractionRecord { ModifiedTryMeElse(usize, usize), ModifiedRetryMeElse(usize, usize), ModifiedRevJmpBy(usize, usize), - IncreasedClauseAssertMargin(ClauseName, usize), - SkeletonClauseClausesTruncateBack(CompilationTarget, PredicateKey, usize), - SkeletonClauseClausesTruncateFront(CompilationTarget, PredicateKey, usize), SkeletonClausePopBack(CompilationTarget, PredicateKey), SkeletonClausePopFront(CompilationTarget, PredicateKey), + SkeletonLocalClauseClausePopBack(CompilationTarget, CompilationTarget, PredicateKey), + SkeletonLocalClauseClausePopFront(CompilationTarget, CompilationTarget, PredicateKey), SkeletonClauseTruncateBack(CompilationTarget, PredicateKey, usize), SkeletonClauseStartReplaced(CompilationTarget, PredicateKey, usize, usize), - RemovedDynamicSkeletonClause( + RemovedSkeletonClause( CompilationTarget, PredicateKey, usize, @@ -86,6 +86,13 @@ pub(crate) enum RetractionRecord { usize, ), ReplacedIndexingLine(usize, Vec), + RemovedLocalSkeletonClauseLocations( + CompilationTarget, + CompilationTarget, + PredicateKey, + SliceDeque, + ), + RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton), } /* @@ -123,7 +130,7 @@ impl RetractionInfo { Self { orig_code_extent, - records: mem::replace(&mut self.records, vec![]), //BTreeMap::new()), + records: mem::replace(&mut self.records, vec![]), } } } @@ -170,31 +177,90 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::AddedModule(module_name) => { self.wam.indices.modules.remove(&module_name); } - RetractionRecord::ReplacedModule(module_decl, listing_src) => { + RetractionRecord::ReplacedModule( + module_decl, + listing_src, + local_extensible_predicates, + ) => { match self.wam.indices.modules.get_mut(&module_decl.name) { Some(ref mut module) => { module.module_decl = module_decl; module.listing_src = listing_src; + module.local_extensible_predicates = local_extensible_predicates; } _ => { unreachable!() } } } - RetractionRecord::AddedModuleDynamicPredicate(module_name, key) => { - match self.wam.indices.modules.get_mut(&module_name) { - Some(ref mut module) => { - module.extensible_predicates.get_mut(&key).map(|skeleton| { - skeleton.is_dynamic = false; - }); + RetractionRecord::AddedDiscontiguousPredicate(compilation_target, key) => { + match compilation_target { + CompilationTarget::User => { + self.wam + .indices + .extensible_predicates + .get_mut(&key) + .map(|skeleton| { + skeleton.is_discontiguous = false; + }); + } + CompilationTarget::Module(module_name) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.extensible_predicates.get_mut(&key).map(|skeleton| { + skeleton.is_discontiguous = false; + }); + } + None => {} + } } - None => {} } } - RetractionRecord::AddedModuleExtensiblePredicate(module_name, key) => { - self.wam - .indices - .remove_predicate_skeleton(&CompilationTarget::Module(module_name), &key); + RetractionRecord::AddedDynamicPredicate(compilation_target, key) => { + match compilation_target { + CompilationTarget::User => { + self.wam + .indices + .extensible_predicates + .get_mut(&key) + .map(|skeleton| { + skeleton.is_dynamic = false; + }); + } + CompilationTarget::Module(module_name) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.extensible_predicates.get_mut(&key).map(|skeleton| { + skeleton.is_dynamic = false; + }); + } + None => {} + } + } + } + } + RetractionRecord::AddedMultifilePredicate(compilation_target, key) => { + match compilation_target { + CompilationTarget::User => { + self.wam + .indices + .extensible_predicates + .get_mut(&key) + .map(|skeleton| { + skeleton.is_multifile = false; + }); + } + CompilationTarget::Module(module_name) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.extensible_predicates.get_mut(&key).map(|skeleton| { + skeleton.is_multifile = false; + }); + } + None => {} + } + } + } } RetractionRecord::AppendedModuleExtensiblePredicate(module_name, key) => { self.wam @@ -249,19 +315,10 @@ impl<'a> Drop for LoadState<'a> { None => {} } } - RetractionRecord::AddedUserDynamicPredicate(key) => { - self.wam - .indices - .extensible_predicates - .get_mut(&key) - .map(|skeleton| { - skeleton.is_dynamic = false; - }); - } - RetractionRecord::AddedUserExtensiblePredicate(key) => { + RetractionRecord::AddedExtensiblePredicate(compilation_target, key) => { self.wam .indices - .remove_predicate_skeleton(&CompilationTarget::User, &key); + .remove_predicate_skeleton(&compilation_target, &key); } RetractionRecord::AppendedUserExtensiblePredicate(key) => { self.wam @@ -399,99 +456,65 @@ impl<'a> Drop for LoadState<'a> { self.wam.code_repo.code[instr_loc] = Line::Control(ControlInstruction::RevJmpBy(o)); } - RetractionRecord::IncreasedClauseAssertMargin(module_name, incr) => { - if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { - module.clause_assert_margin -= incr; - } - } - RetractionRecord::SkeletonClauseClausesTruncateFront( - compilation_target, - key, - len, - ) => { + RetractionRecord::SkeletonClausePopBack(compilation_target, key) => { match self .wam .indices .get_predicate_skeleton_mut(&compilation_target, &key) { Some(skeleton) => { - skeleton.clause_clause_locs.truncate_front(len); - } - None => {} - } - - let compilation_target = match compilation_target { - CompilationTarget::User => { - CompilationTarget::Module(clause_name!("builtins")) - } - _ => compilation_target, - }; - - match self - .wam - .indices - .get_predicate_skeleton_mut(&compilation_target, &(clause_name!("$clause"), 2)) - { - Some(skeleton) => { - skeleton.clause_clause_locs.truncate_front(len); + skeleton.clauses.pop_back(); + skeleton.clause_clause_locs.pop_back(); } None => {} } } - RetractionRecord::SkeletonClauseClausesTruncateBack( - compilation_target, - key, - len, - ) => { + RetractionRecord::SkeletonClausePopFront(compilation_target, key) => { match self .wam .indices .get_predicate_skeleton_mut(&compilation_target, &key) { Some(skeleton) => { - skeleton.clause_clause_locs.truncate_back(len); - } - None => {} - } - - let compilation_target = match compilation_target { - CompilationTarget::User => { - CompilationTarget::Module(clause_name!("builtins")) - } - _ => compilation_target, - }; - - match self - .wam - .indices - .get_predicate_skeleton_mut(&compilation_target, &(clause_name!("$clause"), 2)) - { - Some(skeleton) => { - skeleton.clause_clause_locs.truncate_back(len); + skeleton.clauses.pop_front(); + skeleton.clause_clause_locs.pop_front(); + skeleton.clause_assert_margin -= 1; } None => {} } } - RetractionRecord::SkeletonClausePopBack(compilation_target, key) => { + RetractionRecord::SkeletonLocalClauseClausePopFront( + src_compilation_target, local_compilation_target, key, + ) => { match self .wam .indices - .get_predicate_skeleton_mut(&compilation_target, &key) + .get_local_predicate_skeleton_mut( + &src_compilation_target, + local_compilation_target, + key, + ) { Some(skeleton) => { - skeleton.clauses.pop_back(); + skeleton.clause_clause_locs.pop_front(); } None => {} } } - RetractionRecord::SkeletonClausePopFront(compilation_target, key) => { + RetractionRecord::SkeletonLocalClauseClausePopBack( + src_compilation_target, local_compilation_target, key, + ) => { match self .wam .indices - .get_predicate_skeleton_mut(&compilation_target, &key) + .get_local_predicate_skeleton_mut( + &src_compilation_target, + local_compilation_target, + key, + ) { Some(skeleton) => { - skeleton.clauses.pop_front(); + skeleton.clause_clause_locs.pop_back(); } None => {} } @@ -504,6 +527,7 @@ impl<'a> Drop for LoadState<'a> { { Some(skeleton) => { skeleton.clauses.truncate_back(len); + skeleton.clause_clause_locs.truncate_back(len); } None => {} } @@ -525,7 +549,7 @@ impl<'a> Drop for LoadState<'a> { None => {} } } - RetractionRecord::RemovedDynamicSkeletonClause( + RetractionRecord::RemovedSkeletonClause( compilation_target, key, target_pos, @@ -549,6 +573,37 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => { self.wam.code_repo.code[index_loc] = Line::IndexingCode(indexing_code); } + RetractionRecord::RemovedLocalSkeletonClauseLocations( + compilation_target, + local_compilation_target, + key, + clause_locs, + ) => { + match self + .wam + .indices + .get_local_predicate_skeleton_mut( + &compilation_target, + local_compilation_target, + key, + ) + { + Some(skeleton) => skeleton.clause_clause_locs = clause_locs, + None => {} + } + } + RetractionRecord::RemovedSkeleton(compilation_target, key, skeleton) => { + match compilation_target { + CompilationTarget::User => { + self.wam.indices.extensible_predicates.insert(key, skeleton); + } + CompilationTarget::Module(module_name) => { + if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + module.extensible_predicates.insert(key, skeleton); + } + } + } + } } } @@ -557,7 +612,7 @@ impl<'a> Drop for LoadState<'a> { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum CompilationTarget { Module(ClauseName), User, @@ -577,7 +632,7 @@ impl CompilationTarget { } #[inline] - pub(super) fn module_name(&self) -> ClauseName { + pub fn module_name(&self) -> ClauseName { match self { CompilationTarget::User => { clause_name!("user") @@ -588,28 +643,18 @@ impl CompilationTarget { } pub struct PredicateQueue { - pub(super) predicates: Vec, + pub(super) predicates: Vec, pub(super) compilation_target: CompilationTarget, } impl PredicateQueue { #[inline] - pub(super) fn push(&mut self, clause: PredicateClause) { + pub(super) fn push(&mut self, clause: Term) { self.predicates.push(clause); } #[inline] - pub(super) fn extend(&mut self, iter: impl Iterator) { - self.predicates.extend(iter); - } - - #[inline] - pub(super) fn clear(&mut self) { - self.predicates.clear(); - } - - #[inline] - pub(crate) fn first(&self) -> Option<&PredicateClause> { + pub(crate) fn first(&self) -> Option<&Term> { self.predicates.first() } @@ -625,6 +670,11 @@ impl PredicateQueue { compilation_target: self.compilation_target.take(), } } + + #[inline] + pub(super) fn len(&self) -> usize { + self.predicates.len() + } } macro_rules! predicate_queue { @@ -642,13 +692,11 @@ pub(crate) struct Loader<'a, TermStream> { pub(super) clause_clauses: Vec<(Term, Term)>, term_stream: TermStream, pub(super) non_counted_bt_preds: IndexSet, - pub(super) preprocessor: Preprocessor, } impl<'a, TS: TermStream> Loader<'a, TS> { #[inline] pub(super) fn new(term_stream: TS, wam: &'a mut Machine) -> Self { - let flags = wam.machine_st.flags; let load_state = LoadState { compilation_target: CompilationTarget::User, module_op_exports: vec![], @@ -660,7 +708,6 @@ impl<'a, TS: TermStream> Loader<'a, TS> { load_state, term_stream, non_counted_bt_preds: IndexSet::new(), - preprocessor: Preprocessor::new(flags), predicates: predicate_queue![], clause_clauses: vec![], } @@ -683,19 +730,15 @@ impl<'a, TS: TermStream> Loader<'a, TS> { self.compile_and_submit()?; } - let tl = self.preprocessor.try_term_to_tl( - &mut self.load_state, - term, - CutContext::BlocksCuts, - )?; + let term = match term { + Term::Clause(_, name, terms, _) + if name.as_str() == ":-" && terms.len() == 1 => { + return Ok(Some(setup_declaration(&self.load_state, terms)?)); + }, + term => term, + }; - match tl { - TopLevel::Fact(fact) => self.predicates.push(PredicateClause::Fact(fact)), - TopLevel::Rule(rule) => self.predicates.push(PredicateClause::Rule(rule)), - TopLevel::Predicate(pred) => self.predicates.extend(pred.into_iter()), - TopLevel::Declaration(decl) => return Ok(Some(decl)), - TopLevel::Query(_) => return Err(SessionError::QueryCannotBeDefinedAsFact), - } + self.predicates.push(term); } Ok(None) @@ -704,7 +747,8 @@ impl<'a, TS: TermStream> Loader<'a, TS> { pub(super) fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> { match decl { Declaration::Dynamic(name, arity) => { - self.add_dynamic_predicate(name, arity); + let compilation_target = self.load_state.compilation_target.clone(); + self.add_dynamic_predicate(compilation_target, name, arity)?; } Declaration::MetaPredicate(module_name, name, meta_specs) => { self.load_state @@ -857,10 +901,18 @@ impl<'a, TS: TermStream> Loader<'a, TS> { Ok(()) } - fn add_dynamic_predicate(&mut self, name: ClauseName, arity: usize) { + fn add_extensible_predicate_declaration( + &mut self, + compilation_target: CompilationTarget, + name: ClauseName, + arity: usize, + flag_accessor: impl Fn(&mut PredicateSkeleton) -> &mut bool, + retraction_fn: impl Fn(CompilationTarget, PredicateKey) -> RetractionRecord, + ) -> Result<(), SessionError> { let key = (name, arity); + let mut throw_permission_error = false; - match &self.load_state.compilation_target { + match &compilation_target { CompilationTarget::User => { match self .load_state @@ -870,20 +922,27 @@ impl<'a, TS: TermStream> Loader<'a, TS> { .get_mut(&key) { Some(ref mut skeleton) => { - if !skeleton.is_dynamic { - skeleton.is_dynamic = true; + if !*flag_accessor(skeleton) { + *flag_accessor(skeleton) = true; self.load_state.retraction_info.push_record( - RetractionRecord::AddedUserDynamicPredicate(key.clone()), + retraction_fn(compilation_target.clone(), key.clone()), ); } } None => { - self.load_state.add_extensible_predicate( - key.clone(), - PredicateSkeleton::new().set_dynamic(true), - CompilationTarget::User, - ); + if self.load_state.compilation_target == compilation_target { + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_extensible_predicate( + key.clone(), + skeleton, + CompilationTarget::User, + ); + } else { + throw_permission_error = true; + } } } } @@ -891,44 +950,176 @@ impl<'a, TS: TermStream> Loader<'a, TS> { match self.load_state.wam.indices.modules.get_mut(module_name) { Some(ref mut module) => match module.extensible_predicates.get_mut(&key) { Some(ref mut skeleton) => { - if !skeleton.is_dynamic { - skeleton.is_dynamic = true; + if !*flag_accessor(skeleton) { + *flag_accessor(skeleton) = true; self.load_state.retraction_info.push_record( - RetractionRecord::AddedModuleDynamicPredicate( - module_name.clone(), - key.clone(), - ), + retraction_fn(compilation_target.clone(), key.clone()), ); } } None => { - self.load_state.add_extensible_predicate( - key.clone(), - PredicateSkeleton::new().set_dynamic(true), - self.load_state.compilation_target.clone(), - ); + if self.load_state.compilation_target == compilation_target { + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_extensible_predicate( + key.clone(), + skeleton, + compilation_target.clone(), + ); + } else { + throw_permission_error = true; + } } }, None => { - unreachable!(); + self.load_state.add_dynamically_generated_module(module_name); + + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_extensible_predicate( + key.clone(), + skeleton, + compilation_target.clone(), + ); } } } } + if !throw_permission_error { + match self.load_state.compilation_target.clone() { + CompilationTarget::User => { + match self + .load_state + .wam + .indices + .local_extensible_predicates + .get_mut(&(compilation_target.clone(), key.clone())) + { + Some(ref mut skeleton) => { + if !*flag_accessor(skeleton) { + *flag_accessor(skeleton) = true; + } + } + None => { + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + } + } + CompilationTarget::Module(ref module_name) => { + match self.load_state.wam.indices.modules.get_mut(module_name) { + Some(ref mut module) => + match module.local_extensible_predicates.get_mut( + &(compilation_target.clone(), key.clone()), + ) { + Some(ref mut skeleton) => { + if !*flag_accessor(skeleton) { + *flag_accessor(skeleton) = true; + } + } + None => { + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + }, + None => { + self.load_state.add_dynamically_generated_module(module_name); + + let mut skeleton = PredicateSkeleton::new(); + *flag_accessor(&mut skeleton) = true; + + self.load_state.add_local_extensible_predicate( + compilation_target.clone(), + key.clone(), + skeleton, + ); + } + } + } + } + + Ok(()) + } else { + Err(SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key)) + } + } + + fn add_discontiguous_predicate( + &mut self, + compilation_target: CompilationTarget, + name: ClauseName, + arity: usize, + ) -> Result<(), SessionError> { + self.add_extensible_predicate_declaration( + compilation_target, + name, + arity, + |skeleton| &mut skeleton.is_discontiguous, + RetractionRecord::AddedDiscontiguousPredicate, + ) + } + + fn add_dynamic_predicate( + &mut self, + compilation_target: CompilationTarget, + name: ClauseName, + arity: usize, + ) -> Result<(), SessionError> { + self.add_extensible_predicate_declaration( + compilation_target.clone(), + name.clone(), + arity, + |skeleton| &mut skeleton.is_dynamic, + RetractionRecord::AddedDynamicPredicate, + )?; + let code_index = self.load_state.get_or_insert_code_index( - key.clone(), - self.load_state.compilation_target.clone(), + (name.clone(), arity), + compilation_target.clone(), ); - set_code_index( - &mut self.load_state.retraction_info, - &self.load_state.compilation_target, - key, - &code_index, - IndexPtr::DynamicUndefined, - ); + if let IndexPtr::Undefined = code_index.get() { + set_code_index( + &mut self.load_state.retraction_info, + &compilation_target, + (name, arity), + &code_index, + IndexPtr::DynamicUndefined, + ); + } + + Ok(()) + } + + fn add_multifile_predicate( + &mut self, + compilation_target: CompilationTarget, + name: ClauseName, + arity: usize, + ) -> Result<(), SessionError> { + self.add_extensible_predicate_declaration( + compilation_target, + name, + arity, + |skeleton| &mut skeleton.is_multifile, + RetractionRecord::AddedMultifilePredicate, + ) } fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> { @@ -953,6 +1144,51 @@ impl<'a, TS: TermStream> Loader<'a, TS> { Ok(()) } + + pub(super) fn retract_local_clauses(&mut self, key: &PredicateKey, is_dynamic: bool) { + let clause_locs = match self + .load_state + .wam + .indices + .get_local_predicate_skeleton_mut( + &self.load_state.compilation_target, + self.predicates.compilation_target.clone(), + key.clone(), + ) + { + Some(skeleton) if !skeleton.clause_clause_locs.is_empty() => + mem::replace(&mut skeleton.clause_clause_locs, sdeq![]), + _ => + return, + }; + + self.load_state.retraction_info.push_record( + RetractionRecord::RemovedLocalSkeletonClauseLocations( + self.load_state.compilation_target.clone(), + self.predicates.compilation_target.clone(), + key.clone(), + clause_locs.clone(), + ), + ); + + self.load_state.retract_local_clauses( + self.predicates.compilation_target.clone(), + key.clone(), + &clause_locs, + ); + + if is_dynamic { + let clause_clause_compilation_target = match &self.predicates.compilation_target { + CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), + module_name => module_name.clone(), + }; + + self.load_state.retract_local_clause_clauses( + clause_clause_compilation_target, + &clause_locs, + ); + } + } } impl Machine { @@ -1052,16 +1288,52 @@ impl Machine { self.restore_load_state_payload(result, evacuable_h); } + #[inline] + pub(crate) fn add_discontiguous_predicate(&mut self) { + self.add_extensible_predicate_declaration(|loader, compilation_target, clause_name, arity| { + loader.add_discontiguous_predicate(compilation_target, clause_name, arity) + }); + } + + #[inline] pub(crate) fn add_dynamic_predicate(&mut self) { - let predicate_name = atom_from!( + self.add_extensible_predicate_declaration(|loader, compilation_target, clause_name, arity| { + loader.add_dynamic_predicate(compilation_target, clause_name, arity) + }); + } + + #[inline] + pub(crate) fn add_multifile_predicate(&mut self) { + self.add_extensible_predicate_declaration(|loader, compilation_target, clause_name, arity| { + loader.add_multifile_predicate(compilation_target, clause_name, arity) + }); + } + + fn add_extensible_predicate_declaration( + &mut self, + decl_adder: impl Fn(&mut Loader, CompilationTarget, ClauseName, usize) + -> Result<(), SessionError>, + ) { + let module_name = atom_from!( self.machine_st, self.machine_st .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) ); + let compilation_target = match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + let predicate_name = atom_from!( + self.machine_st, + self.machine_st + .store(self.machine_st.deref(self.machine_st[temp_v!(2)])) + ); + let arity = self .machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(2)])); + .store(self.machine_st.deref(self.machine_st[temp_v!(3)])); let arity = match Number::try_from((arity, &self.machine_st.heap)) { Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => Ok(n.to_usize().unwrap()), @@ -1071,14 +1343,14 @@ impl Machine { _ => Err(SessionError::from(CompilationError::InvalidRuleHead)), }; - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(4)); - let add_dynamic_predicate = || { - loader.add_dynamic_predicate(predicate_name, arity?); + let add_predicate_decl = || { + decl_adder(&mut loader, compilation_target, predicate_name, arity?)?; LiveTermStream::evacuate(loader) }; - let result = add_dynamic_predicate(); + let result = add_predicate_decl(); self.restore_load_state_payload(result, evacuable_h); } @@ -1088,7 +1360,7 @@ impl Machine { let add_clause = || { let term = loader.read_term_from_heap(temp_v!(1))?; - loader.incremental_compile_clause( + loader.load_state.incremental_compile_clause( (clause_name!("term_expansion"), 2), term, CompilationTarget::User, @@ -1120,7 +1392,7 @@ impl Machine { let add_clause = || { let term = loader.read_term_from_heap(temp_v!(2))?; - loader.incremental_compile_clause( + loader.load_state.incremental_compile_clause( (clause_name!("goal_expansion"), 2), term, compilation_target, @@ -1415,7 +1687,7 @@ impl Machine { fetch_op_spec(clause_name!(":-"), 2, &loader.load_state.wam.indices.op_dir), ); - loader.incremental_compile_clause( + loader.load_state.incremental_compile_clause( key.clone(), asserted_clause, compilation_target.clone(), @@ -1484,15 +1756,6 @@ impl Machine { } }; - let mut clause_assert_margin = loader - .load_state - .wam - .indices - .modules - .get(&clause_clause_compilation_target.module_name()) - .map(|module| module.clause_assert_margin) - .unwrap(); - let mut clause_clause_target_poses: Vec<_> = loader .load_state .wam @@ -1513,8 +1776,7 @@ impl Machine { .map(|clause_clause_loc| { clause_clause_skeleton.target_pos_of_clause_clause_loc( *clause_clause_loc, - clause_assert_margin, - ) + ).unwrap() }) .collect() }) @@ -1527,10 +1789,7 @@ impl Machine { .wam .indices .get_predicate_skeleton_mut(&loader.load_state.compilation_target, &key) - .map(|skeleton| { - skeleton.clauses.clear(); - skeleton.clause_clause_locs.clear(); - }); + .map(|skeleton| skeleton.reset()); let code_index = loader.load_state.get_or_insert_code_index( key, @@ -1543,20 +1802,8 @@ impl Machine { while let Some(target_pos) = clause_clause_target_poses.pop() { loader.load_state.retract_clause((clause_name!("$clause"), 2), target_pos); - - if target_pos < clause_assert_margin { - clause_assert_margin -= 1; - } } - loader - .load_state - .wam - .indices - .modules - .get_mut(&loader.load_state.compilation_target.module_name()) - .map(|module| module.clause_assert_margin = clause_assert_margin); - LiveTermStream::evacuate(loader) }; @@ -1605,36 +1852,14 @@ impl Machine { let clause_clause_loc = loader.load_state.retract_clause(key, target_pos); - let clause_assert_margin = loader - .load_state - .wam - .indices - .modules - .get(&clause_clause_compilation_target.module_name()) - .map(|module| module.clause_assert_margin) - .unwrap(); - let target_pos = match loader.load_state.wam.indices.get_predicate_skeleton( &clause_clause_compilation_target, &(clause_name!("$clause"), 2), ) { Some(skeleton) => { - let target_pos = skeleton.target_pos_of_clause_clause_loc( + skeleton.target_pos_of_clause_clause_loc( clause_clause_loc, - clause_assert_margin, - ); - - if target_pos < clause_assert_margin { - loader - .load_state - .wam - .indices - .modules - .get_mut(&clause_clause_compilation_target.module_name()) - .map(|module| module.clause_assert_margin -= 1); - } - - target_pos + ).unwrap() } None => { unreachable!(); @@ -1834,10 +2059,6 @@ impl<'a> Loader<'a, LiveTermStream> { &mut self.term_stream, LiveTermStream::new(ListingSource::User), ), - preprocessor: mem::replace( - &mut self.preprocessor, - Preprocessor::new(self.load_state.wam.machine_st.flags), - ), non_counted_bt_preds: mem::replace(&mut self.non_counted_bt_preds, IndexSet::new()), compilation_target: self.load_state.compilation_target.take(), retraction_info: mem::replace( @@ -1859,10 +2080,6 @@ impl<'a> Loader<'a, LiveTermStream> { &mut payload.term_stream, LiveTermStream::new(ListingSource::User), ), - preprocessor: mem::replace( - &mut payload.preprocessor, - Preprocessor::new(MachineFlags::default()), - ), non_counted_bt_preds: mem::replace(&mut payload.non_counted_bt_preds, IndexSet::new()), clause_clauses: mem::replace(&mut payload.clause_clauses, vec![]), predicates: payload.predicates.take(), @@ -1875,44 +2092,6 @@ impl<'a> Loader<'a, LiveTermStream> { } } - fn incremental_compile_clause( - &mut self, - key: PredicateKey, - term: Term, - compilation_target: CompilationTarget, - non_counted_bt: bool, - append_or_prepend: AppendOrPrepend, - ) -> Result<(), SessionError> { - let mut preprocessor = Preprocessor::new(self.load_state.wam.machine_st.flags); - - let tl = preprocessor.try_term_to_tl( - &mut self.load_state, - term, - CutContext::BlocksCuts, - )?; - - let queue = preprocessor.parse_queue(&mut self.load_state)?; - - let clause = match tl { - TopLevel::Fact(fact) => PredicateClause::Fact(fact), - TopLevel::Rule(rule) => PredicateClause::Rule(rule), - _ => { - unreachable!() - } - }; - - self.load_state.incremental_compile_clause( - key, - clause, - queue, - compilation_target, - non_counted_bt, - append_or_prepend, - )?; - - Ok(()) - } - fn read_and_enqueue_term( mut self, term_reg: RegType, diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 2e3b5e91..c446107f 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -4,6 +4,7 @@ use prolog_parser::{clause_name, temp_v}; use crate::forms::{ModuleSource, Number}; //, PredicateKey}; use crate::machine::PredicateKey; use crate::machine::heap::*; +use crate::machine::loader::CompilationTarget; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; use crate::rug::Integer; @@ -344,6 +345,22 @@ impl MachineError { Self::permission_error(h, Permission::Create, "operator", functor!(clause_name(op))) } SessionError::CompilationError(err) => Self::syntax_error(h, err), + SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => { + let functor_stub = Self::functor_stub(key.0, key.1); + let stub = functor!( + ":", + SharedOpDesc::new(600, XFY), + [clause_name(compilation_target.module_name()), aux(h + 4, 0)], + [functor_stub] + ); + + Self::permission_error( + h, + Permission::Modify, + "not_declared_multifile_or_discontiguous", + stub, + ) + } SessionError::QueryCannotBeDefinedAsFact => Self::permission_error( h, Permission::Create, @@ -808,6 +825,7 @@ pub enum SessionError { ModuleCannotImportSelf(ClauseName), NamelessEntry, OpIsInfixAndPostFix(ClauseName), + PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey), QueryCannotBeDefinedAsFact, } diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 4b4a4c18..2d0556d3 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -417,7 +417,9 @@ impl Default for CodeIndex { #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] pub enum REPLCodePtr { + AddDiscontiguousPredicate, AddDynamicPredicate, + AddMultifilePredicate, AddGoalExpansionClause, AddTermExpansionClause, ClauseToEvacuable, @@ -743,6 +745,68 @@ impl IndexStore { } } + pub fn get_local_predicate_skeleton_mut( + &mut self, + src_compilation_target: &CompilationTarget, + local_compilation_target: CompilationTarget, + key: PredicateKey, + ) -> Option<&mut PredicateSkeleton> { + match (key.0.as_str(), key.1) { + ("term_expansion", 2) => { + self.local_extensible_predicates.get_mut( + &(local_compilation_target, key), + ) + } + _ => match src_compilation_target { + CompilationTarget::User => { + self.local_extensible_predicates.get_mut( + &(local_compilation_target, key), + ) + } + CompilationTarget::Module(ref module_name) => { + if let Some(module) = self.modules.get_mut(module_name) { + module.local_extensible_predicates.get_mut( + &(local_compilation_target, key), + ) + } else { + None + } + } + }, + } + } + + pub fn get_local_predicate_skeleton( + &self, + src_compilation_target: &CompilationTarget, + local_compilation_target: CompilationTarget, + key: PredicateKey, + ) -> Option<&PredicateSkeleton> { + match (key.0.as_str(), key.1) { + ("term_expansion", 2) => { + self.local_extensible_predicates.get( + &(local_compilation_target, key), + ) + } + _ => match src_compilation_target { + CompilationTarget::User => { + self.local_extensible_predicates.get( + &(local_compilation_target, key), + ) + } + CompilationTarget::Module(ref module_name) => { + if let Some(module) = self.modules.get(module_name) { + module.local_extensible_predicates.get( + &(local_compilation_target, key), + ) + } else { + None + } + } + }, + } + } + pub fn get_predicate_skeleton( &self, compilation_target: &CompilationTarget, @@ -767,18 +831,20 @@ impl IndexStore { &mut self, compilation_target: &CompilationTarget, key: &PredicateKey, - ) { + ) -> Option { match (key.0.as_str(), key.1) { ("term_expansion", 2) => { - self.extensible_predicates.remove(key); + self.extensible_predicates.remove(key) } _ => match compilation_target { CompilationTarget::User => { - self.extensible_predicates.remove(key); + self.extensible_predicates.remove(key) } CompilationTarget::Module(ref module_name) => { if let Some(module) = self.modules.get_mut(module_name) { - module.extensible_predicates.remove(key); + module.extensible_predicates.remove(key) + } else { + None } } }, diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 38ecd285..8360b3fe 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -412,9 +412,15 @@ impl Machine { fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) { match code_ptr { + REPLCodePtr::AddDiscontiguousPredicate => { + self.add_discontiguous_predicate(); + } REPLCodePtr::AddDynamicPredicate => { self.add_dynamic_predicate(); } + REPLCodePtr::AddMultifilePredicate => { + self.add_multifile_predicate(); + } REPLCodePtr::AddGoalExpansionClause => { self.add_goal_expansion_clause(); } diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index 6e055134..bbc99c22 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -394,9 +394,6 @@ fn merge_clauses(tls: &mut VecDeque) -> Result { return Ok(tl); } - TopLevel::Declaration(_) if clauses.is_empty() => { - return Ok(tl); - } TopLevel::Query(_) => { return Err(CompilationError::InconsistentEntry); } @@ -409,10 +406,6 @@ fn merge_clauses(tls: &mut VecDeque) -> Result clauses.extend(predicate.into_iter()), - _ => { - tls.push_front(tl); - break; - } } } @@ -497,7 +490,7 @@ fn check_for_internal_if_then(terms: &mut Vec) { } } -fn setup_declaration<'a>( +pub(super) fn setup_declaration<'a>( load_state: &LoadState<'a>, mut terms: Vec>, ) -> Result { @@ -883,8 +876,6 @@ impl Preprocessor { terms, cut_context, )?)) - } else if name.as_str() == ":-" && terms.len() == 1 { - Ok(TopLevel::Declaration(setup_declaration(load_state, terms)?)) } else { let term = Term::Clause(r, name, terms, fixity); Ok(TopLevel::Fact(self.setup_fact(term)?)) diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs index 21a30e29..6a23ff66 100644 --- a/src/machine/term_stream.rs +++ b/src/machine/term_stream.rs @@ -2,7 +2,6 @@ use prolog_parser::ast::*; use prolog_parser::parser::*; use crate::machine::machine_errors::CompilationError; -use crate::machine::preprocessor::*; use crate::machine::*; use indexmap::IndexSet; @@ -100,7 +99,6 @@ pub struct LoadStatePayload { pub(super) retraction_info: RetractionInfo, pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>, pub(super) non_counted_bt_preds: IndexSet, - pub(super) preprocessor: Preprocessor, pub(super) predicates: PredicateQueue, pub(super) clause_clauses: Vec<(Term, Term)>, } @@ -119,7 +117,6 @@ impl LoadStatePayload { retraction_info: RetractionInfo::new(wam.code_repo.code.len()), module_op_exports: vec![], non_counted_bt_preds: IndexSet::new(), - preprocessor: Preprocessor::new(wam.machine_st.flags), predicates: predicate_queue![], clause_clauses: vec![], } diff --git a/src/write.rs b/src/write.rs index dacf0ed9..95e9160c 100644 --- a/src/write.rs +++ b/src/write.rs @@ -2,6 +2,7 @@ use crate::clause_types::*; use crate::forms::*; use crate::indexing::IndexingCodePtr; use crate::instructions::*; +use crate::machine::loader::CompilationTarget; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; @@ -20,8 +21,12 @@ impl fmt::Display for LocalCodePtr { impl fmt::Display for REPLCodePtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + REPLCodePtr::AddDiscontiguousPredicate => + write!(f, "REPLCodePtr::AddDiscontiguousPredicate"), REPLCodePtr::AddDynamicPredicate => write!(f, "REPLCodePtr::AddDynamicPredicate"), + REPLCodePtr::AddMultifilePredicate => + write!(f, "REPLCodePtr::AddMultifilePredicate"), REPLCodePtr::AddGoalExpansionClause => write!(f, "REPLCodePtr::AddGoalExpansionClause"), REPLCodePtr::AddTermExpansionClause => @@ -88,6 +93,15 @@ impl fmt::Display for IndexPtr { } } +impl fmt::Display for CompilationTarget { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + CompilationTarget::User => write!(f, "user"), + CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name), + } + } +} + impl fmt::Display for FactInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -404,6 +418,10 @@ impl fmt::Display for SessionError { write!(f, "modules ({}, in this case) cannot import themselves.", module_name) } + &SessionError::PredicateNotMultifileOrDiscontiguous(ref compilation_target, ref key) => { + write!(f, "module {} does not define {}/{} as multifile or discontiguous.", + compilation_target.module_name(), key.0, key.1) + } } } }