]> Repositorios git - scryer-prolog.git/commitdiff
add provisional module support.
authorMark Thom <[email protected]>
Sat, 3 Mar 2018 05:28:12 +0000 (22:28 -0700)
committerMark Thom <[email protected]>
Sat, 3 Mar 2018 05:28:12 +0000 (22:28 -0700)
21 files changed:
README.md
src/main.rs
src/prolog/allocator.rs
src/prolog/arithmetic.rs
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/codegen.rs
src/prolog/debray_allocator.rs
src/prolog/fixtures.rs
src/prolog/io.rs
src/prolog/iterators.rs
src/prolog/lib/control.pl
src/prolog/lib/lists.pl
src/prolog/machine/machine_state.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/prolog/macros.rs
src/prolog/mod.rs
src/prolog/parser
src/prolog/tabled_rc.rs
src/test_utils.rs

index 82fa08e0a25da74296aef30f9d8ecfb64fb76b3c..3b256fb54a5d32b7fe35c30285028d39f07efbb4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ Extend rusty-wam to include the following, among other features:
 * Built-in predicates for list processing and top-level declarative
   control (`setup_call_control/3`, `call_with_inference_limit/3`,
   etc.) (_done_).
-* A rudimentary module system.
+* A rudimentary module system (_in progress_).
 * Attributed variables using the SICStus Prolog interface and
   semantics. Adding coroutines like `dif/2`, `freeze/2`, etc.
   is straightforward with attributed variables.
@@ -102,6 +102,7 @@ The following predicates are built-in to rusty-wam.
 * `atomic/1`
 * `between/3`
 * `call/1..63`
+* `call_cleanup/2`
 * `call_with_inference_limit/3`
 * `catch/3`
 * `compare/3`
@@ -199,11 +200,31 @@ Note that the values of variables belonging to successful queries are
 printed out, on one line each. Uninstantiated variables are denoted by
 a number preceded by an underscore (`X = _0` in an example above).
 
-Lastly, rusty-wam supports dynamic operators. Using the built-in
+### Dynamic operators
+
+rusty-wam supports dynamic operators. Using the built-in
 arithmetic operators with the usual precedences,
 
 ```
 prolog> ?- display(-5 + 3 - (2 * 4) // 8).
 '-'('+'('-'(5), 3), '//'('*'(2, 4), 8))
 true.
+```
+
+New operators can be defined using the `op` declaration.
+
+### Modules
+
+rusty-wam has seemingly correct but presently untested support for a
+basic predicate-based module system. It provides a way to separate
+units of code into distinct namespaces, for both predicates and
+operators. See the files `src/prolog/lib/*.pl` for examples.
+
+At the time of this writing, several control and list processing
+operators are hidden within their own modules that have not
+been exported to the toplevel. To export them, write
+
+```
+prolog> :- use_module(library(lists)).
+prolog> :- use_module(library(control)).
 ```
\ No newline at end of file
index c7ae8b1d3bb571780aeef84c974f9b8248620d1c..4d99223ccd4b184485e4c54ed077e8f1661632d3 100644 (file)
@@ -5,6 +5,7 @@ extern crate termion;
 mod prolog;
 #[macro_use] mod test_utils;
 
+use prolog::ast::*;
 use prolog::io::*;
 use prolog::machine::*;
 
@@ -17,20 +18,20 @@ pub static CONTROL: &str = include_str!("./prolog/lib/control.pl");
 fn process_buffer(wam: &mut Machine, buffer: &str)
 {
     match parse_code(wam, buffer) {
-        Ok(tl) => {
-            let result = compile(wam, &tl);
+        Ok(packet) => {
+            let result = compile_packet(wam, packet);
             print(wam, result);
         },
         Err(s) => println!("{:?}", s)
-    };
+    }
 }
 
 fn load_init_str(wam: &mut Machine, src_str: &str)
 {
-    match parse_batch(wam, src_str) {
-        Ok(tls) => compile_batch(wam, &tls),
-        Err(_)  => panic!("failed to parse batch from string.")
-    };
+    match compile_listing(wam, src_str) {
+        EvalSession::Error(_) => panic!("failed to parse batch from string."),
+        _ => {}
+    }
 }
 
 fn prolog_repl() {
index cd9f523b11857978efc625a73244fc4a41d377cd..36b9cceb75a722b1f4764cd7abb109c796b350cc 100644 (file)
@@ -3,6 +3,7 @@ use prolog::fixtures::*;
 use prolog::targets::*;
 
 use std::cell::Cell;
+use std::rc::Rc;
 
 pub trait Allocator<'a>
 {
@@ -12,7 +13,7 @@ pub trait Allocator<'a>
         where Target: CompilationTarget<'a>;
     fn mark_non_var<Target>(&mut self, Level, GenContext, &'a Cell<RegType>, &mut Vec<Target>)
         where Target: CompilationTarget<'a>;
-    fn mark_var<Target>(&mut self, &'a Var, Level, &'a Cell<VarReg>, GenContext, &mut Vec<Target>)
+    fn mark_var<Target>(&mut self, Rc<Var>, Level, &'a Cell<VarReg>, GenContext, &mut Vec<Target>)
         where Target: CompilationTarget<'a>;    
     
     fn reset(&mut self);
@@ -21,10 +22,10 @@ pub trait Allocator<'a>
     
     fn advance_arg(&mut self);
 
-    fn bindings(&self) -> &AllocVarDict<'a>;
-    fn bindings_mut(&mut self) -> &mut AllocVarDict<'a>;
+    fn bindings(&self) -> &AllocVarDict;
+    fn bindings_mut(&mut self) -> &mut AllocVarDict;
 
-    fn take_bindings(self) -> AllocVarDict<'a>;
+    fn take_bindings(self) -> AllocVarDict;
 
     fn drain_var_data(&mut self, vs: VariableFixtures<'a>) -> VariableFixtures<'a>
     {
@@ -33,10 +34,10 @@ pub trait Allocator<'a>
         for (var, (var_status, cells)) in vs.into_iter() {
             match var_status {
                 VarStatus::Temp(chunk_num, tvd) => {
-                    self.bindings_mut().insert(var, VarData::Temp(chunk_num, 0, tvd));
+                    self.bindings_mut().insert(var.clone(), VarData::Temp(chunk_num, 0, tvd));
                 },
                 VarStatus::Perm(_) => {
-                    self.bindings_mut().insert(var, VarData::Perm(0));
+                    self.bindings_mut().insert(var.clone(), VarData::Perm(0));
                     perm_vs.insert(var, (var_status, cells));
                 }
             };
@@ -45,12 +46,12 @@ pub trait Allocator<'a>
         perm_vs
     }
     
-    fn get(&self, var: &'a Var) -> RegType {
-        self.bindings().get(var).unwrap().as_reg_type()
+    fn get(&self, var: Rc<Var>) -> RegType {
+        self.bindings().get(&var).unwrap().as_reg_type()
     }
     
-    fn record_register(&mut self, var: &'a Var, r: RegType) {
-        match self.bindings_mut().get_mut(var).unwrap() {
+    fn record_register(&mut self, var: Rc<Var>, r: RegType) {
+        match self.bindings_mut().get_mut(&var).unwrap() {
             &mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
             &mut VarData::Perm(ref mut s) => *s = r.reg_num()
         }
index ce3ce89e6ef60896f87d1fc459826c8dceb668bf..436772fcbeffae0f2af2c87e1faf0a17bcea96eb 100644 (file)
@@ -1,8 +1,8 @@
 use prolog::ast::*;
-use prolog::fixtures::*;
 
 use std::cell::Cell;
 use std::cmp::{min, max};
+use std::rc::Rc;
 use std::vec::Vec;
 
 pub struct ArithInstructionIterator<'a> {
@@ -31,7 +31,7 @@ impl<'a> ArithInstructionIterator<'a> {
             &Term::Cons(_, _, _) =>
                 return Err(ArithmeticError::InvalidTerm),
             &Term::Var(ref cell, ref var) =>
-                TermIterState::Var(Level::Shallow, cell, var)
+                TermIterState::Var(Level::Shallow, cell, (*var).clone())
         };
 
         Ok(ArithInstructionIterator { state_stack: vec![state] })
@@ -41,7 +41,7 @@ impl<'a> ArithInstructionIterator<'a> {
 pub enum ArithTermRef<'a> {
     Constant(&'a Constant),
     Op(ClauseName, usize), // name, arity.
-    Var(&'a Cell<VarReg>, &'a Var)
+    Var(&'a Cell<VarReg>, Rc<Var>)
 }
 
 impl<'a> Iterator for ArithInstructionIterator<'a> {
@@ -65,7 +65,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
                 TermIterState::Constant(_, _, c) =>
                     return Some(Ok(ArithTermRef::Constant(c))),
                 TermIterState::Var(_, cell, var) =>
-                    return Some(Ok(ArithTermRef::Var(cell, var))),
+                    return Some(Ok(ArithTermRef::Var(cell, var.clone()))),
                 _ =>
                     return Some(Err(ArithmeticError::InvalidTerm))
             };
@@ -76,7 +76,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
 }
 
 pub struct ArithmeticEvaluator<'a> {
-    bindings: &'a AllocVarDict<'a>,
+    bindings: &'a AllocVarDict,
     interm: Vec<ArithmeticTerm>,
     interm_c: usize
 }
@@ -97,7 +97,7 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
 
 impl<'a> ArithmeticEvaluator<'a>
 {
-    pub fn new(bindings: &'a AllocVarDict<'a>, target_int: usize) -> Self {
+    pub fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
         ArithmeticEvaluator { bindings, interm: Vec::new(), interm_c: target_int }
     }
 
@@ -207,7 +207,7 @@ impl<'a> ArithmeticEvaluator<'a>
                 ArithTermRef::Constant(c) => self.push_constant(c)?,
                 ArithTermRef::Var(cell, name) => {
                     let r = if cell.get().norm().reg_num() == 0 {
-                        match self.bindings.get(name) {
+                        match self.bindings.get(&name) {
                             Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
                             Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
                             _ => return Err(ArithmeticError::UninstantiatedVar)
index 9721aea18b28974dd998b69d74bb9f26907f9b24..b0bbc89959f3c2ccad41e77f02bae9af28ac086b 100644 (file)
@@ -6,7 +6,7 @@ use prolog::tabled_rc::*;
 
 use std::cell::Cell;
 use std::cmp::Ordering;
-use std::collections::{HashMap, VecDeque};
+use std::collections::{BTreeSet, HashMap, VecDeque};
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::io::Error as IOError;
@@ -66,8 +66,90 @@ impl PredicateClause {
     }
 }
 
+pub type OpDirKey = (ClauseName, Fixity);
+// name and fixity -> operator type and precedence.
+pub type OpDir = HashMap<OpDirKey, (Specifier, usize)>;
+
+pub type CodeDir = HashMap<PredicateKey, (PredicateKeyType, usize, ClauseName)>;
+
+pub type PredicateKey = (ClauseName, usize); // name, arity.
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub enum PredicateKeyType {
+    BuiltIn,
+    User
+}
+
+pub struct ModuleDecl {
+    pub name: ClauseName,
+    pub exports: Vec<PredicateKey>
+}
+
+pub struct Module {
+    pub module_decl: ModuleDecl,
+    pub code_dir: CodeDir,
+    pub op_dir: OpDir
+}
+
+impl Module {
+    pub fn new(module_decl: ModuleDecl) -> Self {
+        Module { module_decl,
+                 code_dir: CodeDir::new(),
+                 op_dir: OpDir::new() }
+    }
+}
+
+impl SubModuleUser for Module {
+    fn op_dir(&mut self) -> &mut OpDir {
+        &mut self.op_dir
+    }
+
+    fn code_dir(&mut self) -> &mut CodeDir {
+        &mut self.code_dir
+    }
+}
+
+pub trait SubModuleUser {
+    fn op_dir(&mut self) -> &mut OpDir;
+    fn code_dir(&mut self) -> &mut CodeDir;
+
+    fn use_module(&mut self, submodule: &Module) -> EvalSession {
+        for (name, arity) in submodule.module_decl.exports.iter().cloned() {
+            let name = name.defrock_brackets();
+            
+            if arity == 1 {
+                if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Pre)) {
+                    self.op_dir().insert((name.clone(), Fixity::Pre), op_data.clone());
+                }
+
+                if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Post)) {
+                    self.op_dir().insert((name.clone(), Fixity::Post), op_data.clone());
+                }
+            } else if arity == 2 {
+                if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::In)) {
+                    self.op_dir().insert((name.clone(), Fixity::In), op_data.clone());
+                }
+            }
+
+            if self.code_dir().contains_key(&(name.clone(), arity)) {
+                println!("warning: overwriting {}/{}", &name, arity);
+            }
+
+            if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
+                self.code_dir().insert((name, arity), code_data.clone());
+            } else {
+                return EvalSession::from(EvalError::ModuleDoesNotContainExport);
+            }
+        }
+
+        EvalSession::EntrySuccess
+    }
+}
+
 pub enum Declaration {
-    Op(usize, Specifier, ClauseName)
+    Module(ModuleDecl),
+    Op(OpDecl),
+    UseModule(ClauseName)
 }
 
 pub enum TopLevel {
@@ -233,6 +315,104 @@ macro_rules! prefix {
     ($x:expr) => ($x & (FX | FY))
 }
 
+// labeled with chunk numbers.
+pub enum VarStatus {
+    Perm(usize), Temp(usize, TempVarData) // Perm(chunk_num) | Temp(chunk_num, _)
+}
+
+pub type OccurrenceSet = BTreeSet<(GenContext, usize)>;
+
+// Perm: 0 initially, a stack register once processed.
+// Temp: labeled with chunk_num and temp offset (unassigned if 0).
+pub enum VarData {
+    Perm(usize), Temp(usize, usize, TempVarData)
+}
+
+pub struct TempVarData {
+    pub last_term_arity: usize,
+    pub use_set: OccurrenceSet,
+    pub no_use_set: BTreeSet<usize>,
+    pub conflict_set: BTreeSet<usize>
+}
+
+pub type HeapVarDict  = HashMap<Rc<Var>, Addr>;
+pub type AllocVarDict = HashMap<Rc<Var>, VarData>;
+
+pub enum EvalError {
+    ImpermissibleEntry(String),
+    ModuleDoesNotContainExport,
+    ModuleNotFound,
+    NamelessEntry,
+    OpIsInfixAndPostFix,
+    ParserError(ParserError),
+    QueryFailure,
+    QueryFailureWithException(String)
+}
+
+pub enum EvalSession {
+    EntrySuccess,
+    Error(EvalError),
+    InitialQuerySuccess(AllocVarDict, HeapVarDict),
+    SubsequentQuerySuccess,
+}
+
+impl From<EvalError> for EvalSession {
+    fn from(err: EvalError) -> Self {
+        EvalSession::Error(err)
+    }
+}
+
+impl From<ParserError> for EvalError {
+    fn from(err: ParserError) -> Self {
+        EvalError::ParserError(err)
+    }
+}
+
+impl From<ParserError> for EvalSession {
+    fn from(err: ParserError) -> Self {
+        EvalSession::from(EvalError::ParserError(err))
+    }
+}
+
+pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
+
+impl OpDecl {
+    pub fn submit(&self, op_dir: &mut OpDir) -> Result<(), EvalError>
+    {
+        let (prec, spec, name) = (self.0, self.1, self.2.clone());
+
+        if is_infix!(spec) {
+            match op_dir.get(&(name.clone(), Fixity::Post)) {
+                Some(_) => return Err(EvalError::OpIsInfixAndPostFix),
+                _ => {}
+            };
+        }
+
+        if is_postfix!(spec) {
+            match op_dir.get(&(name.clone(), Fixity::In)) {
+                Some(_) => return Err(EvalError::OpIsInfixAndPostFix),
+                _ => {}
+            };
+        }
+
+        if prec > 0 {
+            match spec {
+                XFY | XFX | YFX => op_dir.insert((name.clone(), Fixity::In),
+                                                 (spec, prec)),
+                XF | YF => op_dir.insert((name.clone(), Fixity::Post), (spec, prec)),
+                FX | FY => op_dir.insert((name.clone(), Fixity::Pre), (spec,prec)),
+                _ => None
+            };
+        } else {
+            op_dir.remove(&(name.clone(), Fixity::Pre));
+            op_dir.remove(&(name.clone(), Fixity::In));
+            op_dir.remove(&(name.clone(), Fixity::Post));
+        }
+
+        Ok(())
+    }
+}
+
 #[derive(Debug, Clone, Copy)]
 pub enum ArithmeticError {
     InvalidAtom,
@@ -260,7 +440,10 @@ pub enum ParserError
     InadmissibleQueryTerm,
     IncompleteReduction,
     InconsistentEntry, // was InconsistentDeclaration.
+    InvalidModuleDecl,
+    InvalidModuleExport,
     InvalidRuleHead,
+    InvalidUseModuleDecl,
     ParseBigInt,
     ParseFloat(ParseFloatError),
     // TokenTooLong,
@@ -305,6 +488,22 @@ pub enum Constant {
     EmptyList
 }
 
+impl Constant {
+    pub fn to_atom(self) -> Option<ClauseName> {
+        match self {
+            Constant::Atom(a) => Some(a),
+            _ => None
+        }
+    }
+
+    pub fn to_integer(self) -> Option<Rc<BigInt>> {
+        match self {
+            Constant::Number(Number::Integer(b)) => Some(b),
+            _ => None
+        }
+    }
+}
+
 impl fmt::Display for Constant {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -494,7 +693,7 @@ pub enum ClauseName {
 impl Hash for ClauseName {
     fn hash<H: Hasher>(&self, state: &mut H) {
         (*self.as_str()).hash(state)
-    }        
+    }
 }
 
 impl PartialEq for ClauseName {
@@ -523,6 +722,14 @@ impl<'a> From<&'a TabledRc<Atom>> for ClauseName {
     }
 }
 
+fn defrock_brackets(s: &str) -> &str {
+    if s.starts_with('(') && s.ends_with(')') {
+        &s[1 .. s.len() - 1]
+    } else {
+        s
+    }
+}
+
 impl ClauseName {
     pub fn as_str(&self) -> &str {
         match self {
@@ -530,6 +737,16 @@ impl ClauseName {
             &ClauseName::User(ref name) => name.as_ref()
         }
     }
+
+    fn defrock_brackets(self) -> Self {
+        match self {
+            ClauseName::BuiltIn(s) =>
+                ClauseName::BuiltIn(defrock_brackets(s)),
+            ClauseName::User(s) =>
+                ClauseName::User(tabled_rc!(defrock_brackets(s.as_str()).to_owned(),
+                                            s.atom_tbl()))
+        }
+    }
 }
 
 impl ClauseType {
@@ -599,7 +816,7 @@ pub enum TermRef<'a> {
     Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
     Constant(Level, &'a Cell<RegType>, &'a Constant),
     Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
-    Var(Level, &'a Cell<VarReg>, &'a Var)
+    Var(Level, &'a Cell<VarReg>, Rc<Var>)
 }
 
 impl<'a> TermRef<'a> {
@@ -1196,18 +1413,27 @@ impl HeapCellValue {
     }
 }
 
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Clone, PartialEq)]
 pub enum CodePtr {
-    DirEntry(usize),
+    DirEntry(usize, ClauseName), // offset, resident module name.
     TopLevel(usize, usize) // chunk_num, offset.
 }
 
+impl CodePtr {    
+    pub fn module_name(&self) -> ClauseName {
+        match self {
+            &CodePtr::DirEntry(_, ref name) => name.clone(),
+            _ => ClauseName::BuiltIn("user")
+        }
+    }
+}
+
 impl PartialOrd<CodePtr> for CodePtr {
     fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
         match (self, other) {
-            (&CodePtr::DirEntry(p1), &CodePtr::DirEntry(ref p2)) =>
-                p1.partial_cmp(p2),
-            (&CodePtr::DirEntry(_), &CodePtr::TopLevel(_, _)) =>
+            (&CodePtr::DirEntry(p1, _), &CodePtr::DirEntry(p2, _)) =>
+                p1.partial_cmp(&p2),
+            (&CodePtr::DirEntry(..), &CodePtr::TopLevel(_, _)) =>
                 Some(Ordering::Less),
             (&CodePtr::TopLevel(_, p1), &CodePtr::TopLevel(_, ref p2)) =>
                 p1.partial_cmp(p2),
@@ -1227,7 +1453,7 @@ impl Add<usize> for CodePtr {
 
     fn add(self, rhs: usize) -> Self::Output {
         match self {
-            CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
+            CodePtr::DirEntry(p, name) => CodePtr::DirEntry(p + rhs, name),
             CodePtr::TopLevel(cn, p) => CodePtr::TopLevel(cn, p + rhs)
         }
     }
@@ -1236,7 +1462,7 @@ impl Add<usize> for CodePtr {
 impl AddAssign<usize> for CodePtr {
     fn add_assign(&mut self, rhs: usize) {
         match self {
-            &mut CodePtr::DirEntry(ref mut p) |
+            &mut CodePtr::DirEntry(ref mut p, _) |
             &mut CodePtr::TopLevel(_, ref mut p) => *p += rhs
         }
     }
@@ -1296,6 +1522,13 @@ impl IndexMut<usize> for Heap {
 pub type Registers = Vec<Addr>;
 
 impl Term {
+    pub fn to_constant(self) -> Option<Constant> {
+        match self {
+            Term::Constant(_, c) => Some(c),
+            _ => None
+        }
+    }
+
     pub fn first_arg(&self) -> Option<&Term> {
         match self {
             &Term::Clause(_, _, ref terms, _) =>
@@ -1326,7 +1559,7 @@ pub enum TermIterState<'a> {
     Clause(Level, usize, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
     InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
     FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
-    Var(Level, &'a Cell<VarReg>, &'a Var)
+    Var(Level, &'a Cell<VarReg>, Rc<Var>)
 }
 
 impl<'a> TermIterState<'a> {
@@ -1334,13 +1567,13 @@ impl<'a> TermIterState<'a> {
         match term {
             &Term::AnonVar =>
                 TermIterState::AnonVar(lvl),
-            &Term::Clause(ref cell, ref name, ref subterms, fixity) => {                
+            &Term::Clause(ref cell, ref name, ref subterms, fixity) => {
                 let ct = if let Some(fixity) = fixity {
                     ClauseType::Op(name.clone(), fixity)
                 } else {
                     ClauseType::Named(name.clone())
                 };
-                
+
                 TermIterState::Clause(lvl, 0, cell, ct, subterms)
             },
             &Term::Cons(ref cell, ref head, ref tail) =>
@@ -1348,7 +1581,7 @@ impl<'a> TermIterState<'a> {
             &Term::Constant(ref cell, ref constant) =>
                 TermIterState::Constant(lvl, cell, constant),
             &Term::Var(ref cell, ref var) =>
-                TermIterState::Var(lvl, cell, var)
+                TermIterState::Var(lvl, cell, (*var).clone())
         }
     }
 }
index 2ad9fa705e7f936f54dc11418a98c0e80c3fbe93..135eac8b234b5db768cfc3c004be79b86849b2e3 100644 (file)
@@ -4,20 +4,6 @@ use prolog::num::bigint::{BigInt};
 use std::collections::HashMap;
 use std::rc::Rc;
 
-pub type PredicateKey = (ClauseName, usize); // name, arity, type.
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub enum PredicateKeyType {
-    BuiltIn,
-    User
-}
-
-pub type OpDirKey = (ClauseName, Fixity);
-// name and fixity -> operator type and precedence.
-pub type OpDir = HashMap<OpDirKey, (Specifier, usize)>;
-
-pub type CodeDir = HashMap<PredicateKey, (PredicateKeyType, usize)>;
-
 fn get_builtins() -> Code {
     vec![internal_call_n!(), // callN/N, 0.
          is_atomic!(temp_v!(1)), // atomic/1, 1.
@@ -278,7 +264,7 @@ fn get_builtins() -> Code {
          proceed!(),
          dynamic_num_test!(cmp_gte!()), // >=/2, 200.
          proceed!(),
-         dynamic_num_test!(cmp_lte!()), // <=/2, 202.
+         dynamic_num_test!(cmp_lte!()), // =</2, 202.
          proceed!(),
          dynamic_num_test!(cmp_ne!()), // =\=, 204.
          proceed!(),
@@ -582,7 +568,7 @@ fn get_builtins() -> Code {
          query![put_value!(perm_v!(4), 1),
                 put_value!(perm_v!(3), 2),
                 put_value!(perm_v!(1), 3),
-                put_value!(perm_v!(2), 4)],         
+                put_value!(perm_v!(2), 4)],
          deallocate!(),
          goto_execute!(452, 4), // goto end_block/4, 452
          default_trust_me!(), // 423
@@ -602,7 +588,7 @@ fn get_builtins() -> Code {
                 put_value!(perm_v!(1), 3)],
          deallocate!(),
          goto_execute!(444, 3), // goto handle_ile/3, 442.
-         try_me_else!(5), // the inner clause.         
+         try_me_else!(5), // the inner clause.
          query![put_value!(temp_v!(2), 1)],
          get_ball!(),
          neck_cut!(),
@@ -638,13 +624,11 @@ fn get_builtins() -> Code {
     ]
 }
 
-pub fn build_code_dir() -> (Code, CodeDir, OpDir)
+pub fn build_code_and_op_dirs() -> (CodeDir, OpDir)
 {
     let mut code_dir = HashMap::new();
     let mut op_dir   = HashMap::new();
 
-    let builtin_code = get_builtins();
-
     op_dir.insert((clause_name!(":-"), Fixity::In),   (XFX, 1200));
     op_dir.insert((clause_name!(":-"), Fixity::Pre),  (FX, 1200));
     op_dir.insert((clause_name!("?-"), Fixity::Pre),  (FX, 1200));
@@ -693,64 +677,168 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir)
     op_dir.insert((clause_name!("=@="), Fixity::In), (XFX, 700));
     op_dir.insert((clause_name!("\\=@="), Fixity::In), (XFX, 700));
 
+    let builtin = ClauseName::BuiltIn("builtin");
+
     // there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62
     // (an extra register is needed for the predicate name)
     for arity in 0 .. 63 {
-        code_dir.insert((clause_name!("call"), arity), (PredicateKeyType::BuiltIn, 0));
+        code_dir.insert((clause_name!("call"), arity),
+                        (PredicateKeyType::BuiltIn, 0, builtin.clone()));
     }
 
-    code_dir.insert((clause_name!("atomic"), 1), (PredicateKeyType::BuiltIn, 1));
-    code_dir.insert((clause_name!("var"), 1), (PredicateKeyType::BuiltIn, 3));
-    code_dir.insert((clause_name!("false"), 0), (PredicateKeyType::BuiltIn, 61));
-    code_dir.insert((clause_name!("\\+"), 1), (PredicateKeyType::BuiltIn, 62));
-    code_dir.insert((clause_name!("duplicate_term"), 2), (PredicateKeyType::BuiltIn, 71));
-    code_dir.insert((clause_name!("catch"), 3), (PredicateKeyType::BuiltIn, 5));
-    code_dir.insert((clause_name!("throw"), 1), (PredicateKeyType::BuiltIn, 59));
-    code_dir.insert((clause_name!("="), 2), (PredicateKeyType::BuiltIn, 73));
-    code_dir.insert((clause_name!("true"), 0), (PredicateKeyType::BuiltIn, 75));
+    code_dir.insert((clause_name!("atomic"), 1),
+                    (PredicateKeyType::BuiltIn, 1, builtin.clone()));
+    code_dir.insert((clause_name!("var"), 1),
+                    (PredicateKeyType::BuiltIn, 3, builtin.clone()));
+    code_dir.insert((clause_name!("false"), 0),
+                    (PredicateKeyType::BuiltIn, 61, builtin.clone()));
+    code_dir.insert((clause_name!("\\+"), 1),
+                    (PredicateKeyType::BuiltIn, 62, builtin.clone()));
+    code_dir.insert((clause_name!("duplicate_term"), 2),
+                    (PredicateKeyType::BuiltIn, 71, builtin.clone()));
+    code_dir.insert((clause_name!("catch"), 3),
+                    (PredicateKeyType::BuiltIn, 5, builtin.clone()));
+    code_dir.insert((clause_name!("throw"), 1),
+                    (PredicateKeyType::BuiltIn, 59, builtin.clone()));
+    code_dir.insert((clause_name!("="), 2),
+                    (PredicateKeyType::BuiltIn, 73, builtin.clone()));
+    code_dir.insert((clause_name!("true"), 0),
+                    (PredicateKeyType::BuiltIn, 75, builtin.clone()));
 
-    code_dir.insert((clause_name!(","), 2), (PredicateKeyType::BuiltIn, 76));
-    code_dir.insert((clause_name!(";"), 2), (PredicateKeyType::BuiltIn, 120));
-    code_dir.insert((clause_name!("->"), 2), (PredicateKeyType::BuiltIn, 138));
+    code_dir.insert((clause_name!(","), 2),
+                    (PredicateKeyType::BuiltIn, 76, builtin.clone()));
+    code_dir.insert((clause_name!(";"), 2),
+                    (PredicateKeyType::BuiltIn, 120, builtin.clone()));
+    code_dir.insert((clause_name!("->"), 2),
+                    (PredicateKeyType::BuiltIn, 138, builtin.clone()));
 
-    code_dir.insert((clause_name!("functor"), 3), (PredicateKeyType::BuiltIn, 146));
-    code_dir.insert((clause_name!("arg"), 3), (PredicateKeyType::BuiltIn, 150));
-    code_dir.insert((clause_name!("integer"), 1), (PredicateKeyType::BuiltIn, 147));
-    code_dir.insert((clause_name!("display"), 1), (PredicateKeyType::BuiltIn, 192));
+    code_dir.insert((clause_name!("functor"), 3),
+                    (PredicateKeyType::BuiltIn, 146, builtin.clone()));
+    code_dir.insert((clause_name!("arg"), 3),
+                    (PredicateKeyType::BuiltIn, 150, builtin.clone()));
+    code_dir.insert((clause_name!("integer"), 1),
+                    (PredicateKeyType::BuiltIn, 147, builtin.clone()));
+    code_dir.insert((clause_name!("display"), 1),
+                    (PredicateKeyType::BuiltIn, 192, builtin.clone()));
 
-    code_dir.insert((clause_name!("is"), 2), (PredicateKeyType::BuiltIn, 194));
-    code_dir.insert((clause_name!(">"), 2), (PredicateKeyType::BuiltIn, 196));
-    code_dir.insert((clause_name!("<"), 2), (PredicateKeyType::BuiltIn, 198));
-    code_dir.insert((clause_name!(">="), 2), (PredicateKeyType::BuiltIn, 200));
-    code_dir.insert((clause_name!("<="), 2), (PredicateKeyType::BuiltIn, 202));
-    code_dir.insert((clause_name!("=\\="), 2), (PredicateKeyType::BuiltIn, 204));
-    code_dir.insert((clause_name!("=:="), 2), (PredicateKeyType::BuiltIn, 206));
-    code_dir.insert((clause_name!("=.."), 2), (PredicateKeyType::BuiltIn, 208));
+    code_dir.insert((clause_name!("is"), 2),
+                    (PredicateKeyType::BuiltIn, 194, builtin.clone()));
+    code_dir.insert((clause_name!(">"), 2),
+                    (PredicateKeyType::BuiltIn, 196, builtin.clone()));
+    code_dir.insert((clause_name!("<"), 2),
+                    (PredicateKeyType::BuiltIn, 198, builtin.clone()));
+    code_dir.insert((clause_name!(">="), 2),
+                    (PredicateKeyType::BuiltIn, 200, builtin.clone()));
+    code_dir.insert((clause_name!("=<"), 2),
+                    (PredicateKeyType::BuiltIn, 202, builtin.clone()));
+    code_dir.insert((clause_name!("=\\="), 2),
+                    (PredicateKeyType::BuiltIn, 204, builtin.clone()));
+    code_dir.insert((clause_name!("=:="), 2),
+                    (PredicateKeyType::BuiltIn, 206, builtin.clone()));
+    code_dir.insert((clause_name!("=.."), 2),
+                    (PredicateKeyType::BuiltIn, 208, builtin.clone()));
 
-    code_dir.insert((clause_name!("length"), 2), (PredicateKeyType::BuiltIn, 261));
+    code_dir.insert((clause_name!("length"), 2),
+                    (PredicateKeyType::BuiltIn, 261, builtin.clone()));
     code_dir.insert((clause_name!("setup_call_cleanup"), 3),
-                    (PredicateKeyType::BuiltIn, 294));
+                    (PredicateKeyType::BuiltIn, 294, builtin.clone()));
     code_dir.insert((clause_name!("call_with_inference_limit"), 3),
-                    (PredicateKeyType::BuiltIn, 393));
-    code_dir.insert((clause_name!("_handle_inference_limit_exceeded"), 2),
-                    (PredicateKeyType::BuiltIn, 421));
+                    (PredicateKeyType::BuiltIn, 393, builtin.clone()));
+
+    code_dir.insert((clause_name!("compound"), 1),
+                    (PredicateKeyType::BuiltIn, 372, builtin.clone()));
+    code_dir.insert((clause_name!("rational"), 1),
+                    (PredicateKeyType::BuiltIn, 374, builtin.clone()));
+    code_dir.insert((clause_name!("string"), 1),
+                    (PredicateKeyType::BuiltIn, 376, builtin.clone()));
+    code_dir.insert((clause_name!("float"), 1),
+                    (PredicateKeyType::BuiltIn, 378, builtin.clone()));
+    code_dir.insert((clause_name!("nonvar"), 1),
+                    (PredicateKeyType::BuiltIn, 380, builtin.clone()));
 
-    code_dir.insert((clause_name!("compound"), 1), (PredicateKeyType::BuiltIn, 372));
-    code_dir.insert((clause_name!("rational"), 1), (PredicateKeyType::BuiltIn, 374));
-    code_dir.insert((clause_name!("string"), 1), (PredicateKeyType::BuiltIn, 376));
-    code_dir.insert((clause_name!("float"), 1), (PredicateKeyType::BuiltIn, 378));
-    code_dir.insert((clause_name!("nonvar"), 1), (PredicateKeyType::BuiltIn, 380));
+    code_dir.insert((clause_name!("ground"), 1),
+                    (PredicateKeyType::BuiltIn, 384, builtin.clone()));
+    code_dir.insert((clause_name!("=="), 2),
+                    (PredicateKeyType::BuiltIn, 385, builtin.clone()));
+    code_dir.insert((clause_name!("\\=="), 2),
+                    (PredicateKeyType::BuiltIn, 386, builtin.clone()));
+    code_dir.insert((clause_name!("@>="), 2),
+                    (PredicateKeyType::BuiltIn, 387, builtin.clone()));
+    code_dir.insert((clause_name!("@=<"), 2),
+                    (PredicateKeyType::BuiltIn, 388, builtin.clone()));
+    code_dir.insert((clause_name!("@>"), 2),
+                    (PredicateKeyType::BuiltIn, 389, builtin.clone()));
+    code_dir.insert((clause_name!("@<"), 2),
+                    (PredicateKeyType::BuiltIn, 390, builtin.clone()));
+    code_dir.insert((clause_name!("=@="), 2),
+                    (PredicateKeyType::BuiltIn, 391, builtin.clone()));
+    code_dir.insert((clause_name!("\\=@="), 2),
+                    (PredicateKeyType::BuiltIn, 392, builtin.clone()));
+    code_dir.insert((clause_name!("compare"), 3),
+                    (PredicateKeyType::BuiltIn, 464, builtin.clone()));
+
+    (code_dir, op_dir)
+}
+
+pub fn default_build() -> (Code, CodeDir, OpDir)
+{
+    let builtin_code = get_builtins();
+    let (code_dir, op_dir) = build_code_and_op_dirs();
 
-    code_dir.insert((clause_name!("ground"), 1), (PredicateKeyType::BuiltIn, 384));
-    code_dir.insert((clause_name!("=="), 2), (PredicateKeyType::BuiltIn, 385));
-    code_dir.insert((clause_name!("\\=="), 2), (PredicateKeyType::BuiltIn, 386));
-    code_dir.insert((clause_name!("@>="), 2), (PredicateKeyType::BuiltIn, 387));
-    code_dir.insert((clause_name!("@=<"), 2), (PredicateKeyType::BuiltIn, 388));
-    code_dir.insert((clause_name!("@>"), 2), (PredicateKeyType::BuiltIn, 389));
-    code_dir.insert((clause_name!("@<"), 2), (PredicateKeyType::BuiltIn, 390));
-    code_dir.insert((clause_name!("=@="), 2), (PredicateKeyType::BuiltIn, 391));
-    code_dir.insert((clause_name!("\\=@="), 2), (PredicateKeyType::BuiltIn, 392));
-    code_dir.insert((clause_name!("compare"), 3), (PredicateKeyType::BuiltIn, 464));
-    
     (builtin_code, code_dir, op_dir)
 }
+
+#[allow(dead_code)]
+pub fn builtin_module() -> Module
+{
+    let (code_dir, op_dir) = build_code_and_op_dirs();
+    let mut module_decl = module_decl!(clause_name!("builtin"),
+                                       vec![(clause_name!("atomic"), 1),
+                                            (clause_name!("var"), 1),
+                                            (clause_name!("false"), 0),
+                                            (clause_name!("catch"), 3),
+                                            (clause_name!("throw"), 1),
+                                            (clause_name!("(\\+)"), 1),
+                                            (clause_name!("duplicate_term"), 2),
+                                            (clause_name!("(=)"), 2),
+                                            (clause_name!("true"), 0),
+                                            (clause_name!("(,)"), 2),                                      
+                                            (clause_name!("(;)"), 2),
+                                            (clause_name!("->"), 2),
+                                            (clause_name!("functor"), 3),
+                                            (clause_name!("arg"), 3),
+                                            (clause_name!("(=..)"), 3),
+                                            (clause_name!("display"), 1),
+                                            (clause_name!("is"), 2),
+                                            (clause_name!("(>)"), 2),
+                                            (clause_name!("(<)"), 2),
+                                            (clause_name!("(>=)"), 2),
+                                            (clause_name!("(=<)"), 2),
+                                            (clause_name!("(=\\=)"), 2),
+                                            (clause_name!("(=:=)"), 2),
+                                            (clause_name!("(@>)"), 2),
+                                            (clause_name!("(@<)"), 2),
+                                            (clause_name!("(@>=)"), 2),
+                                            (clause_name!("(@=<)"), 2),
+                                            (clause_name!("(=@=)"), 2),
+                                            (clause_name!("(\\=@=)"), 2),
+                                            (clause_name!("(==)"), 2),
+                                            (clause_name!("(\\==)"), 2),
+                                            (clause_name!("length"), 2),
+                                            (clause_name!("compound"), 1),
+                                            (clause_name!("rational"), 1),
+                                            (clause_name!("integer"), 1),
+                                            (clause_name!("string"), 1),
+                                            (clause_name!("float"), 1),
+                                            (clause_name!("nonvar"), 1),
+                                            (clause_name!("ground"), 1),
+                                            (clause_name!("setup_call_cleanup"), 3),
+                                            (clause_name!("call_with_inference_limit"), 3),
+                                            (clause_name!("compare"), 3)]);
+
+    for arity in 0 .. 63 {
+        module_decl.exports.push((clause_name!("call"), arity));
+    }
+
+    Module { module_decl, code_dir, op_dir }
+}
index 33328ec06b9afc683458c104ce34fbfd1551b3c4..72abc742a65a5815458e369fc602122afbeef473 100644 (file)
@@ -8,39 +8,12 @@ use prolog::targets::*;
 
 use std::cell::Cell;
 use std::collections::HashMap;
+use std::rc::Rc;
 use std::vec::Vec;
 
-pub struct CodeGenerator<'a, TermMarker> {
+pub struct CodeGenerator<TermMarker> {
     marker: TermMarker,
-    var_count: HashMap<&'a Var, usize>
-}
-
-pub enum EvalError {
-    OpIsInfixAndPostFix,
-    NamelessEntry,
-    ParserError(ParserError),
-    ImpermissibleEntry(String),
-    QueryFailure,
-    QueryFailureWithException(String)
-}
-
-pub enum EvalSession<'a> {
-    EntrySuccess,
-    Error(EvalError),
-    InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
-    SubsequentQuerySuccess,
-}
-
-impl<'a> From<EvalError> for EvalSession<'a> {
-    fn from(err: EvalError) -> Self {
-        EvalSession::Error(err)
-    }
-}
-
-impl<'a> From<ParserError> for EvalSession<'a> {
-    fn from(err: ParserError) -> Self {
-        EvalSession::from(EvalError::ParserError(err))
-    }
+    var_count: HashMap<Rc<Var>, usize>
 }
 
 pub struct ConjunctInfo<'a> {
@@ -69,14 +42,14 @@ impl<'a> ConjunctInfo<'a>
     }
 }
 
-impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
+impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
 {
     pub fn new() -> Self {
         CodeGenerator { marker:  Allocator::new(),
                         var_count: HashMap::new() }
     }
 
-    pub fn take_vars(self) -> AllocVarDict<'a> {
+    pub fn take_vars(self) -> AllocVarDict {
         self.marker.take_bindings()
     }
 
@@ -94,11 +67,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
         *self.var_count.get(var).unwrap()
     }
 
-    fn mark_non_callable(&mut self, name: &'a Atom, arity: usize, term_loc: GenContext,
+    fn mark_non_callable(&mut self, name: Rc<Atom>, arity: usize, term_loc: GenContext,
                          vr: &'a Cell<VarReg>, code: &mut Code)
                          -> RegType
     {
-        match self.marker.bindings().get(name) {
+        match self.marker.bindings().get(&name) {
             Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
             Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
             _ => {
@@ -149,7 +122,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                 target.push(Target::constant_subterm(constant.clone())),
             &Term::Var(ref cell, ref var) =>
                 if is_exposed || self.get_var_count(var) > 1 {
-                    self.marker.mark_var(var, Level::Deep, cell, term_loc, target);
+                    self.marker.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
                 } else {
                     Self::add_or_increment_void_instr(target);
                 }
@@ -189,8 +162,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                     } else {
                         self.marker.mark_anon_var(lvl, &mut target);
                     },
-                TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
-                    self.marker.mark_var(var, lvl, cell, term_loc, &mut target),
+                TermRef::Var(lvl @ Level::Shallow, cell, var) =>
+                    self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target),
                 _ => {}
             };
         }
@@ -211,7 +184,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                     } else {
                         GenContext::Last(chunk_num)
                     }
-                };                
+                };
 
                 self.update_var_count(chunked_term.post_order_iter());
                 vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc);
@@ -356,7 +329,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         code.push(succeed!());
                     },
                     &Term::Var(ref vr, ref name) => {
-                        let r = self.mark_non_callable(name, 1, term_loc, vr, code);
+                        let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
                         code.push(is_atomic!(r));
                     }
                 },
@@ -366,7 +339,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         code.push(succeed!());
                     },
                     &Term::Var(ref vr, ref name) => {
-                        let r = self.mark_non_callable(name, 1, term_loc, vr, code);
+                        let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
                         code.push(is_compound!(r));
                     },
                     _ => {
@@ -379,7 +352,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         code.push(succeed!());
                     },
                     &Term::Var(ref vr, ref name) => {
-                        let r = self.mark_non_callable(name, 1, term_loc, vr, code);
+                        let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
                         code.push(is_rational!(r));
                     },
                     _ => {
@@ -392,7 +365,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         code.push(succeed!());
                     },
                     &Term::Var(ref vr, ref name) => {
-                        let r = self.mark_non_callable(name, 1, term_loc, vr, code);
+                        let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
                         code.push(is_float!(r));
                     },
                     _ => {
@@ -405,7 +378,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         code.push(succeed!());
                     },
                     &Term::Var(ref vr, ref name) => {
-                        let r = self.mark_non_callable(name, 1, term_loc, vr, code);
+                        let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
                         code.push(is_string!(r));
                     },
                     _ => {
@@ -418,7 +391,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         code.push(fail!());
                     },
                     &Term::Var(ref vr, ref name) => {
-                        let r = self.mark_non_callable(name, 1, term_loc, vr, code);
+                        let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
                         code.push(is_nonvar!(r));
                     },
                     _ => {
@@ -431,7 +404,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         code.push(succeed!());
                     },
                     &Term::Var(ref vr, ref name) => {
-                        let r = self.mark_non_callable(name, 1, term_loc, vr, code);
+                        let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
                         code.push(is_integer!(r));
                     },
                     _ => {
@@ -447,7 +420,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                         code.push(succeed!());
                     },
                     &Term::Var(ref vr, ref name) => {
-                        let r = self.mark_non_callable(name, 1, term_loc, vr, code);
+                        let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
                         code.push(is_var!(r));
                     }
                 }
@@ -492,7 +465,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
                                 let mut target = Vec::new();
 
                                 self.marker.reset_arg(2);
-                                self.marker.mark_var(name, Level::Shallow, vr,
+                                self.marker.mark_var(name.clone(), Level::Shallow, vr,
                                                      term_loc, &mut target);
 
                                 if !target.is_empty() {
index 4fda7415f9ccdf22eb886a7a0593243116a81c2c..1bdc5a9e5a9e6dc79f9ecc2b709755c9e40909c1 100644 (file)
@@ -1,28 +1,28 @@
 use prolog::allocator::*;
 use prolog::ast::*;
-use prolog::fixtures::*;
 use prolog::targets::*;
 
 use std::cell::Cell;
 use std::collections::{BTreeSet, HashMap};
+use std::rc::Rc;
 
-pub struct DebrayAllocator<'a> {
-    bindings: HashMap<&'a Var, VarData>,
+pub struct DebrayAllocator {
+    bindings: HashMap<Rc<Var>, VarData>,
     arg_c:    usize,
     temp_lb:  usize,
-    contents: HashMap<usize, &'a Var>,
+    contents: HashMap<usize, Rc<Var>>,
     in_use:   BTreeSet<usize>,
 }
 
-impl<'a> DebrayAllocator<'a> {
-    fn is_curr_arg_distinct_from(&self, var: &'a Var) -> bool {
+impl DebrayAllocator {
+    fn is_curr_arg_distinct_from(&self, var: &Var) -> bool {
         match self.contents.get(&self.arg_c) {
             Some(t_var) if **t_var != *var => true,
             _ => false
         }
     }
 
-    fn occurs_shallowly_in_head(&self, var: &'a Var, r: usize) -> bool
+    fn occurs_shallowly_in_head(&self, var: &Var, r: usize) -> bool
     {
         match self.bindings.get(var).unwrap() {
             &VarData::Temp(_, _, ref tvd) =>
@@ -31,7 +31,7 @@ impl<'a> DebrayAllocator<'a> {
         }
     }
 
-    fn alloc_with_cr(&self, var: &'a Var) -> usize
+    fn alloc_with_cr(&self, var: &Var) -> usize
     {
         match self.bindings.get(var) {
             Some(&VarData::Temp(_, _, ref tvd)) => {
@@ -58,7 +58,7 @@ impl<'a> DebrayAllocator<'a> {
         }
     }
 
-    fn alloc_with_ca(&self, var: &'a Var) -> usize
+    fn alloc_with_ca(&self, var: &Var) -> usize
     {
         match self.bindings.get(var) {
             Some(&VarData::Temp(_, _, ref tvd)) => {
@@ -87,7 +87,7 @@ impl<'a> DebrayAllocator<'a> {
         }
     }
 
-    fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(&'a Var, usize)>
+    fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc<Var>, usize)>
     {
         // we want to allocate a register to the k^{th} parameter, par_k.
         // par_k may not be a temporary variable.
@@ -103,7 +103,7 @@ impl<'a> DebrayAllocator<'a> {
                 let tvd = self.bindings.get(t_var).unwrap();
                 if let &VarData::Temp(_, _, ref tvd) = tvd {
                     if !tvd.use_set.contains(&(GenContext::Last(chunk_num), k)) {
-                        return Some((t_var, self.alloc_with_ca(t_var)));
+                        return Some((t_var.clone(), self.alloc_with_ca(t_var)));
                     }
                 }
 
@@ -113,7 +113,7 @@ impl<'a> DebrayAllocator<'a> {
         }
     }
 
-    fn evacuate_arg<Target>(&mut self, chunk_num: usize, target: &mut Vec<Target>)
+    fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec<Target>)
         where Target: CompilationTarget<'a>
     {
         match self.alloc_in_last_goal_hint(chunk_num) {
@@ -127,7 +127,7 @@ impl<'a> DebrayAllocator<'a> {
                         target.push(Target::move_to_register(r, k));
 
                         self.contents.remove(&k);
-                        self.contents.insert(r.reg_num(), var);
+                        self.contents.insert(r.reg_num(), var.clone());
 
                         self.record_register(var, r);
                         self.in_use.insert(r.reg_num());
@@ -138,8 +138,8 @@ impl<'a> DebrayAllocator<'a> {
         };
     }
 
-    fn alloc_reg_to_var<Target>(&mut self, var: &'a Var, lvl: Level, term_loc: GenContext,
-                                target: &mut Vec<Target>)
+    fn alloc_reg_to_var<'a, Target>(&mut self, var: &Var, lvl: Level, term_loc: GenContext,
+                                    target: &mut Vec<Target>)
                                 -> usize
         where Target: CompilationTarget<'a>
     {
@@ -179,7 +179,7 @@ impl<'a> DebrayAllocator<'a> {
         final_index
     }
 
-    fn in_place(&self, var: &'a Var, term_loc: GenContext, r: RegType, k: usize) -> bool
+    fn in_place(&self, var: &Var, term_loc: GenContext, r: RegType, k: usize) -> bool
     {
         match term_loc {
             GenContext::Head if !r.is_perm() => r.reg_num() == k,
@@ -191,9 +191,9 @@ impl<'a> DebrayAllocator<'a> {
     }
 }
 
-impl<'a> Allocator<'a> for DebrayAllocator<'a>
+impl<'a> Allocator<'a> for DebrayAllocator
 {
-    fn new() -> DebrayAllocator<'a> {
+    fn new() -> DebrayAllocator {
         DebrayAllocator {
             arg_c:   1,
             temp_lb: 1,
@@ -244,14 +244,14 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
         }
     }
 
-    fn mark_var<Target>(&mut self, var: &'a Var, lvl: Level, cell: &'a Cell<VarReg>,
+    fn mark_var<Target>(&mut self, var: Rc<Var>, lvl: Level, cell: &Cell<VarReg>,
                         term_loc: GenContext, target: &mut Vec<Target>)
         where Target: CompilationTarget<'a>
     {
-        let (r, is_new_var) = match self.get(var) {
+        let (r, is_new_var) = match self.get(var.clone()) {
             RegType::Temp(0) => {
                 // here, r is temporary *and* unassigned.
-                let o = self.alloc_reg_to_var(var, lvl, term_loc, target);
+                let o = self.alloc_reg_to_var(&var, lvl, term_loc, target);
 
                 cell.set(VarReg::Norm(RegType::Temp(o)));
 
@@ -259,7 +259,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
             },
             RegType::Perm(0) => {
                 let pr = cell.get().norm();
-                self.record_register(var, pr);
+                self.record_register(var.clone(), pr);
 
                 (pr, true)
             },
@@ -270,7 +270,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
             Level::Root | Level::Shallow => {
                 let k = self.arg_c;
 
-                if self.is_curr_arg_distinct_from(var) {
+                if self.is_curr_arg_distinct_from(&var) {
                     self.evacuate_arg(term_loc.chunk_num(), target);
                 }
 
@@ -278,7 +278,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
 
                 cell.set(VarReg::ArgAndNorm(r, k));
 
-                if !self.in_place(var, term_loc, r, k) {
+                if !self.in_place(&var, term_loc, r, k) {
                     if is_new_var {
                         target.push(Target::argument_to_variable(r, k));
                     } else {
@@ -288,7 +288,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
             },
             Level::Deep if is_new_var =>
                 if let GenContext::Head = term_loc {
-                    if self.occurs_shallowly_in_head(var, r.reg_num()) {
+                    if self.occurs_shallowly_in_head(&var, r.reg_num()) {
                         target.push(Target::subterm_to_value(r));
                     } else {
                         target.push(Target::subterm_to_variable(r));
@@ -303,8 +303,8 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
         if !r.is_perm() {
             let o = r.reg_num();
 
-            self.contents.insert(o, var);
-            self.record_register(var, r);
+            self.contents.insert(o, var.clone());
+            self.record_register(var.clone(), r);
             self.in_use.insert(o);
         }
     }
@@ -324,15 +324,15 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
         self.arg_c += 1;
     }
 
-    fn bindings(&self) -> &AllocVarDict<'a> {
+    fn bindings(&self) -> &AllocVarDict {
         &self.bindings
     }
 
-    fn bindings_mut(&mut self) -> &mut AllocVarDict<'a> {
+    fn bindings_mut(&mut self) -> &mut AllocVarDict {
         &mut self.bindings
     }
 
-    fn take_bindings(self) -> AllocVarDict<'a> {
+    fn take_bindings(self) -> AllocVarDict {
         self.bindings
     }
 
index 3b9abcf63e77eb069e3f56a86d4304ef2664b680..34a70751a4ceef6ce85407b14806fee7ee4ccec7 100644 (file)
@@ -5,31 +5,9 @@ use std::cell::Cell;
 use std::collections::{BTreeMap, BTreeSet, HashMap};
 use std::collections::btree_map::{IntoIter, IterMut, Values};
 use std::mem::swap;
+use std::rc::Rc;
 use std::vec::Vec;
 
-pub type OccurrenceSet = BTreeSet<(GenContext, usize)>;
-
-pub type HeapVarDict<'a>  = HashMap<&'a Var, Addr>;
-pub type AllocVarDict<'a> = HashMap<&'a Var, VarData>;
-
-pub struct TempVarData {
-    last_term_arity: usize,
-    pub use_set: OccurrenceSet,
-    pub no_use_set: BTreeSet<usize>,
-    pub conflict_set: BTreeSet<usize>
-}
-
-// labeled with chunk numbers.
-pub enum VarStatus {
-    Perm(usize), Temp(usize, TempVarData) // Perm(chunk_num) | Temp(chunk_num, _)
-}
-
-// Perm: 0 initially, a stack register once processed.
-// Temp: labeled with chunk_num and temp offset (unassigned if 0).
-pub enum VarData {
-    Perm(usize), Temp(usize, usize, TempVarData)
-}
-
 impl VarData {
     pub fn as_reg_type(&self) -> RegType {
         match self {
@@ -73,8 +51,8 @@ impl TempVarData {
     }
 }
 
-type VariableFixture<'a>  = (VarStatus, Vec<&'a Cell<VarReg>>);
-pub struct VariableFixtures<'a>(BTreeMap<&'a Var, VariableFixture<'a>>);
+type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
+pub struct VariableFixtures<'a>(BTreeMap<Rc<Var>, VariableFixture<'a>>);
 
 impl<'a> VariableFixtures<'a>
 {
@@ -82,7 +60,7 @@ impl<'a> VariableFixtures<'a>
         VariableFixtures(BTreeMap::new())
     }
 
-    pub fn insert(&mut self, var: &'a Var, vs: VariableFixture<'a>) {
+    pub fn insert(&mut self, var: Rc<Var>, vs: VariableFixture<'a>) {
         self.0.insert(var, vs);
     }
 
@@ -98,14 +76,14 @@ impl<'a> VariableFixtures<'a>
         // Compute the conflict set of u.
 
         // 1.
-        let mut use_sets : HashMap<&'a Var, OccurrenceSet> = HashMap::new();
+        let mut use_sets: HashMap<Rc<Var>, OccurrenceSet> = HashMap::new();
 
-        for (ref var, &mut (ref mut var_status, _)) in self.iter_mut() {
+        for (var, &mut (ref mut var_status, _)) in self.iter_mut() {
             if let &mut VarStatus::Temp(_, ref mut var_data) = var_status {
                 let mut use_set = OccurrenceSet::new();
 
                 swap(&mut var_data.use_set, &mut use_set);
-                use_sets.insert(var, use_set);
+                use_sets.insert((*var).clone(), use_set);
             }
         }
 
@@ -136,11 +114,11 @@ impl<'a> VariableFixtures<'a>
         }
     }
 
-    fn get_mut(&mut self, u: &'a Var) -> Option<&mut VariableFixture<'a>> {
-        self.0.get_mut(u)
+    fn get_mut(&mut self, u: Rc<Var>) -> Option<&mut VariableFixture<'a>> {
+        self.0.get_mut(&u)
     }
 
-    fn iter_mut(&mut self) -> IterMut<&'a Var, VariableFixture<'a>> {
+    fn iter_mut(&mut self) -> IterMut<Rc<Var>, VariableFixture<'a>> {
         self.0.iter_mut()
     }
 
@@ -179,7 +157,7 @@ impl<'a> VariableFixtures<'a>
         let mut arg_c = 1;
 
         for term_ref in iter {
-            if let TermRef::Var(lvl, cell, var) = term_ref {
+            if let &TermRef::Var(lvl, cell, ref var) = &term_ref {
                 let mut status = self.0.remove(var)
                     .unwrap_or((VarStatus::Temp(chunk_num, TempVarData::new(lt_arity)), Vec::new()));
 
@@ -194,7 +172,7 @@ impl<'a> VariableFixtures<'a>
                     _ => status.0 = VarStatus::Perm(chunk_num)
                 };
 
-                self.0.insert(var, status);
+                self.0.insert(var.clone(), status);
             }
 
             if let Level::Shallow = term_ref.level() {
@@ -203,11 +181,11 @@ impl<'a> VariableFixtures<'a>
         }
     }
 
-    pub fn into_iter(self) -> IntoIter<&'a Var, VariableFixture<'a>> {
+    pub fn into_iter(self) -> IntoIter<Rc<Var>, VariableFixture<'a>> {
         self.0.into_iter()
     }
 
-    fn values(&self) -> Values<&'a Var, VariableFixture<'a>> {
+    fn values(&self) -> Values<Rc<Var>, VariableFixture<'a>> {
         self.0.values()
     }
 
index c81c2004e535856c3d533da8f70d999e3ad481a9..d5a42981d23e577cc06822f777c62a7452fca29d 100644 (file)
@@ -1,7 +1,7 @@
 use prolog::ast::*;
+use prolog::builtins::*;
 use prolog::codegen::*;
 use prolog::debray_allocator::*;
-use prolog::fixtures::*;
 use prolog::heap_print::*;
 use prolog::machine::*;
 use prolog::parser::toplevel::*;
@@ -306,9 +306,11 @@ impl fmt::Display for IndexingInstruction {
 impl fmt::Display for EvalError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
+            &EvalError::ModuleNotFound => write!(f, "module not found."),
+            &EvalError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."),
             &EvalError::QueryFailure => write!(f, "false."),
             &EvalError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)),
-            &EvalError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite builtin {}", msg),
+            &EvalError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite builtin {}.", msg),
             &EvalError::OpIsInfixAndPostFix =>
                 write!(f, "cannot define an op to be both postfix and infix."),
             &EvalError::NamelessEntry => write!(f, "the predicate head is not an atom or clause."),
@@ -438,16 +440,10 @@ pub fn print_code(code: &Code) {
     }
 }
 
-pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
+pub fn parse_code(wam: &Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
 {
-    let mut worker = TopLevelWorker::new(wam.atom_tbl(), wam.op_dir());
-    worker.parse_code(buffer)
-}
-
-pub fn parse_batch(wam: &mut Machine, buffer: &str) -> Result<Vec<TopLevelPacket>, ParserError>
-{
-    let mut worker = TopLevelWorker::new(wam.atom_tbl(), wam.op_dir());
-    worker.parse_batch(buffer)
+    let mut worker = TopLevelWorker::new(buffer.as_bytes(), wam.atom_tbl());
+    worker.parse_code(&wam.op_dir)
 }
 
 pub fn read() -> String {
@@ -512,7 +508,7 @@ fn set_first_index(code: &mut Code)
     }
 }
 
-fn compile_appendix(code: &mut Code, queue: &Vec<TopLevel>) -> Result<(), ParserError>
+fn compile_appendix(code: &mut Code, queue: Vec<TopLevel>) -> Result<(), ParserError>
 {
     for tl in queue.iter() {
         set_first_index(code);
@@ -522,31 +518,31 @@ fn compile_appendix(code: &mut Code, queue: &Vec<TopLevel>) -> Result<(), Parser
     Ok(())
 }
 
-fn compile_query<'a>(terms: &'a Vec<QueryTerm>, queue: &'a Vec<TopLevel>)
-                     -> Result<(Code, AllocVarDict<'a>), ParserError>
+fn compile_query(terms: Vec<QueryTerm>, queue: Vec<TopLevel>)
+                 -> Result<(Code, AllocVarDict), ParserError>
 {
     let mut cg = CodeGenerator::<DebrayAllocator>::new();
-    let mut code = try!(cg.compile_query(terms));
+    let mut code = try!(cg.compile_query(&terms));
 
     compile_appendix(&mut code, queue)?;
-    
+
     Ok((code, cg.take_vars()))
 }
 
-fn compile_decl<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel, queue: &'b Vec<TopLevel>)
-                            -> EvalSession<'b>
+fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSession
 {
     match tl {
-        &TopLevel::Declaration(ref decl) => wam.submit_decl(decl),
+        TopLevel::Declaration(Declaration::Op(op_decl)) => {
+            try_eval_session!(op_decl.submit(&mut wam.op_dir));
+            EvalSession::EntrySuccess
+        },
+        TopLevel::Declaration(Declaration::UseModule(name)) =>
+            wam.use_module_in_toplevel(name),
+        TopLevel::Declaration(_) =>
+            EvalSession::from(ParserError::InvalidModuleDecl),
         _ => {
-            let mut code = match compile_relation(tl) {
-                Ok(code) => code,
-                Err(e) => return EvalSession::from(EvalError::ParserError(e))
-            };
-
-            if let Err(e) = compile_appendix(&mut code, queue) {
-                return EvalSession::from(e);
-            };
+            let mut code = try_eval_session!(compile_relation(&tl));
+            try_eval_session!(compile_appendix(&mut code, queue));
 
             if !code.is_empty() {
                 if let Some(name) = tl.name() {
@@ -561,36 +557,87 @@ fn compile_decl<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel, queue: &'b V
     }
 }
 
-pub fn compile<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevelPacket) -> EvalSession<'b>
+pub fn compile_packet(wam: &mut Machine, tl: TopLevelPacket) -> EvalSession
 {
     match tl {
-        &TopLevelPacket::Query(ref terms, ref queue) =>
+        TopLevelPacket::Query(terms, queue) =>
             match compile_query(terms, queue) {
-                Ok((code, vars)) => wam.submit_query(code, vars),
+                Ok((mut code, vars)) => wam.submit_query(code, vars),
                 Err(e) => EvalSession::from(e)
             },
-        &TopLevelPacket::Decl(ref tl, ref queue) =>
+        TopLevelPacket::Decl(tl, queue) =>
             compile_decl(wam, tl, queue)
     }
 }
 
-pub fn compile_batch<'a, 'b: 'a>(wam: &'a mut Machine, tls: &'b Vec<TopLevelPacket>)
-                                 -> EvalSession<'b>
+pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession
 {
+    fn get_module_name(module: &Option<Module>) -> ClauseName {
+        match module {
+            &Some(ref module) => module.module_decl.name.clone(),
+            _ => ClauseName::BuiltIn("builtin")
+        }
+    }
+
+    let mut module: Option<Module> = None;
+    let (mut code_dir, mut op_dir) = build_code_and_op_dirs();
+
+    let mut code = Vec::new();
+
+    let mut worker = TopLevelWorker::new(src_str.as_bytes(), wam.atom_tbl());
+    let tls = try_eval_session!(worker.parse_batch(&mut op_dir));
+    
     for tl in tls {
         match tl {
-            &TopLevelPacket::Query(..) =>
+            TopLevelPacket::Query(..) =>
                 return EvalSession::from(ParserError::ExpectedRel),
-            &TopLevelPacket::Decl(ref tl, ref queue) => {
-                let result = compile_decl(wam, tl, queue);
+            TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Module(module_decl)), _) =>
+                if module.is_none() {
+                    let (builtin_code_dir, builtin_op_dir) = build_code_and_op_dirs();
 
-                if let &EvalSession::Error(_) = &result {
-                    return result;
+                    code_dir.extend(builtin_code_dir.into_iter());
+                    op_dir.extend(builtin_op_dir.into_iter());
+
+                    module = Some(Module::new(module_decl));
+                } else {
+                    return EvalSession::from(ParserError::InvalidModuleDecl);
+                },
+            TopLevelPacket::Decl(TopLevel::Declaration(Declaration::UseModule(name)), _) => {
+                if let Some(ref submodule) = wam.get_module(name.clone()) {
+                    if let Some(ref mut module) = module {
+                        module.use_module(submodule);
+                        continue;
+                    }
+                } else {
+                    return EvalSession::from(EvalError::ModuleNotFound);
                 }
+
+                wam.use_module_in_toplevel(name);
+            },
+            TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Op(..)), _) => {},
+            TopLevelPacket::Decl(decl, queue) => {
+                let p = code.len() + wam.code_size();
+                let mut decl_code = try_eval_session!(compile_relation(&decl));
+
+                try_eval_session!(compile_appendix(&mut decl_code, queue));
+
+                code.extend(decl_code.into_iter());
+                code_dir.insert((decl.name().unwrap(), decl.arity()),
+                                (PredicateKeyType::User, p, get_module_name(&module)));
             }
         }
     }
 
+    if let Some(mut module) = module {
+        module.code_dir = code_dir;
+        module.op_dir = op_dir;
+
+        wam.add_module(module, code);
+    } else {
+        wam.add_batched_code(code, code_dir);
+        wam.add_batched_ops(op_dir);
+    }
+
     EvalSession::EntrySuccess
 }
 
index 29035a28f324d30b9c527462b19b70972e486d3f..e8bee4296db0fd38766192ad028afc9e77b012c5 100644 (file)
@@ -34,7 +34,7 @@ impl<'a> QueryIterator<'a> {
             &Term::Constant(_, _) =>
                 return QueryIterator { state_stack: vec![] },
             &Term::Var(ref cell, ref var) =>
-                TermIterState::Var(Level::Root, cell, var)
+                TermIterState::Var(Level::Root, cell, (*var).clone())
         };
 
         QueryIterator { state_stack: vec![state] }
@@ -138,7 +138,7 @@ impl<'a> FactIterator<'a> {
             &Term::Constant(ref cell, ref constant) =>
                 vec![TermIterState::Constant(Level::Root, cell, constant)],
             &Term::Var(ref cell, ref var) =>
-                vec![TermIterState::Var(Level::Root, cell, var)]
+                vec![TermIterState::Var(Level::Root, cell, var.clone())]
         };
 
         FactIterator { state_queue: VecDeque::from(states) }
index df794db4f9e5625158d34a2ba96f4c897bf3e618..1501bb81bb7e319d83a78c6c2aa1875b7ef0275e 100644 (file)
@@ -1,9 +1,13 @@
+:- module(control, [(\=)/2, between/3, call_cleanup/2, once/1]).
+
 :- op(700, xfx, \=).
 
 once(G) :- G, !.
 
-\=(X, X) :- !, false.
-\=(_, _).
+X \= X :- !, false.
+_ \= _.
+
+call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
 
 between(Lower, Upper, Lower) :-
     Lower =< Upper.
index 3816c546e4c7574af35d9efb989df964802c313e..f8c49710324404dc2d49d0c0627ce0f091dd75ff 100644 (file)
@@ -1,3 +1,7 @@
+:- module(lists, [member/2, select/3, append/3, memberchk/2, reverse/2, maplist/2,
+                 maplist/3, maplist/4, maplist/5, maplist/6, maplist/7, maplist/8,
+                 maplist/9]).
+
 member(X, [X|_]).
 member(X, [_|Xs]) :- member(X, Xs).
 
index b5f9838b2225d6d8353e1927986df605d4763ddc..d2e6bc065035bbf1f1785755b41faf3b7c3579d6 100644 (file)
@@ -1,5 +1,4 @@
 use prolog::and_stack::*;
-use prolog::builtins::CodeDir;
 use prolog::ast::*;
 use prolog::copier::*;
 use prolog::num::{BigInt, BigUint, Zero, One};
@@ -8,10 +7,40 @@ use prolog::tabled_rc::*;
 
 use downcast::Any;
 
+use std::collections::HashMap;
 use std::mem::swap;
 use std::ops::{Index, IndexMut};
 use std::rc::Rc;
 
+pub(crate) struct CodeDirs<'a> {
+    code_dir: &'a CodeDir,
+    modules: &'a HashMap<ClauseName, Module>
+}
+
+impl<'a> CodeDirs<'a> {
+    pub(super) fn new(code_dir: &'a CodeDir, modules: &'a HashMap<ClauseName, Module>) -> Self {
+        CodeDirs { code_dir, modules }
+    }
+
+    fn get_current_code_dir(&self, p: &CodePtr) -> &CodeDir {
+        let module_name = p.module_name();
+
+        match module_name {
+            ClauseName::BuiltIn("user") | ClauseName::BuiltIn("builtin") =>
+                self.code_dir,
+            _ =>
+                &self.modules.get(&module_name).unwrap().code_dir
+        }
+    }
+
+    pub(crate) fn get(&self, name: ClauseName, arity: usize, p: &CodePtr)
+                      -> Option<(usize, ClauseName)>
+    {
+        let code_dir = self.get_current_code_dir(p);        
+        code_dir.get(&(name, arity)).map(|idx| (idx.1, idx.2.clone()))
+    }
+}
+
 pub(super) struct DuplicateTerm<'a> {
     state: &'a mut MachineState
 }
@@ -184,36 +213,40 @@ pub struct MachineState {
 pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
 
 pub(crate) trait CallPolicy: Any {
-    fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
-                name: ClauseName, arity: usize)
-                -> CallResult
+    fn try_call<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
+                    name: ClauseName, arity: usize)
+                    -> CallResult
     {
-        let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
+        let compiled_tl_index = code_dirs.get(name, arity, &machine_st.p);
 
         match compiled_tl_index {
             Some(compiled_tl_index) => {
-                machine_st.cp = machine_st.p + 1;
+                let module_name = compiled_tl_index.1.clone();
+
+                machine_st.cp = machine_st.p.clone() + 1;
                 machine_st.num_of_args = arity;
                 machine_st.b0 = machine_st.b;
-                machine_st.p  = CodePtr::DirEntry(compiled_tl_index);
+                machine_st.p  = CodePtr::DirEntry(compiled_tl_index.0, module_name);
             },
             None => machine_st.fail = true
         };
-
+        
         Ok(())
     }
 
-    fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
-                   name: ClauseName, arity: usize)
-                   -> CallResult
+    fn try_execute<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
+                       name: ClauseName, arity: usize)
+                       -> CallResult
     {
-        let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
+        let compiled_tl_index = code_dirs.get(name, arity, &machine_st.p);
 
         match compiled_tl_index {
             Some(compiled_tl_index) => {
+                let module_name = compiled_tl_index.1.clone();
+
                 machine_st.num_of_args = arity;
                 machine_st.b0 = machine_st.b;
-                machine_st.p  = CodePtr::DirEntry(compiled_tl_index);
+                machine_st.p  = CodePtr::DirEntry(compiled_tl_index.0, module_name);
             },
             None => machine_st.fail = true
         };
@@ -231,9 +264,9 @@ pub(crate) trait CallPolicy: Any {
         }
 
         machine_st.e  = machine_st.or_stack[b].e;
-        machine_st.cp = machine_st.or_stack[b].cp;
+        machine_st.cp = machine_st.or_stack[b].cp.clone();
 
-        machine_st.or_stack[b].bp = machine_st.p + offset;
+        machine_st.or_stack[b].bp = machine_st.p.clone() + offset;
 
         let old_tr  = machine_st.or_stack[b].tr;
         let curr_tr = machine_st.tr;
@@ -261,9 +294,9 @@ pub(crate) trait CallPolicy: Any {
         }
 
         machine_st.e  = machine_st.or_stack[b].e;
-        machine_st.cp = machine_st.or_stack[b].cp;
+        machine_st.cp = machine_st.or_stack[b].cp.clone();
 
-        machine_st.or_stack[b].bp = machine_st.p + 1;
+        machine_st.or_stack[b].bp = machine_st.p.clone() + 1;
 
         let old_tr  = machine_st.or_stack[b].tr;
         let curr_tr = machine_st.tr;
@@ -291,7 +324,7 @@ pub(crate) trait CallPolicy: Any {
         }
 
         machine_st.e  = machine_st.or_stack[b].e;
-        machine_st.cp = machine_st.or_stack[b].cp;
+        machine_st.cp = machine_st.or_stack[b].cp.clone();
 
         let old_tr  = machine_st.or_stack[b].tr;
         let curr_tr = machine_st.tr;
@@ -322,7 +355,7 @@ pub(crate) trait CallPolicy: Any {
         }
 
         machine_st.e  = machine_st.or_stack[b].e;
-        machine_st.cp = machine_st.or_stack[b].cp;
+        machine_st.cp = machine_st.or_stack[b].cp.clone();
 
         let old_tr  = machine_st.or_stack[b].tr;
         let curr_tr = machine_st.tr;
@@ -351,7 +384,7 @@ pub(crate) struct DefaultCallPolicy {}
 
 impl CallPolicy for DefaultCallPolicy {}
 
-pub(crate) struct CallWithInferenceLimitCallPolicy {    
+pub(crate) struct CallWithInferenceLimitCallPolicy {
     pub(crate) prev_policy: Box<CallPolicy>,
     count:  BigUint,
     limits: Vec<(BigUint, usize)>
@@ -378,7 +411,7 @@ impl CallWithInferenceLimitCallPolicy {
                 self.count += BigUint::one();
             }
         }
-        
+
         Ok(())
     }
 
@@ -418,19 +451,19 @@ impl CallWithInferenceLimitCallPolicy {
 }
 
 impl CallPolicy for CallWithInferenceLimitCallPolicy {
-    fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
-                name: ClauseName, arity: usize)
+    fn try_call<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
+                    name: ClauseName, arity: usize)
                 -> CallResult
     {
-        self.prev_policy.try_call(machine_st, code_dir, name, arity)?;
+        self.prev_policy.try_call(machine_st, code_dirs, name, arity)?;
         self.increment()
     }
 
-    fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
-                   name: ClauseName, arity: usize)
-                   -> CallResult
+    fn try_execute<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
+                       name: ClauseName, arity: usize)
+                       -> CallResult
     {
-        self.prev_policy.try_execute(machine_st, code_dir, name, arity)?;
+        self.prev_policy.try_execute(machine_st, code_dirs, name, arity)?;
         self.increment()
     }
 
@@ -527,10 +560,11 @@ impl CutPolicy for SetupCallCleanupCutPolicy {
         machine_st.p += 1;
 
         if !self.out_of_cont_pts() {
-            machine_st.cp = machine_st.p;
+            machine_st.cp = machine_st.p.clone();
             machine_st.num_of_args = 0;
             machine_st.b0 = machine_st.b;
-            machine_st.p  = CodePtr::DirEntry(354); // goto_call run_cleaners_without_handling/0, 354.
+            // goto_call run_cleaners_without_handling/0, 354.
+            machine_st.p = CodePtr::DirEntry(354, clause_name!("builtin"));
         }
     }
 }
index 7bb6be194c26cb57bcad654c345b4fe8d54148fc..c8d169cd24aa08309bf9b24123cddb30d80a142b 100644 (file)
@@ -1,6 +1,5 @@
 use prolog::and_stack::*;
 use prolog::ast::*;
-use prolog::builtins::*;
 use prolog::copier::*;
 use prolog::heap_iter::*;
 use prolog::heap_print::*;
@@ -908,7 +907,8 @@ impl MachineState {
         }
     }
 
-    fn handle_internal_call_n(&mut self, call_policy: &mut Box<CallPolicy>, code_dir: &CodeDir)
+    fn handle_internal_call_n<'a>(&mut self, call_policy: &mut Box<CallPolicy>,
+                                  code_dirs: CodeDirs<'a>)
     {
         let arity = self.num_of_args + 1;
         let pred  = self.registers[1].clone();
@@ -921,7 +921,7 @@ impl MachineState {
             self.registers[arity - 1] = pred;
 
             if let Some((name, arity)) = self.setup_call_n(arity - 1) {
-                try_or_fail!(self, call_policy.try_execute(self, code_dir, name, arity));
+                try_or_fail!(self, call_policy.try_execute(self, code_dirs, name, arity));
             }
         } else {
             self.fail = true;
@@ -931,7 +931,7 @@ impl MachineState {
     fn goto_throw(&mut self) {
         self.num_of_args = 1;
         self.b0 = self.b;
-        self.p  = CodePtr::DirEntry(59);
+        self.p  = CodePtr::DirEntry(59, clause_name!("builtin"));
     }
 
     fn throw_exception(&mut self, hcv: Vec<HeapCellValue>) {
@@ -1209,10 +1209,10 @@ impl MachineState {
         };
     }
 
-    pub(super) fn execute_built_in_instr(&mut self, code_dir: &CodeDir,
-                                         call_policy: &mut Box<CallPolicy>,
-                                         cut_policy:  &mut Box<CutPolicy>,
-                                         instr: &BuiltInInstruction)
+    pub(super) fn execute_built_in_instr<'a>(&mut self, code_dirs: CodeDirs<'a>,
+                                             call_policy: &mut Box<CallPolicy>,
+                                             cut_policy:  &mut Box<CutPolicy>,
+                                             instr: &BuiltInInstruction)
     {
         match instr {
             &BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) => {
@@ -1253,7 +1253,7 @@ impl MachineState {
             &BuiltInInstruction::GetArgExecute =>
                 try_or_fail!(self, {
                     let val = self.try_get_arg();
-                    self.p = self.cp;
+                    self.p = self.cp.clone();
                     val
                 }),
             &BuiltInInstruction::GetCurrentBlock => {
@@ -1537,7 +1537,7 @@ impl MachineState {
                 self.fail = true;
             },
             &BuiltInInstruction::InternalCallN =>
-                self.handle_internal_call_n(call_policy, code_dir),
+                self.handle_internal_call_n(call_policy, code_dirs),
             &BuiltInInstruction::Fail => {
                 self.fail = true;
                 self.p += 1;
@@ -1728,10 +1728,10 @@ impl MachineState {
         false
     }
 
-    pub(super) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir,
-                                     call_policy: &mut Box<CallPolicy>,
-                                     cut_policy:  &mut Box<CutPolicy>,
-                                     instr: &ControlInstruction)
+    pub(super) fn execute_ctrl_instr<'a>(&mut self, code_dirs: CodeDirs<'a>,
+                                         call_policy: &mut Box<CallPolicy>,
+                                         cut_policy:  &mut Box<CutPolicy>,
+                                         instr: &ControlInstruction)
     {
         match instr {
             &ControlInstruction::Allocate(num_cells) => {
@@ -1749,7 +1749,7 @@ impl MachineState {
                         let index = self.e + 1;
 
                         self.and_stack[index].e  = self.e;
-                        self.and_stack[index].cp = self.cp;
+                        self.and_stack[index].cp = self.cp.clone();
                         self.and_stack[index].global_index = gi;
 
                         self.and_stack.resize(index, num_cells);
@@ -1760,48 +1760,49 @@ impl MachineState {
                     }
                 }
 
-                self.and_stack.push(gi, self.e, self.cp, num_cells);
+                self.and_stack.push(gi, self.e, self.cp.clone(), num_cells);
                 self.e = self.and_stack.len() - 1;
             },
             &ControlInstruction::ArgCall => {
-                self.cp = self.p + 1;
+                self.cp = self.p.clone() + 1;
                 self.num_of_args = 3;
                 self.b0 = self.b;
-                self.p  = CodePtr::DirEntry(150);
+                self.p  = CodePtr::DirEntry(150, clause_name!("builtin"));
             },
             &ControlInstruction::ArgExecute => {
                 self.num_of_args = 3;
                 self.b0 = self.b;
-                self.p  = CodePtr::DirEntry(150);
+                self.p  = CodePtr::DirEntry(150, clause_name!("builtin"));
             },
             &ControlInstruction::Call(ref name, arity, _) =>
-                try_or_fail!(self, call_policy.try_call(self, code_dir, name.clone(), arity)),
+                try_or_fail!(self, call_policy.try_call(self, code_dirs, name.clone(), arity)),
             &ControlInstruction::CatchCall => {
-                self.cp = self.p + 1;
+                self.cp = self.p.clone() + 1;
                 self.num_of_args = 3;
                 self.b0 = self.b;
-                self.p  = CodePtr::DirEntry(5);
+                self.p  = CodePtr::DirEntry(5, clause_name!("builtin"));
             },
             &ControlInstruction::CatchExecute => {
                 self.num_of_args = 3;
                 self.b0 = self.b;
-                self.p  = CodePtr::DirEntry(5);
+                self.p  = CodePtr::DirEntry(5, clause_name!("builtin"));
             },
             &ControlInstruction::CallN(arity) =>
                 if let Some((name, arity)) = self.setup_call_n(arity) {
-                    try_or_fail!(self, call_policy.try_call(self, code_dir, name, arity))
+                    try_or_fail!(self, call_policy.try_call(self, code_dirs, name, arity))
                 },
             &ControlInstruction::CheckCpExecute => {
                 let a = self.store(self.deref(self[temp_v!(2)].clone()));
 
                 match a {
                     Addr::Con(Constant::Usize(old_b)) if self.b > old_b + 1 => {
-                        self.p = self.cp;
+                        self.p = self.cp.clone();
                     },
                     _ => {
                         self.num_of_args = 2;
                         self.b0 = self.b;
-                        self.p = CodePtr::DirEntry(366); // goto sgc_on_success/2, 366.
+                        // goto sgc_on_success/2, 366.
+                        self.p = CodePtr::DirEntry(366, clause_name!("builtin"));
                     }
                 };
             },
@@ -1833,7 +1834,7 @@ impl MachineState {
 
                 self.unify(a1, c);
 
-                self.p = self.cp;
+                self.p = self.cp.clone();
             },
             &ControlInstruction::CompareTermCall(qt) => {
                 match qt {
@@ -1855,12 +1856,12 @@ impl MachineState {
                     _ => self.compare_term(qt)
                 };
 
-                self.p = self.cp;
+                self.p = self.cp.clone();
             },
             &ControlInstruction::Deallocate => {
                 let e = self.e;
 
-                self.cp = self.and_stack[e].cp;
+                self.cp = self.and_stack[e].cp.clone();
                 self.e  = self.and_stack[e].e;
 
                 self.p += 1;
@@ -1881,7 +1882,7 @@ impl MachineState {
 
                 println!("{}", output.result());
 
-                self.p = self.cp;
+                self.p = self.cp.clone();
             },
             &ControlInstruction::DuplicateTermCall => {
                 self.duplicate_term();
@@ -1889,7 +1890,7 @@ impl MachineState {
             },
             &ControlInstruction::DuplicateTermExecute => {
                 self.duplicate_term();
-                self.p = self.cp;
+                self.p = self.cp.clone();
             },
             &ControlInstruction::DynamicIs => {
                 let a = self[temp_v!(1)].clone();
@@ -1904,7 +1905,7 @@ impl MachineState {
             },
             &ControlInstruction::EqExecute => {
                 self.fail = self.eq_test();
-                self.p = self.cp;
+                self.p = self.cp.clone();
             },
             &ControlInstruction::GroundCall => {
                 self.fail = self.ground_test();
@@ -1912,13 +1913,13 @@ impl MachineState {
             },
             &ControlInstruction::GroundExecute => {
                 self.fail = self.ground_test();
-                self.p = self.cp;
+                self.p = self.cp.clone();
             },
             &ControlInstruction::Execute(ref name, arity) =>
-                try_or_fail!(self, call_policy.try_execute(self, code_dir, name.clone(), arity)),
+                try_or_fail!(self, call_policy.try_execute(self, code_dirs, name.clone(), arity)),
             &ControlInstruction::ExecuteN(arity) =>
                 if let Some((name, arity)) = self.setup_call_n(arity) {
-                    try_or_fail!(self, call_policy.try_execute(self, code_dir, name, arity))
+                    try_or_fail!(self, call_policy.try_execute(self, code_dirs, name, arity))
                 },
             &ControlInstruction::FunctorCall =>
                 try_or_fail!(self, {
@@ -1929,7 +1930,7 @@ impl MachineState {
             &ControlInstruction::FunctorExecute =>
                 try_or_fail!(self, {
                     let val = self.try_functor();
-                    self.p = self.cp;
+                    self.p = self.cp.clone();
                     val
                 }),
             &ControlInstruction::GetCleanerCall => {
@@ -1958,15 +1959,15 @@ impl MachineState {
                 self.fail = true;
             },
             &ControlInstruction::GotoCall(p, arity) => {
-                self.cp = self.p + 1;
+                self.cp = self.p.clone() + 1;
                 self.num_of_args = arity;
                 self.b0 = self.b;
-                self.p  = CodePtr::DirEntry(p);
+                self.p  = CodePtr::DirEntry(p, clause_name!("builtin"));
             },
             &ControlInstruction::GotoExecute(p, arity) => {
                 self.num_of_args = arity;
                 self.b0 = self.b;
-                self.p  = CodePtr::DirEntry(p);
+                self.p  = CodePtr::DirEntry(p, clause_name!("builtin"));
             },
             &ControlInstruction::IsCall(r, ref at) => {
                 let a1 = self[r].clone();
@@ -1980,10 +1981,10 @@ impl MachineState {
                 let a2 = try_or_fail!(self, self.get_number(at));
 
                 self.unify(a1, Addr::Con(Constant::Number(a2)));
-                self.p = self.cp;
+                self.p = self.cp.clone();
             },
             &ControlInstruction::JmpByCall(arity, offset) => {
-                self.cp = self.p + 1;
+                self.cp = self.p.clone() + 1;
                 self.num_of_args = arity;
                 self.b0 = self.b;
                 self.p += offset;
@@ -1999,12 +2000,12 @@ impl MachineState {
             },
             &ControlInstruction::NotEqExecute => {
                 self.fail = !self.eq_test();
-                self.p = self.cp;
+                self.p = self.cp.clone();
             },
             &ControlInstruction::Proceed =>
-                self.p = self.cp,
+                self.p = self.cp.clone(),
             &ControlInstruction::ThrowCall => {
-                self.cp = self.p + 1;
+                self.cp = self.p.clone() + 1;
                 self.goto_throw();
             },
             &ControlInstruction::ThrowExecute => {
@@ -2023,9 +2024,9 @@ impl MachineState {
 
                 self.or_stack.push(gi,
                                    self.e,
-                                   self.cp,
+                                   self.cp.clone(),
                                    self.b,
-                                   self.p + 1,
+                                   self.p.clone() + 1,
                                    self.tr,
                                    self.heap.h,
                                    self.b0,
@@ -2058,9 +2059,9 @@ impl MachineState {
 
                 self.or_stack.push(gi,
                                    self.e,
-                                   self.cp,
+                                   self.cp.clone(),
                                    self.b,
-                                   self.p + offset,
+                                   self.p.clone() + offset,
                                    self.tr,
                                    self.heap.h,
                                    self.b0,
index 0d012eb75c23c77c89fc4f477a33b97a58394dd1..6377e17e17c1c737ee90dcab82caa537af6a1cd3 100644 (file)
@@ -1,8 +1,6 @@
 use prolog::ast::*;
 use prolog::builtins::*;
-use prolog::codegen::*;
 use prolog::heap_print::*;
-use prolog::fixtures::*;
 use prolog::tabled_rc::*;
 
 pub(crate) mod machine_state;
@@ -17,13 +15,19 @@ use std::mem::swap;
 use std::ops::Index;
 use std::rc::Rc;
 
+struct MachineCodeIndex<'a> {
+    code_dir: &'a mut CodeDir,
+    op_dir: &'a mut OpDir
+}
+
 pub struct Machine {
     ms: MachineState,
     call_policy: Box<CallPolicy>,
     cut_policy: Box<CutPolicy>,
     code: Code,
     code_dir: CodeDir,
-    op_dir: OpDir,
+    pub op_dir: OpDir,
+    modules: HashMap<ClauseName, Module>,
     cached_query: Option<Code>
 }
 
@@ -38,16 +42,26 @@ impl Index<CodePtr> for Machine {
                     &None => panic!("Out-of-bounds top level index.")
                 }
             },
-            CodePtr::DirEntry(p) => &self.code[p]
+            CodePtr::DirEntry(p, _) => &self.code[p]
         }
     }
 }
 
+impl<'a> SubModuleUser for MachineCodeIndex<'a> {
+    fn op_dir(&mut self) -> &mut OpDir {
+        self.op_dir
+    }
+
+    fn code_dir(&mut self) -> &mut CodeDir {
+        self.code_dir
+    }
+}
+
 impl Machine {
     pub fn new() -> Self {
         let atom_tbl = Rc::new(RefCell::new(HashSet::new()));
-        let (code, code_dir, op_dir) = build_code_dir();
-
+        let (code, code_dir, op_dir) = default_build();
+        
         Machine {
             ms: MachineState::new(atom_tbl),
             call_policy: Box::new(DefaultCallPolicy {}),
@@ -55,6 +69,7 @@ impl Machine {
             code,
             code_dir,
             op_dir,
+            modules: HashMap::new(),
             cached_query: None
         }
     }
@@ -67,30 +82,62 @@ impl Machine {
         self.ms.atom_tbl.clone()
     }
 
-    pub fn add_user_code<'a>(&mut self, name: ClauseName, arity: usize, mut code: Code)
-                             -> EvalSession<'a>
+    pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession {
+        match self.modules.get(&name) {
+            Some(ref module) => {
+                let mut indices = MachineCodeIndex { code_dir: &mut self.code_dir,
+                                                     op_dir: &mut self.op_dir };
+                indices.use_module(module)
+            },
+            None => EvalSession::from(EvalError::ModuleNotFound)
+        }
+    }
+    
+    pub fn get_module(&self, name: ClauseName) -> Option<&Module> {
+        self.modules.get(&name)
+    }
+    
+    pub fn add_batched_code(&mut self, mut code: Code, code_dir: CodeDir) {
+        self.code.append(&mut code);
+        self.code_dir.extend(code_dir.into_iter());
+    }
+
+    pub fn add_batched_ops(&mut self, op_dir: OpDir) {        
+        self.op_dir.extend(op_dir.into_iter());
+    }
+
+    pub fn add_module(&mut self, module: Module, code: Code) {
+        self.modules.insert(module.module_decl.name.clone(), module);
+        self.code.extend(code.into_iter());
+    }
+    
+    pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code) -> EvalSession
     {
         match self.code_dir.get(&(name.clone(), arity)) {
-            Some(&(PredicateKeyType::BuiltIn, _)) =>
+            Some(&(PredicateKeyType::BuiltIn, _, _)) =>
                 return EvalSession::from(EvalError::ImpermissibleEntry(format!("{}/{}", name, arity))),
             _ => {}
         };
 
         let offset = self.code.len();
 
-        self.code.append(&mut code);
-        self.code_dir.insert((name, arity), (PredicateKeyType::User, offset));
+        self.code.extend(code.into_iter());
+        self.code_dir.insert((name, arity), (PredicateKeyType::User, offset, clause_name!("user")));
 
         EvalSession::EntrySuccess
     }
 
+    pub fn code_size(&self) -> usize {
+        self.code.len()
+    }
+    
     fn cached_query_size(&self) -> usize {
         match &self.cached_query {
             &Some(ref query) => query.len(),
             _ => 0
         }
     }
-
+    
     fn execute_instr(&mut self)
     {
         let instr = match self.ms.p {
@@ -100,22 +147,26 @@ impl Machine {
                     &None => return
                 }
             },
-            CodePtr::DirEntry(p) => &self.code[p]
+            CodePtr::DirEntry(p, _) => &self.code[p]
         };
 
         match instr {
             &Line::Arithmetic(ref arith_instr) =>
                 self.ms.execute_arith_instr(arith_instr),
-            &Line::BuiltIn(ref built_in_instr) =>
-                self.ms.execute_built_in_instr(&self.code_dir, &mut self.call_policy,
-                                               &mut self.cut_policy, built_in_instr),
+            &Line::BuiltIn(ref built_in_instr) => {
+                let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
+                self.ms.execute_built_in_instr(code_dirs, &mut self.call_policy,
+                                               &mut self.cut_policy, built_in_instr);
+            },
             &Line::Choice(ref choice_instr) =>
                 self.ms.execute_choice_instr(choice_instr, &mut self.call_policy),
             &Line::Cut(ref cut_instr) =>
                 self.ms.execute_cut_instr(cut_instr, &mut self.cut_policy),
-            &Line::Control(ref control_instr) =>
-                self.ms.execute_ctrl_instr(&self.code_dir, &mut self.call_policy,
-                                           &mut self.cut_policy, control_instr),
+            &Line::Control(ref control_instr) => {
+                let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
+                self.ms.execute_ctrl_instr(code_dirs, &mut self.call_policy,
+                                           &mut self.cut_policy, control_instr)
+            },
             &Line::Fact(ref fact) => {
                 for fact_instr in fact {
                     if self.failed() {
@@ -151,7 +202,7 @@ impl Machine {
             let b = self.ms.b - 1;
 
             self.ms.b0 = self.ms.or_stack[b].b0;
-            self.ms.p  = self.ms.or_stack[b].bp;
+            self.ms.p  = self.ms.or_stack[b].bp.clone();
 
             if let CodePtr::TopLevel(_, p) = self.ms.p {
                 self.ms.fail = p == 0;
@@ -173,14 +224,14 @@ impl Machine {
             }
 
             match self.ms.p {
-                CodePtr::DirEntry(p) if p < self.code.len() => {},
+                CodePtr::DirEntry(p, _) if p < self.code.len() => {},
                 _ => break
             };
         }
     }
 
-    fn record_var_places<'a>(&self, chunk_num: usize,
-                             alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
+    fn record_var_places(&self, chunk_num: usize, alloc_locs: &AllocVarDict,
+                         heap_locs: &mut HeapVarDict)
     {
         for (var, var_data) in alloc_locs {
             match var_data {
@@ -190,14 +241,14 @@ impl Machine {
                     let r = var_data.as_reg_type().reg_num();
                     let addr = self.ms.and_stack[e][r].clone();
 
-                    heap_locs.insert(var, addr);
+                    heap_locs.insert(var.clone(), addr);
                 },
                 &VarData::Temp(cn, _, _) if cn == chunk_num => {
                     let r = var_data.as_reg_type();
                     
                     if r.reg_num() != 0 {
                         let addr = self.ms[r].clone();
-                        heap_locs.insert(var, addr);
+                        heap_locs.insert(var.clone(), addr);
                     }
                 },
                 _ => {}
@@ -205,7 +256,7 @@ impl Machine {
         }
     }
 
-    fn run_query<'a>(&mut self, alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
+    fn run_query(&mut self, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict)
     {
         let end_ptr = CodePtr::TopLevel(0, self.cached_query_size());        
         
@@ -237,7 +288,7 @@ impl Machine {
         }
     }
 
-    fn fail<'a>(&mut self) -> EvalSession<'a>
+    fn fail(&mut self) -> EvalSession
     {
         if self.ms.ball.1.len() > 0 {
             let h = self.ms.heap.h;
@@ -253,45 +304,8 @@ impl Machine {
             EvalSession::from(EvalError::QueryFailure)
         }
     }
-
-    pub fn submit_decl<'a>(&mut self, decl: &Declaration) -> EvalSession<'a>
-    {
-        match decl {
-            &Declaration::Op(prec, spec, ref name) => {
-                if is_infix!(spec) {
-                    match self.op_dir.get(&(name.clone(), Fixity::Post)) {
-                        Some(_) => return EvalSession::from(EvalError::OpIsInfixAndPostFix),
-                        _ => {}
-                    };
-                }
-
-                if is_postfix!(spec) {
-                    match self.op_dir.get(&(name.clone(), Fixity::In)) {
-                        Some(_) => return EvalSession::from(EvalError::OpIsInfixAndPostFix),
-                        _ => {}
-                    };
-                }
-
-                if prec > 0 {
-                    match spec {
-                        XFY | XFX | YFX => self.op_dir.insert((name.clone(), Fixity::In),
-                                                              (spec, prec)),
-                        XF | YF => self.op_dir.insert((name.clone(), Fixity::Post), (spec, prec)),
-                        FX | FY => self.op_dir.insert((name.clone(), Fixity::Pre), (spec,prec)),
-                        _ => None
-                    };
-                } else {
-                    self.op_dir.remove(&(name.clone(), Fixity::Pre));
-                    self.op_dir.remove(&(name.clone(), Fixity::In));
-                    self.op_dir.remove(&(name.clone(), Fixity::Post));
-                }
-
-                EvalSession::EntrySuccess
-            }
-        }
-    }
-
-    pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
+    
+    pub fn submit_query(&mut self, code: Code, alloc_locs: AllocVarDict) -> EvalSession
     {
         let mut heap_locs = HashMap::new();
 
@@ -305,12 +319,11 @@ impl Machine {
         }
     }
 
-    pub fn continue_query<'a>(&mut self, alloc_l: &AllocVarDict<'a>, heap_l: &mut HeapVarDict<'a>)
-                              -> EvalSession<'a>
+    pub fn continue_query(&mut self, alloc_l: &AllocVarDict, heap_l: &mut HeapVarDict) -> EvalSession
     {
         if !self.or_stack_is_empty() {
             let b = self.ms.b - 1;
-            self.ms.p = self.ms.or_stack[b].bp;
+            self.ms.p = self.ms.or_stack[b].bp.clone();
 
             if let CodePtr::TopLevel(_, 0) = self.ms.p {
                 return EvalSession::from(EvalError::QueryFailure);
@@ -356,8 +369,4 @@ impl Machine {
         self.cut_policy = Box::new(DefaultCutPolicy {});
         self.ms.reset();
     }
-
-    pub fn op_dir(&self) -> &OpDir {
-        &self.op_dir
-    }
 }
index fd0b5ea613227b88e3c6297eb354f4982d1b5432..01e075f357a902b996a3873449ebcb7e8394d813 100644 (file)
@@ -686,3 +686,18 @@ macro_rules! compare_execute {
         Line::Control(ControlInstruction::CompareExecute)
     )
 }
+
+macro_rules! module_decl {
+    ($name:expr, $decls:expr) => (
+        ModuleDecl { name: $name, exports: $decls }
+    )
+}
+
+macro_rules! try_eval_session {
+    ($e:expr) => (
+        match $e {
+            Ok(result) => result,
+            Err(e) => return EvalSession::from(e)
+        }
+    )
+}
index 0eaa1d9c05ce06ad9ea87cc986d3f647e66f8766..31bde83b71d4168bf38f847c72baf8f10d81210d 100644 (file)
@@ -4,9 +4,10 @@ extern crate ordered_float;
 pub mod allocator;
 pub mod and_stack;
 #[macro_use]
+pub mod macros;
+#[macro_use]
 pub mod ast;
 #[macro_use]
-pub mod macros;
 pub mod arithmetic;
 pub mod builtins;
 pub mod codegen;
@@ -20,6 +21,7 @@ pub mod io;
 pub mod iterators;
 pub mod machine;
 pub mod or_stack;
+#[macro_use]
 pub mod parser;
 pub mod targets;
 pub mod tabled_rc;
index 5b74536d6edfc55c943f77c72a99ad00dcbd96c4..efb52afa2cb121bf0f81ea381510baccf8359773 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5b74536d6edfc55c943f77c72a99ad00dcbd96c4
+Subproject commit efb52afa2cb121bf0f81ea381510baccf8359773
index 09d253a4fd9ebfe3e823d0180ec5081bf839f05f..30824f91e385ffb09c39bf3ad87b2f6dd3030f82 100644 (file)
@@ -54,6 +54,10 @@ impl<T: Hash + Eq> TabledRc<T> {
 
         TabledRc { atom, table }
     }
+
+    pub fn atom_tbl(&self) -> TabledData<T> {
+        self.table.clone()
+    }
 }
 
 impl<T: Hash + Eq> Drop for TabledRc<T> {
index bb31d99e0d2f6f2a81684fe56343e672e55f3a6b..f464c0729c8fc4a62ee9228c298af483ec57b694 100644 (file)
@@ -1,5 +1,4 @@
-use prolog::codegen::*;
-use prolog::fixtures::*;
+use prolog::ast::*;
 use prolog::heap_print::*;
 use prolog::io::*;
 use prolog::machine::*;
@@ -63,9 +62,8 @@ impl HeapCellValueOutputter for TestOutputter {
     }
 }
 
-pub fn collect_test_output<'a>(wam: &mut Machine, alloc_locs: AllocVarDict<'a>,
-                               mut heap_locs: HeapVarDict<'a>)
-                               -> Vec<HashSet<String>>
+pub fn collect_test_output(wam: &mut Machine, alloc_locs: AllocVarDict, mut heap_locs: HeapVarDict)
+                           -> Vec<HashSet<String>>
 {
     let mut output = TestOutputter::new();
     
@@ -81,9 +79,9 @@ pub fn collect_test_output<'a>(wam: &mut Machine, alloc_locs: AllocVarDict<'a>,
     output.result()
 }
 
-pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVarDict<'a>,
-                                          mut heap_locs: HeapVarDict<'a>, limit: usize)
-                                          -> Vec<HashSet<String>>
+pub fn collect_test_output_with_limit(wam: &mut Machine, alloc_locs: AllocVarDict,
+                                      mut heap_locs: HeapVarDict, limit: usize)
+                                      -> Vec<HashSet<String>>
 {
     let mut output = TestOutputter::new();
     
@@ -118,7 +116,7 @@ pub fn submit(wam: &mut Machine, buffer: &str) -> bool
         
     match parse_code(wam, buffer) {
         Ok(tl) =>
-            match compile(wam, &tl) {
+            match compile_packet(wam, tl) {
                 EvalSession::InitialQuerySuccess(_, _) |
                 EvalSession::EntrySuccess |
                 EvalSession::SubsequentQuerySuccess =>
@@ -136,7 +134,7 @@ pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>
 
     match parse_code(wam, buffer) {
         Ok(tl) =>
-            match compile(wam, &tl) {
+            match compile_packet(wam, tl) {
                 EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
                     result == collect_test_output(wam, alloc_locs, heap_locs),
                 EvalSession::EntrySuccess => true,
@@ -155,7 +153,7 @@ pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
 
     match parse_code(wam, buffer) {
         Ok(tl) =>
-            match compile(wam, &tl) {
+            match compile_packet(wam, tl) {
                 EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
                     result == collect_test_output_with_limit(wam, alloc_locs,
                                                              heap_locs, limit),