]> Repositorios git - scryer-prolog.git/commitdiff
support discontiguous and multifile declarations
authorMark Thom <[email protected]>
Wed, 17 Feb 2021 03:54:51 +0000 (20:54 -0700)
committerMark Thom <[email protected]>
Wed, 17 Feb 2021 05:08:32 +0000 (22:08 -0700)
12 files changed:
src/clause_types.rs
src/forms.rs
src/loader.pl
src/machine/compile.rs
src/machine/load_state.rs
src/machine/loader.rs
src/machine/machine_errors.rs
src/machine/machine_indices.rs
src/machine/mod.rs
src/machine/preprocessor.rs
src/machine/term_stream.rs
src/write.rs

index 33294fa48fdceb9b5be0971e0ec1ef1cd09ae1ff..660a74a8d487a1bb9ba256a6f0d0de78acfef90e 100644 (file)
@@ -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<SystemClauseType> {
         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))
             }
index fc63e7e51604a9e6de2fdfb0aeb1e8ec4e5c59b1..ad401cd4db8be7f4c672a90a0650710125e2234f 100644 (file)
@@ -28,7 +28,6 @@ pub type JumpStub = Vec<Term>;
 
 #[derive(Debug, Clone)]
 pub enum TopLevel {
-    Declaration(Declaration),
     Fact(Term), // Term, line_num, col_num
     Predicate(Predicate),
     Query(Vec<QueryTerm>),
@@ -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<ClauseName> {
-        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<usize> 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<ClauseIndexInfo>,
     pub clause_clause_locs: SliceDeque<usize>,
+    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<usize> {
+        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()
+        }
     }
 }
index 475bb4b7cbe0d8eb3c52f65528586557fad61fbe..548d0e46f61f0e13a5440fe33db43bd6b27bb560 100644 (file)
@@ -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) ->
index e75259a60eefbb263ff651e46f15ba9b075aec8e..3c7f9eb8fcc500b1ff0cee7cb24388dc3f63c2b0 100644 (file)
@@ -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<Code, CompilationError> {
     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<TopLevel>,
+    mut queue: VecDeque<TopLevel>,
     jmp_by_locs: Vec<usize>,
     non_counted_bt: bool,
     atom_tbl: TabledData<Atom>,
 ) -> 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::<DebrayAllocator>::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<TopLevel>,
-    settings: CodeGenSettings,
-    atom_tbl: TabledData<Atom>,
-) -> Result<StandaloneCompileResult, SessionError> {
-    let mut cg = CodeGenerator::<DebrayAllocator>::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<IndexPtr>,
     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<Atom>,
+    ) -> Result<StandaloneCompileResult, SessionError> {
+        let mut preprocessor = Preprocessor::new(self.wam.machine_st.flags);
+        let mut cg = CodeGenerator::<DebrayAllocator>::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<PredicateClause>,
-        queue: &VecDeque<TopLevel>,
+        predicates: &mut PredicateQueue,
         settings: CodeGenSettings,
-    ) -> Result<IndexPtr, SessionError> {
+    ) -> 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::<DebrayAllocator>::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<TopLevel>,
+        clause: Term,
         compilation_target: CompilationTarget,
         non_counted_bt: bool,
         append_or_prepend: AppendOrPrepend,
-    ) -> Result<IndexPtr, SessionError> {
+    ) -> 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(())
     }
 }
index 81427d05d918a8395bd99e8faa6233126de0d7b3..c0e224739c0620cc6931cf2902e18337153c198b 100644 (file)
@@ -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<usize>,
     ) {
-        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<Option<usize>>,
+    ) {
+        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<usize>,
+    ) {
+        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<PredicateClause, SessionError> {
+        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
             }
index 7046fa1e296de01c186dac627a2805298d9dfe74..3ece45bafa2c4f2f2474f88930ff129d036b3a06 100644 (file)
@@ -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<MetaSpec>),
     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<IndexingLine>),
+    RemovedLocalSkeletonClauseLocations(
+        CompilationTarget,
+        CompilationTarget,
+        PredicateKey,
+        SliceDeque<usize>,
+    ),
+    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<PredicateClause>,
+    pub(super) predicates: Vec<Term>,
     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<Item = PredicateClause>) {
-        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<PredicateKey>,
-    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<LiveTermStream>, 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,
index 2e3b5e91e2ee27d50746bd346a3f89a51792df65..c446107f5a1b6566e7f7f13b7d3534acb4a220d3 100644 (file)
@@ -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,
 }
 
index 4b4a4c18a6c63f1dd91ccc6abb75d809394c6472..2d0556d3d745270e306b33895c6b659fd160ebbf 100644 (file)
@@ -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<PredicateSkeleton> {
         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
                     }
                 }
             },
index 38ecd2859ec56c6af803b9dcdd9d3fd6dd59614b..8360b3fe9e4007ba17f9c234f03fb1e5cb358de1 100644 (file)
@@ -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();
             }
index 6e05513410d970a7573d47f28d87dc667c38cbb6..bbc99c22ee06ac4c7373e0abd8c25b0c46c1b2ec 100644 (file)
@@ -394,9 +394,6 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationEr
             TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => {
                 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<TopLevel>) -> Result<TopLevel, CompilationEr
                 clauses.push(clause);
             }
             TopLevel::Predicate(predicate) => clauses.extend(predicate.into_iter()),
-            _ => {
-                tls.push_front(tl);
-                break;
-            }
         }
     }
 
@@ -497,7 +490,7 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
     }
 }
 
-fn setup_declaration<'a>(
+pub(super) fn setup_declaration<'a>(
     load_state: &LoadState<'a>,
     mut terms: Vec<Box<Term>>,
 ) -> Result<Declaration, CompilationError> {
@@ -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)?))
index 21a30e299d9f5acb763e979bf6cbd20e80612b96..6a23ff664bba411e2a4e6d116b601c0f324645c4 100644 (file)
@@ -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<PredicateKey>,
-    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![],
         }
index dacf0ed94434aa2953f6f5f17de1b0ca06160916..95e9160cbbffab89836531715383b834f7bfc5f0 100644 (file)
@@ -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)
+            }
         }
     }
 }