* 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.
* `atomic/1`
* `between/3`
* `call/1..63`
+* `call_cleanup/2`
* `call_with_inference_limit/3`
* `catch/3`
* `compare/3`
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
mod prolog;
#[macro_use] mod test_utils;
+use prolog::ast::*;
use prolog::io::*;
use prolog::machine::*;
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() {
use prolog::targets::*;
use std::cell::Cell;
+use std::rc::Rc;
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);
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>
{
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));
}
};
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()
}
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> {
&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] })
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> {
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))
};
}
pub struct ArithmeticEvaluator<'a> {
- bindings: &'a AllocVarDict<'a>,
+ bindings: &'a AllocVarDict,
interm: Vec<ArithmeticTerm>,
interm_c: usize
}
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 }
}
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)
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;
}
}
+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 {
($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,
InadmissibleQueryTerm,
IncompleteReduction,
InconsistentEntry, // was InconsistentDeclaration.
+ InvalidModuleDecl,
+ InvalidModuleExport,
InvalidRuleHead,
+ InvalidUseModuleDecl,
ParseBigInt,
ParseFloat(ParseFloatError),
// TokenTooLong,
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 {
impl Hash for ClauseName {
fn hash<H: Hasher>(&self, state: &mut H) {
(*self.as_str()).hash(state)
- }
+ }
}
impl PartialEq 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 {
&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 {
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> {
}
}
-#[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),
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)
}
}
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
}
}
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, _) =>
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> {
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) =>
&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())
}
}
}
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.
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!(),
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
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!(),
]
}
-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));
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 }
+}
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> {
}
}
-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()
}
*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),
_ => {
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);
}
} 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),
_ => {}
};
}
} 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);
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));
}
},
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));
},
_ => {
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));
},
_ => {
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));
},
_ => {
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));
},
_ => {
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));
},
_ => {
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));
},
_ => {
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));
}
}
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() {
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) =>
}
}
- 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)) => {
}
}
- 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)) => {
}
}
- 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.
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)));
}
}
}
}
- 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) {
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());
};
}
- 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>
{
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,
}
}
-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,
}
}
- 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)));
},
RegType::Perm(0) => {
let pr = cell.get().norm();
- self.record_register(var, pr);
+ self.record_register(var.clone(), pr);
(pr, true)
},
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);
}
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 {
},
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));
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);
}
}
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
}
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 {
}
}
-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>
{
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);
}
// 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);
}
}
}
}
- 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()
}
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()));
_ => status.0 = VarStatus::Perm(chunk_num)
};
- self.0.insert(var, status);
+ self.0.insert(var.clone(), status);
}
if let Level::Shallow = term_ref.level() {
}
}
- 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()
}
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::*;
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."),
}
}
-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 {
}
}
-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);
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() {
}
}
-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
}
&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] }
&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) }
+:- 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.
+:- 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).
use prolog::and_stack::*;
-use prolog::builtins::CodeDir;
use prolog::ast::*;
use prolog::copier::*;
use prolog::num::{BigInt, BigUint, Zero, One};
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
}
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
};
}
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;
}
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;
}
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;
}
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;
impl CallPolicy for DefaultCallPolicy {}
-pub(crate) struct CallWithInferenceLimitCallPolicy {
+pub(crate) struct CallWithInferenceLimitCallPolicy {
pub(crate) prev_policy: Box<CallPolicy>,
count: BigUint,
limits: Vec<(BigUint, usize)>
self.count += BigUint::one();
}
}
-
+
Ok(())
}
}
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()
}
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"));
}
}
}
use prolog::and_stack::*;
use prolog::ast::*;
-use prolog::builtins::*;
use prolog::copier::*;
use prolog::heap_iter::*;
use prolog::heap_print::*;
}
}
- 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();
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;
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>) {
};
}
- 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) => {
&BuiltInInstruction::GetArgExecute =>
try_or_fail!(self, {
let val = self.try_get_arg();
- self.p = self.cp;
+ self.p = self.cp.clone();
val
}),
&BuiltInInstruction::GetCurrentBlock => {
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;
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) => {
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);
}
}
- 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"));
}
};
},
self.unify(a1, c);
- self.p = self.cp;
+ self.p = self.cp.clone();
},
&ControlInstruction::CompareTermCall(qt) => {
match qt {
_ => 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;
println!("{}", output.result());
- self.p = self.cp;
+ self.p = self.cp.clone();
},
&ControlInstruction::DuplicateTermCall => {
self.duplicate_term();
},
&ControlInstruction::DuplicateTermExecute => {
self.duplicate_term();
- self.p = self.cp;
+ self.p = self.cp.clone();
},
&ControlInstruction::DynamicIs => {
let a = self[temp_v!(1)].clone();
},
&ControlInstruction::EqExecute => {
self.fail = self.eq_test();
- self.p = self.cp;
+ self.p = self.cp.clone();
},
&ControlInstruction::GroundCall => {
self.fail = self.ground_test();
},
&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, {
&ControlInstruction::FunctorExecute =>
try_or_fail!(self, {
let val = self.try_functor();
- self.p = self.cp;
+ self.p = self.cp.clone();
val
}),
&ControlInstruction::GetCleanerCall => {
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();
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;
},
&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 => {
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,
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,
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;
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>
}
&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 {}),
code,
code_dir,
op_dir,
+ modules: HashMap::new(),
cached_query: None
}
}
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 {
&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() {
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;
}
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 {
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);
}
},
_ => {}
}
}
- 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());
}
}
- 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;
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();
}
}
- 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);
self.cut_policy = Box::new(DefaultCutPolicy {});
self.ms.reset();
}
-
- pub fn op_dir(&self) -> &OpDir {
- &self.op_dir
- }
}
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)
+ }
+ )
+}
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;
pub mod iterators;
pub mod machine;
pub mod or_stack;
+#[macro_use]
pub mod parser;
pub mod targets;
pub mod tabled_rc;
-Subproject commit 5b74536d6edfc55c943f77c72a99ad00dcbd96c4
+Subproject commit efb52afa2cb121bf0f81ea381510baccf8359773
TabledRc { atom, table }
}
+
+ pub fn atom_tbl(&self) -> TabledData<T> {
+ self.table.clone()
+ }
}
impl<T: Hash + Eq> Drop for TabledRc<T> {
-use prolog::codegen::*;
-use prolog::fixtures::*;
+use prolog::ast::*;
use prolog::heap_print::*;
use prolog::io::*;
use prolog::machine::*;
}
}
-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();
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();
match parse_code(wam, buffer) {
Ok(tl) =>
- match compile(wam, &tl) {
+ match compile_packet(wam, tl) {
EvalSession::InitialQuerySuccess(_, _) |
EvalSession::EntrySuccess |
EvalSession::SubsequentQuerySuccess =>
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,
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),