]> Repositorios git - scryer-prolog.git/commitdiff
do not add expansions behind module boundaries until the modules are added
authorMark Thom <[email protected]>
Fri, 4 Jan 2019 02:43:50 +0000 (19:43 -0700)
committerMark Thom <[email protected]>
Fri, 4 Jan 2019 02:43:50 +0000 (19:43 -0700)
src/prolog/compile.rs
src/prolog/instructions.rs
src/prolog/machine/mod.rs
src/prolog/machine/term_expansion.rs
src/prolog/macros.rs
src/prolog/toplevel.rs

index 20aef0a521d052aee2f079c2c8eccd719cd2cfef..7cd4e2c5957cfd7df35f659436275f21dee9b94c 100644 (file)
@@ -5,6 +5,7 @@ use prolog::instructions::*;
 use prolog::debray_allocator::*;
 use prolog::codegen::*;
 use prolog::machine::*;
+use prolog::machine::term_expansion::{ExpansionAdditionResult, TermStream};
 use prolog::toplevel::*;
 
 use std::collections::{HashMap, HashSet, VecDeque};
@@ -87,6 +88,30 @@ pub fn compile_appendix(code: &mut Code, queue: &VecDeque<TopLevel>, non_counted
     Ok(())
 }
 
+impl CodeRepo {
+    pub fn compile_hook(&mut self, hook: CompileTimeHook, flags: MachineFlags)
+                        -> Result<(), ParserError>
+    {
+        let key = (hook.name(), hook.arity());
+        match self.term_dir.get(&key) {
+            Some(preds) => {
+                let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
+                let mut code = cg.compile_predicate(&(preds.0).0)?;
+                
+                compile_appendix(&mut code, &preds.1, false, flags)?;
+                
+                Ok(match hook {
+                    CompileTimeHook::TermExpansion =>
+                        self.term_expanders = code,
+                    CompileTimeHook::GoalExpansion =>
+                        self.goal_expanders = code
+                })
+            },
+            None => Ok(())
+        }
+    }
+}
+
 fn compile_query(terms: Vec<QueryTerm>, queue: VecDeque<TopLevel>, flags: MachineFlags)
                  -> Result<(Code, AllocVarDict), ParserError>
 {
@@ -136,7 +161,8 @@ pub fn compile_term(wam: &mut Machine, term: Term) -> EvalSession
 struct GatherResult {
     worker_results: Vec<(Predicate, VecDeque<TopLevel>)>,
     toplevel_results: Vec<(Predicate, VecDeque<TopLevel>)>,
-    toplevel_indices: IndexStore
+    toplevel_indices: IndexStore,
+    addition_results: ExpansionAdditionResult
 }
 
 pub struct ListingCompiler {
@@ -152,17 +178,19 @@ impl ListingCompiler {
         }
     }
 
-    fn use_module(&mut self, submodule: ClauseName, wam_indices: &mut IndexStore, indices: &mut IndexStore)
+    fn use_module(&mut self, submodule: ClauseName, code_repo: &mut CodeRepo,
+                  flags: MachineFlags, wam_indices: &mut IndexStore,
+                  indices: &mut IndexStore)
                   -> Result<(), SessionError>
     {
         let mod_name = self.get_module_name();
 
         if let Some(submodule) = wam_indices.take_module(submodule) {
-            indices.use_module(&submodule)?;
+            indices.use_module(code_repo, flags, &submodule)?;
 
             if let &mut Some(ref mut module) = &mut self.module {
                 module.remove_module(mod_name, &submodule);
-                module.use_module(&submodule)?;
+                module.use_module(code_repo, flags, &submodule)?;
             } else {
                 wam_indices.remove_module(clause_name!("user"), &submodule);
             }
@@ -173,18 +201,19 @@ impl ListingCompiler {
         }
     }
 
-    fn use_qualified_module(&mut self, submodule: ClauseName, exports: &Vec<PredicateKey>,
+    fn use_qualified_module(&mut self, submodule: ClauseName, code_repo: &mut CodeRepo,
+                            flags: MachineFlags, exports: &Vec<PredicateKey>,
                             wam_indices: &mut IndexStore, indices: &mut IndexStore)
                             -> Result<(), SessionError>
     {
         let mod_name = self.get_module_name();
 
         if let Some(submodule) = wam_indices.take_module(submodule) {
-            indices.use_qualified_module(&submodule, exports)?;
+            indices.use_qualified_module(code_repo, flags, &submodule, exports)?;
 
             if let &mut Some(ref mut module) = &mut self.module {
                 module.remove_module(mod_name, &submodule);
-                module.use_qualified_module(&submodule, exports)?;
+                module.use_qualified_module(code_repo, flags, &submodule, exports)?;
             } else {
                 wam_indices.remove_module(clause_name!("user"), &submodule);
             }
@@ -262,32 +291,26 @@ impl ListingCompiler {
         match decl {
             Declaration::Hook(hook, clause, queue) => {
                 let key = (hook.name(), hook.arity());
-                let preds = code_repo.term_dir.entry(key)
-                    .or_insert((Predicate(vec![]), VecDeque::from(vec![])));
 
-                (preds.0).0.push(clause);
-                preds.1.extend(queue.into_iter());
-                
-                let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
-                let mut code = cg.compile_predicate(&(preds.0).0)?;
-
-                compile_appendix(&mut code, &preds.1, false, flags)?;
-
-                match hook {
-                    CompileTimeHook::TermExpansion =>
-                        Ok(code_repo.term_expanders = code),
-                    CompileTimeHook::GoalExpansion =>
-                        Ok(code_repo.goal_expanders = code)
+                {
+                    let preds = code_repo.term_dir.entry(key)
+                        .or_insert((Predicate(vec![]), VecDeque::from(vec![])));
+                    
+                    (preds.0).0.push(clause);
+                    preds.1.extend(queue.into_iter());
                 }
+                
+                code_repo.compile_hook(hook, flags)
+                         .map_err(SessionError::from)
             },
             Declaration::NonCountedBacktracking(name, arity) =>
                 Ok(self.add_non_counted_bt_flag(name, arity)),
             Declaration::Op(op_decl) =>
                 op_decl.submit(self.get_module_name(), &mut indices.op_dir),
             Declaration::UseModule(name) =>
-                self.use_module(name, wam_indices, indices),
+                self.use_module(name, code_repo, flags, wam_indices, indices),
             Declaration::UseQualifiedModule(name, exports) =>
-                self.use_qualified_module(name, &exports, wam_indices, indices),
+                self.use_qualified_module(name, code_repo, flags, &exports, wam_indices, indices),
             Declaration::Module(module_decl) =>
                 if self.module.is_none() {
                     let module_name = module_decl.name.clone();
@@ -300,6 +323,20 @@ impl ListingCompiler {
         }
     }
 
+    fn process_and_commit_decl<'a, R: Read>(&mut self, decl: Declaration,
+                                            term_stream: &mut TermStream<'a, R>,
+                                            indices: &mut IndexStore, flags: MachineFlags)
+                                            -> Result<(), SessionError>
+    {
+        match &decl {
+            &Declaration::Hook(hook, _, ref queue) if self.module.is_none() =>
+                term_stream.incr_expansion_lens(hook, 1, queue.len()),            
+            _ => {}
+        };
+
+        self.process_decl(decl, term_stream.code_repo, term_stream.indices, indices, flags)
+    }
+    
     fn gather_items<R: Read>(&mut self, wam: &mut Machine, src: R, indices: &mut IndexStore)
                              -> Result<GatherResult, SessionError>
     {
@@ -321,24 +358,25 @@ impl ListingCompiler {
                 mem::swap(&mut worker.results, &mut toplevel_results);
                 worker.in_module = true;
 
-                self.process_decl(decl, worker.term_stream.code_repo,
-                                  worker.term_stream.indices,
-                                  indices, flags)?;
+                self.process_and_commit_decl(decl, &mut worker.term_stream,
+                                             indices, flags)?;
 
                 if let &Some(ref module) = &self.module {
                     worker.term_stream.set_atom_tbl(module.atom_tbl.clone());
                 }
             } else {
-                self.process_decl(decl, worker.term_stream.code_repo,
-                                  worker.term_stream.indices,
-                                  indices, flags)?;
+                self.process_and_commit_decl(decl, &mut worker.term_stream,
+                                             indices, flags)?;
             }
         }
 
+        let addition_results = worker.term_stream.rollback_expansion_code()?;
+
         Ok(GatherResult {
             worker_results: worker.results,
             toplevel_results,
-            toplevel_indices
+            toplevel_indices,
+            addition_results
         })
     }
 }
@@ -354,15 +392,24 @@ fn compile_listing<R: Read>(wam: &mut Machine, src: R, mut indices: IndexStore)
     let toplvl_code = try_eval_session!(compiler.generate_code(results.toplevel_results, wam,
                                                                &mut results.toplevel_indices.code_dir));
 
+    if let Some(ref mut module) = &mut compiler.module {
+        module.term_expansions = results.addition_results.take_term_expansions();
+        module.goal_expansions = results.addition_results.take_goal_expansions();
+    }
+    
     try_eval_session!(compiler.add_code(wam, module_code, indices));
     try_eval_session!(compiler.add_code(wam, toplvl_code, results.toplevel_indices));
   
     EvalSession::EntrySuccess
 }
 
-fn setup_indices(wam: &Machine, indices: &mut IndexStore) -> Result<(), SessionError> {
-    if let Some(ref builtins) = wam.indices.modules.get(&clause_name!("builtins")) {
-        indices.use_module(builtins)
+fn setup_indices(wam: &mut Machine, indices: &mut IndexStore) -> Result<(), SessionError> {
+    if let Some(builtins) = wam.indices.take_module(clause_name!("builtins")) {
+        let flags  = wam.machine_flags();
+        let result = indices.use_module(&mut wam.code_repo, flags, &builtins);
+
+        wam.indices.insert_module(builtins);
+        result
     } else {
         Err(SessionError::ModuleNotFound)
     }
@@ -370,6 +417,6 @@ fn setup_indices(wam: &Machine, indices: &mut IndexStore) -> Result<(), SessionE
 
 pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession {
     let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
-    try_eval_session!(setup_indices(&wam, &mut indices));
+    try_eval_session!(setup_indices(wam, &mut indices));
     compile_listing(wam, src, indices)
 }
index 0c3444d0cb83173c5eb43435239a28ebe64b7d2f..43c1fd5521d80c532ab047f7498903993b7f3942 100644 (file)
@@ -125,6 +125,7 @@ impl CompareTermQT {
 // of vars (we get their adjoining cells this way).
 pub type JumpStub = Vec<Term>;
 
+#[derive(Clone)]
 pub enum QueryTerm {
     // register, clause type, subterms, use default call policy.
     Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>, bool),
@@ -152,19 +153,26 @@ impl QueryTerm {
     }
 }
 
+#[derive(Clone)]
 pub struct Rule {
     pub head: (ClauseName, Vec<Box<Term>>, QueryTerm),
     pub clauses: Vec<QueryTerm>
 }
 
+#[derive(Clone)]
 pub struct Predicate(pub Vec<PredicateClause>);
 
 impl Predicate {
+    pub fn new() -> Self {
+        Predicate(vec![])
+    }
+
     pub fn clauses(self) -> Vec<PredicateClause> {
         self.0
     }
 }
 
+#[derive(Clone)]
 pub enum PredicateClause {
     Fact(Term),
     Rule(Rule)
@@ -203,6 +211,16 @@ pub type ModuleDir = HashMap<ClauseName, Module>;
 
 pub type PredicateKey = (ClauseName, usize); // name, arity.
 
+pub struct CodeRepo {
+    pub(super) cached_query: Code,
+    pub(super) goal_expanders: Code,
+    pub(super) term_expanders: Code,
+    pub(super) code: Code,
+    pub(super) in_situ_code: Code,
+    pub(super) term_dir: TermDir
+}
+
+#[derive(Clone)]
 pub struct ModuleDecl {
     pub name: ClauseName,
     pub exports: Vec<PredicateKey>
@@ -212,7 +230,9 @@ pub struct Module {
     pub atom_tbl: TabledData<Atom>,
     pub module_decl: ModuleDecl,
     pub code_dir: ModuleCodeDir,
-    pub op_dir: OpDir
+    pub op_dir: OpDir,
+    pub term_expansions: (Predicate, VecDeque<TopLevel>),
+    pub goal_expansions: (Predicate, VecDeque<TopLevel>),
 }
 
 #[derive(Copy, Clone, PartialEq)]
@@ -1074,9 +1094,36 @@ impl<'a> TermIterState<'a> {
 impl Module {
     pub fn new(module_decl: ModuleDecl, atom_tbl: TabledData<Atom>) -> Self {
         Module { module_decl, atom_tbl,
+                 term_expansions: (Predicate::new(), VecDeque::from(vec![])),
+                 goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
                  code_dir: ModuleCodeDir::new(),
                  op_dir: default_op_dir() }
     }
+
+    pub fn dump_expansions(&self, code_repo: &mut CodeRepo, flags: MachineFlags)
+                           -> Result<(), ParserError>
+    {
+        {
+            let te = code_repo.term_dir.entry((clause_name!("term_expansion"), 2))
+                .or_insert((Predicate::new(), VecDeque::from(vec![])));
+
+            (te.0).0.extend((self.term_expansions.0).0.iter().cloned());
+            te.1.extend(self.term_expansions.1.iter().cloned());
+        }
+
+        {
+            let ge = code_repo.term_dir.entry((clause_name!("goal_expansion"), 2))
+                .or_insert((Predicate::new(), VecDeque::from(vec![])));
+            
+            (ge.0).0.extend((self.goal_expansions.0).0.iter().cloned());
+            ge.1.extend(self.goal_expansions.1.iter().cloned());
+        }
+
+        code_repo.compile_hook(CompileTimeHook::TermExpansion, flags)?;
+        code_repo.compile_hook(CompileTimeHook::GoalExpansion, flags)?;
+
+        Ok(())
+    }
 }
 
 pub fn as_module_code_dir(code_dir: CodeDir) -> ModuleCodeDir {
@@ -1171,31 +1218,39 @@ pub trait SubModuleUser {
         }
     }
 
-    fn use_qualified_module(&mut self, submodule: &Module, exports: &Vec<PredicateKey>)
-                            -> Result<(), SessionError>
-    {
-        for (name, arity) in exports.iter().cloned() {
-            if !submodule.module_decl.exports.contains(&(name.clone(), arity)) {
-                continue;
-            }
+    fn use_qualified_module(&mut self, &mut CodeRepo, MachineFlags, &Module, &Vec<PredicateKey>)
+                            -> Result<(), SessionError>;
+    fn use_module(&mut self, &mut CodeRepo, MachineFlags, &Module)
+                  -> Result<(), SessionError>;
+}
 
-            if !self.import_decl(name, arity, submodule) {
-                return Err(SessionError::ModuleDoesNotContainExport);
-            }
+pub fn use_qualified_module<User>(user: &mut User, submodule: &Module, exports: &Vec<PredicateKey>)
+                              -> Result<(), SessionError>
+  where User: SubModuleUser
+{
+    for (name, arity) in exports.iter().cloned() {
+        if !submodule.module_decl.exports.contains(&(name.clone(), arity)) {
+            continue;
         }
 
-        Ok(())
+        if !user.import_decl(name, arity, submodule) {
+            return Err(SessionError::ModuleDoesNotContainExport);
+        }
     }
 
-    fn use_module(&mut self, submodule: &Module) -> Result<(), SessionError> {
-        for (name, arity) in submodule.module_decl.exports.iter().cloned() {
-            if !self.import_decl(name, arity, submodule) {
-                return Err(SessionError::ModuleDoesNotContainExport);
-            }
-        }
+    Ok(())
+}
 
-        Ok(())
+pub fn use_module<User: SubModuleUser>(user: &mut User, submodule: &Module)
+                                       -> Result<(), SessionError>
+{
+    for (name, arity) in submodule.module_decl.exports.iter().cloned() {
+        if !user.import_decl(name, arity, submodule) {
+            return Err(SessionError::ModuleDoesNotContainExport);
+        }
     }
+
+    Ok(())
 }
 
 impl SubModuleUser for Module {
@@ -1215,12 +1270,41 @@ impl SubModuleUser for Module {
         self.code_dir.remove(&key);
     }
 
-    fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex)
-    {
+    fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: ModuleCodeIndex) {
         self.code_dir.insert((name, arity), idx);
     }
+
+    fn use_qualified_module(&mut self, _: &mut CodeRepo, _: MachineFlags, submodule: &Module,
+                            exports: &Vec<PredicateKey>)
+                            -> Result<(), SessionError>
+    {
+        use_qualified_module(self, submodule, exports)?;
+
+        (self.term_expansions.0).0.extend((submodule.term_expansions.0).0.iter().cloned());
+        self.term_expansions.1.extend(submodule.term_expansions.1.iter().cloned());
+
+        (self.goal_expansions.0).0.extend((submodule.goal_expansions.0).0.iter().cloned());
+        self.goal_expansions.1.extend(submodule.goal_expansions.1.iter().cloned());
+
+        Ok(())
+    }
+
+    fn use_module(&mut self, _: &mut CodeRepo, _: MachineFlags, submodule: &Module)
+                  -> Result<(), SessionError>
+    {
+        use_module(self, submodule)?;
+
+        (self.term_expansions.0).0.extend((submodule.term_expansions.0).0.iter().cloned());
+        self.term_expansions.1.extend(submodule.term_expansions.1.iter().cloned());
+
+        (self.goal_expansions.0).0.extend((submodule.goal_expansions.0).0.iter().cloned());
+        self.goal_expansions.1.extend(submodule.goal_expansions.1.iter().cloned());
+
+        Ok(())
+    }
 }
 
+#[derive(Clone)]
 pub enum Declaration {
     Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>),
     Module(ModuleDecl),
@@ -1237,6 +1321,7 @@ impl Declaration {
     }
 }
 
+#[derive(Clone)]
 pub enum TopLevel {
     Declaration(Declaration),
     Fact(Term),
@@ -1388,6 +1473,7 @@ impl From<ParserError> for EvalSession {
     }
 }
 
+#[derive(Clone)]
 pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
 
 impl OpDecl {
index ae3c379d44bc94768533a4e735c6aa7c40cb7f89..8ca220d3bd3c0591927cfc3011575559930620fc 100644 (file)
@@ -30,7 +30,7 @@ pub struct IndexStore {
     pub(super) code_dir: CodeDir,
     pub(super) in_situ_code_dir: InSituCodeDir,
     pub(super) op_dir: OpDir,
-    pub(super) modules: ModuleDir
+    pub(super) modules: ModuleDir,
 }
 
 enum RefOrOwned<'a, T: 'a> {
@@ -108,16 +108,7 @@ impl IndexStore {
 
 pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
 
-pub struct CodeRepo {
-    cached_query: Code,
-    pub(super) goal_expanders: Code,
-    pub(super) term_expanders: Code,
-    pub(super) code: Code,
-    pub(super) in_situ_code: Code,
-    pub(super) term_dir: TermDir
-}
-
-impl CodeRepo {
+impl CodeRepo {       
     #[inline]
     fn new() -> Self {
         CodeRepo {
@@ -130,6 +121,25 @@ impl CodeRepo {
         }
     }
 
+    #[inline]
+    pub fn term_dir_entry_len(&self, key: PredicateKey) -> (usize, usize) {
+        self.term_dir.get(&key)
+            .map(|entry| ((entry.0).0.len(), entry.1.len()))
+            .unwrap_or((0,0))
+    }
+
+    #[inline]
+    pub fn truncate_terms(&mut self, key: PredicateKey, len: usize, queue_len: usize) 
+                          -> (Predicate, VecDeque<TopLevel>)
+    {
+        //TODO: fix this! this is causing a test to fail. because term_expansions, when
+        //removed by rollback_expansion_code, aren't jump-labeled properly by generate_code.
+        self.term_dir.get_mut(&key)
+            .map(|entry| (Predicate((entry.0).0.clone()[len ..].to_vec()), //drain(len ..).collect()),
+                          entry.1.drain(queue_len ..).collect()))
+            .unwrap_or((Predicate(vec![]), VecDeque::from(vec![])))
+    }    
+
     pub fn add_in_situ_result(&mut self, result: &CompiledResult, in_situ_code_dir: &mut InSituCodeDir,
                               flags: MachineFlags)
                               -> Result<(), SessionError>
@@ -276,6 +286,21 @@ impl SubModuleUser for IndexStore {
 
         self.code_dir.insert((name, arity), CodeIndex::from(idx));
     }
+
+    fn use_qualified_module(&mut self, code_repo: &mut CodeRepo, flags: MachineFlags,
+                            submodule: &Module, exports: &Vec<PredicateKey>)
+                            -> Result<(), SessionError>
+    {
+        use_qualified_module(self, submodule, exports)?;
+        submodule.dump_expansions(code_repo, flags).map_err(SessionError::from)
+    }
+    
+    fn use_module(&mut self, code_repo: &mut CodeRepo, flags: MachineFlags, submodule: &Module)
+                  -> Result<(), SessionError>
+    {
+        use_module(self, submodule)?;
+        submodule.dump_expansions(code_repo, flags).map_err(SessionError::from)
+    }
 }
 
 static LISTS: &str   = include_str!("../lib/lists.pl");
index cb3054811e3bfc4df14dec5b5dcbb95f9b0964fd..4d64f9e8c0a4bc6cbd67fb7acb838829223b85a0 100644 (file)
@@ -50,6 +50,24 @@ pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
     term
 }
 
+fn extract_from_list(head: Box<Term>, tail: Box<Term>)
+                     -> Result<Rev<IntoIter<Term>>, ParserError>
+{
+    let mut terms = vec![*head];
+    let mut tail  = *tail;
+
+    while let Term::Cons(_, head, next_tail) = tail {
+        terms.push(*head);
+        tail = *next_tail;
+    }
+
+    if let Term::Constant(_, Constant::EmptyList) = tail {
+        Ok(terms.into_iter().rev())
+    } else {
+        Err(ParserError::ExpectedTopLevelTerm)
+    }
+}
+
 pub struct TermStream<'a, R: Read> {
     stack: Vec<Term>,
     pub(crate) indices: &'a mut IndexStore,
@@ -57,13 +75,37 @@ pub struct TermStream<'a, R: Read> {
     pub(crate) code_repo: &'a mut CodeRepo,
     parser: Parser<R>,
     in_module: bool,
-    pub(crate) flags: MachineFlags
+    pub(crate) flags: MachineFlags,
+    term_expansion_lens: (usize, usize),
+    goal_expansion_lens: (usize, usize),
+}
+
+pub struct ExpansionAdditionResult {
+    term_expansion_additions: (Predicate, VecDeque<TopLevel>),
+    goal_expansion_additions: (Predicate, VecDeque<TopLevel>)
+}
+
+impl ExpansionAdditionResult {
+    pub fn take_term_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
+        let tes  = mem::replace(&mut self.term_expansion_additions.0, Predicate::new());
+        let teqs = mem::replace(&mut self.term_expansion_additions.1, VecDeque::from(vec![]));
+
+        (tes, teqs)
+    }
+
+    pub fn take_goal_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
+        let ges  = mem::replace(&mut self.goal_expansion_additions.0, Predicate::new());
+        let geqs = mem::replace(&mut self.goal_expansion_additions.1, VecDeque::from(vec![]));
+
+        (ges, geqs)
+    }
 }
 
 impl<'a, R: Read> Drop for TermStream<'a, R> {
     fn drop(&mut self) {
         self.indices.in_situ_code_dir.clear();
-        self.code_repo.in_situ_code.clear();
+        self.code_repo.in_situ_code.clear();        
+        discard_result!(self.rollback_expansion_code());
     }
 }
 
@@ -75,15 +117,31 @@ impl<'a, R: Read> TermStream<'a, R> {
     {
         TermStream {
             stack: Vec::new(),
+            term_expansion_lens: code_repo.term_dir_entry_len((clause_name!("term_expansion"), 2)),
+            goal_expansion_lens: code_repo.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
+            code_repo,
             indices,
             policies,
-            code_repo,
             parser: Parser::new(src, atom_tbl, flags),
             in_module: false,
             flags
         }
     }
 
+    #[inline]
+    pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
+        match hook {
+            CompileTimeHook::TermExpansion => {
+                self.term_expansion_lens.0 += len;
+                self.term_expansion_lens.1 += queue_len;
+            },
+            CompileTimeHook::GoalExpansion => {
+                self.goal_expansion_lens.0 += len;
+                self.goal_expansion_lens.1 += queue_len;
+            }
+        }
+    }
+
     #[inline]
     pub fn set_atom_tbl(&mut self, atom_tbl: TabledData<Atom>) {
         self.parser.set_atom_tbl(atom_tbl);
@@ -99,28 +157,33 @@ impl<'a, R: Read> TermStream<'a, R> {
         Ok(self.stack.is_empty() && self.parser.eof()?)
     }
 
-    fn extract_from_list(&mut self, head: Box<Term>, tail: Box<Term>)
-                         -> Result<Rev<IntoIter<Term>>, ParserError>
-    {
-        let mut terms = vec![*head];
-        let mut tail  = *tail;
+    pub fn rollback_expansion_code(&mut self) -> Result<ExpansionAdditionResult, ParserError> {
+        let te_len = self.term_expansion_lens.0;
+        let te_queue_len = self.term_expansion_lens.1;
 
-        while let Term::Cons(_, head, next_tail) = tail {
-            terms.push(*head);
-            tail = *next_tail;
-        }
+        let ge_len = self.goal_expansion_lens.0;
+        let ge_queue_len = self.goal_expansion_lens.1;
 
-        if let Term::Constant(_, Constant::EmptyList) = tail {
-            Ok(terms.into_iter().rev())
-        } else {
-            Err(ParserError::ExpectedTopLevelTerm)
-        }
+        let term_expansion_additions =
+            self.code_repo.truncate_terms((clause_name!("term_expansion"), 2),
+                                          te_len, te_queue_len);
+        let goal_expansion_additions =
+            self.code_repo.truncate_terms((clause_name!("goal_expansion"), 2),
+                                          ge_len, ge_queue_len);
+
+        self.code_repo.compile_hook(CompileTimeHook::TermExpansion, self.flags)?;
+        self.code_repo.compile_hook(CompileTimeHook::GoalExpansion, self.flags)?;
+
+        Ok(ExpansionAdditionResult {
+            term_expansion_additions,
+            goal_expansion_additions
+        })
     }
 
     fn enqueue_term(&mut self, term: Term) -> Result<(), ParserError> {
         match term {
             Term::Cons(_, head, tail) => {
-                let iter = self.extract_from_list(head, tail)?;
+                let iter = extract_from_list(head, tail)?;
                 Ok(self.stack.extend(iter))
             },
             Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) =>
@@ -208,7 +271,7 @@ impl<'a, R: Read> TermStream<'a, R> {
 
                     match term {
                         Term::Cons(_, head, tail) =>
-                            for term in self.extract_from_list(head, tail)? {
+                            for term in extract_from_list(head, tail)? {
                                 terms.push_front(term);
                             },
                         term =>
index 28d23b20ad96495b59c51b2d100ed20723989534..47f7a13155e0b4c16a387351152c4bf8dd63c43e 100644 (file)
@@ -248,3 +248,11 @@ macro_rules! get_level_and_unify {
         Line::Cut(CutInstruction::GetLevelAndUnify($r))
     )
 }
+
+macro_rules! discard_result {
+    ($f: expr) => (
+        match $f {
+            _ => ()
+        }
+    )
+}
index d1f073695f77131a3c017460257e3ea4c42e43a7..ef8793a51f28488e11e2b840f2c9f44ec0ff30a3 100644 (file)
@@ -71,7 +71,7 @@ impl<'a, 'b> CompositeIndices<'a, 'b>
 }
 
 #[inline]
-fn get_compile_time_hook(name: &str, arity: usize) -> Option<CompileTimeHook> {
+fn as_compile_time_hook(name: &str, arity: usize) -> Option<CompileTimeHook> {
     match (name, arity) {
         ("term_expansion", 2) => Some(CompileTimeHook::TermExpansion),
         ("goal_expansion", 2) => Some(CompileTimeHook::GoalExpansion),
@@ -84,12 +84,12 @@ fn is_compile_time_hook(name: &ClauseName, terms: &Vec<Box<Term>>) -> Option<Com
     if name.as_str() == ":-" {
         if let Some(ref term) = terms.first() {
             if let &Term::Clause(_, ref name, ref terms, None) = term.as_ref() {
-                return get_compile_time_hook(name.as_str(), terms.len());
+                return as_compile_time_hook(name.as_str(), terms.len());
             }
         }
     }
     
-    get_compile_time_hook(name.as_str(), terms.len())    
+    as_compile_time_hook(name.as_str(), terms.len())    
 }
 
 type CompileTimeHookCompileInfo = (CompileTimeHook, PredicateClause, VecDeque<TopLevel>);