From: Mark Thom Date: Sat, 3 Mar 2018 05:28:12 +0000 (-0700) Subject: add provisional module support. X-Git-Tag: v0.8.110~545 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=8a6362351648145b16521b0b5d94fca364566394;p=scryer-prolog.git add provisional module support. --- diff --git a/README.md b/README.md index 82fa08e0..3b256fb5 100644 --- 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 diff --git a/src/main.rs b/src/main.rs index c7ae8b1d..4d99223c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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() { diff --git a/src/prolog/allocator.rs b/src/prolog/allocator.rs index cd9f523b..36b9cceb 100644 --- a/src/prolog/allocator.rs +++ b/src/prolog/allocator.rs @@ -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(&mut self, Level, GenContext, &'a Cell, &mut Vec) where Target: CompilationTarget<'a>; - fn mark_var(&mut self, &'a Var, Level, &'a Cell, GenContext, &mut Vec) + fn mark_var(&mut self, Rc, Level, &'a Cell, GenContext, &mut Vec) 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) -> 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, 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() } diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index ce3ce89e..436772fc 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -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, &'a Var) + Var(&'a Cell, Rc) } 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, 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) diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 9721aea1..b0bbc899 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -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; + +pub type CodeDir = HashMap; + +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 +} + +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, + pub conflict_set: BTreeSet +} + +pub type HeapVarDict = HashMap, Addr>; +pub type AllocVarDict = HashMap, 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 for EvalSession { + fn from(err: EvalError) -> Self { + EvalSession::Error(err) + } +} + +impl From for EvalError { + fn from(err: ParserError) -> Self { + EvalError::ParserError(err) + } +} + +impl From 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 { + match self { + Constant::Atom(a) => Some(a), + _ => None + } + } + + pub fn to_integer(self) -> Option> { + 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(&self, state: &mut H) { (*self.as_str()).hash(state) - } + } } impl PartialEq for ClauseName { @@ -523,6 +722,14 @@ impl<'a> From<&'a TabledRc> 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, &'a Term, &'a Term), Constant(Level, &'a Cell, &'a Constant), Clause(Level, &'a Cell, ClauseType, &'a Vec>), - Var(Level, &'a Cell, &'a Var) + Var(Level, &'a Cell, Rc) } 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 for CodePtr { fn partial_cmp(&self, other: &CodePtr) -> Option { 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 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 for CodePtr { impl AddAssign 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 for Heap { pub type Registers = Vec; impl Term { + pub fn to_constant(self) -> Option { + 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, ClauseType, &'a Vec>), InitialCons(Level, &'a Cell, &'a Term, &'a Term), FinalCons(Level, &'a Cell, &'a Term, &'a Term), - Var(Level, &'a Cell, &'a Var) + Var(Level, &'a Cell, Rc) } 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()) } } } diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 2ad9fa70..135eac8b 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -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; - -pub type CodeDir = HashMap; - 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!()), // = 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 } +} diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index 33328ec0..72abc742 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -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 { 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 for EvalSession<'a> { - fn from(err: EvalError) -> Self { - EvalSession::Error(err) - } -} - -impl<'a> From for EvalSession<'a> { - fn from(err: ParserError) -> Self { - EvalSession::from(EvalError::ParserError(err)) - } + var_count: HashMap, 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 { 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, arity: usize, term_loc: GenContext, vr: &'a Cell, 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() { diff --git a/src/prolog/debray_allocator.rs b/src/prolog/debray_allocator.rs index 4fda7415..1bdc5a9e 100644 --- a/src/prolog/debray_allocator.rs +++ b/src/prolog/debray_allocator.rs @@ -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, VarData>, arg_c: usize, temp_lb: usize, - contents: HashMap, + contents: HashMap>, in_use: BTreeSet, } -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, 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(&mut self, chunk_num: usize, target: &mut Vec) + fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec) 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(&mut self, var: &'a Var, lvl: Level, term_loc: GenContext, - target: &mut Vec) + fn alloc_reg_to_var<'a, Target>(&mut self, var: &Var, lvl: Level, term_loc: GenContext, + target: &mut Vec) -> 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(&mut self, var: &'a Var, lvl: Level, cell: &'a Cell, + fn mark_var(&mut self, var: Rc, lvl: Level, cell: &Cell, term_loc: GenContext, target: &mut Vec) 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 } diff --git a/src/prolog/fixtures.rs b/src/prolog/fixtures.rs index 3b9abcf6..34a70751 100644 --- a/src/prolog/fixtures.rs +++ b/src/prolog/fixtures.rs @@ -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, - pub conflict_set: BTreeSet -} - -// 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>); -pub struct VariableFixtures<'a>(BTreeMap<&'a Var, VariableFixture<'a>>); +type VariableFixture<'a> = (VarStatus, Vec<&'a Cell>); +pub struct VariableFixtures<'a>(BTreeMap, 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, 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, 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) -> 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, 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, VariableFixture<'a>> { self.0.into_iter() } - fn values(&self) -> Values<&'a Var, VariableFixture<'a>> { + fn values(&self) -> Values, VariableFixture<'a>> { self.0.values() } diff --git a/src/prolog/io.rs b/src/prolog/io.rs index c81c2004..d5a42981 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -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 +pub fn parse_code(wam: &Machine, buffer: &str) -> Result { - 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, 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) -> Result<(), ParserError> +fn compile_appendix(code: &mut Code, queue: Vec) -> Result<(), ParserError> { for tl in queue.iter() { set_first_index(code); @@ -522,31 +518,31 @@ fn compile_appendix(code: &mut Code, queue: &Vec) -> Result<(), Parser Ok(()) } -fn compile_query<'a>(terms: &'a Vec, queue: &'a Vec) - -> Result<(Code, AllocVarDict<'a>), ParserError> +fn compile_query(terms: Vec, queue: Vec) + -> Result<(Code, AllocVarDict), ParserError> { let mut cg = CodeGenerator::::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) - -> EvalSession<'b> +fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec) -> 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) - -> EvalSession<'b> +pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession { + fn get_module_name(module: &Option) -> ClauseName { + match module { + &Some(ref module) => module.module_decl.name.clone(), + _ => ClauseName::BuiltIn("builtin") + } + } + + let mut module: Option = 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 } diff --git a/src/prolog/iterators.rs b/src/prolog/iterators.rs index 29035a28..e8bee429 100644 --- a/src/prolog/iterators.rs +++ b/src/prolog/iterators.rs @@ -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) } diff --git a/src/prolog/lib/control.pl b/src/prolog/lib/control.pl index df794db4..1501bb81 100644 --- a/src/prolog/lib/control.pl +++ b/src/prolog/lib/control.pl @@ -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. diff --git a/src/prolog/lib/lists.pl b/src/prolog/lib/lists.pl index 3816c546..f8c49710 100644 --- a/src/prolog/lib/lists.pl +++ b/src/prolog/lib/lists.pl @@ -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). diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index b5f9838b..d2e6bc06 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -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 +} + +impl<'a> CodeDirs<'a> { + pub(super) fn new(code_dir: &'a CodeDir, modules: &'a HashMap) -> 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>; 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, 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")); } } } diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 7bb6be19..c8d169cd 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -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, code_dir: &CodeDir) + fn handle_internal_call_n<'a>(&mut self, call_policy: &mut Box, + 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) { @@ -1209,10 +1209,10 @@ impl MachineState { }; } - pub(super) fn execute_built_in_instr(&mut self, code_dir: &CodeDir, - call_policy: &mut Box, - cut_policy: &mut Box, - instr: &BuiltInInstruction) + pub(super) fn execute_built_in_instr<'a>(&mut self, code_dirs: CodeDirs<'a>, + call_policy: &mut Box, + cut_policy: &mut Box, + 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, - cut_policy: &mut Box, - instr: &ControlInstruction) + pub(super) fn execute_ctrl_instr<'a>(&mut self, code_dirs: CodeDirs<'a>, + call_policy: &mut Box, + cut_policy: &mut Box, + 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, diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 0d012eb7..6377e17e 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -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, cut_policy: Box, code: Code, code_dir: CodeDir, - op_dir: OpDir, + pub op_dir: OpDir, + modules: HashMap, cached_query: Option } @@ -38,16 +42,26 @@ impl Index 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 - } } diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index fd0b5ea6..01e075f3 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -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) + } + ) +} diff --git a/src/prolog/mod.rs b/src/prolog/mod.rs index 0eaa1d9c..31bde83b 100644 --- a/src/prolog/mod.rs +++ b/src/prolog/mod.rs @@ -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; diff --git a/src/prolog/parser b/src/prolog/parser index 5b74536d..efb52afa 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit 5b74536d6edfc55c943f77c72a99ad00dcbd96c4 +Subproject commit efb52afa2cb121bf0f81ea381510baccf8359773 diff --git a/src/prolog/tabled_rc.rs b/src/prolog/tabled_rc.rs index 09d253a4..30824f91 100644 --- a/src/prolog/tabled_rc.rs +++ b/src/prolog/tabled_rc.rs @@ -54,6 +54,10 @@ impl TabledRc { TabledRc { atom, table } } + + pub fn atom_tbl(&self) -> TabledData { + self.table.clone() + } } impl Drop for TabledRc { diff --git a/src/test_utils.rs b/src/test_utils.rs index bb31d99e..f464c072 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -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> +pub fn collect_test_output(wam: &mut Machine, alloc_locs: AllocVarDict, mut heap_locs: HeapVarDict) + -> Vec> { 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> +pub fn collect_test_output_with_limit(wam: &mut Machine, alloc_locs: AllocVarDict, + mut heap_locs: HeapVarDict, limit: usize) + -> Vec> { 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 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),