add provisional module support.

This commit is contained in:
Mark Thom
2018-03-02 22:28:12 -07:00
parent 33834609c3
commit 8a63623516
21 changed files with 839 additions and 426 deletions

View File

@@ -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)).
```

View File

@@ -5,6 +5,7 @@ extern crate termion;
mod prolog;
#[macro_use] mod test_utils;
use prolog::ast::*;
use prolog::io::*;
use prolog::machine::*;
@@ -17,20 +18,20 @@ pub static CONTROL: &str = include_str!("./prolog/lib/control.pl");
fn process_buffer(wam: &mut Machine, buffer: &str)
{
match parse_code(wam, buffer) {
Ok(tl) => {
let result = compile(wam, &tl);
Ok(packet) => {
let result = compile_packet(wam, packet);
print(wam, result);
},
Err(s) => println!("{:?}", s)
};
}
}
fn load_init_str(wam: &mut Machine, src_str: &str)
{
match parse_batch(wam, src_str) {
Ok(tls) => compile_batch(wam, &tls),
Err(_) => panic!("failed to parse batch from string.")
};
match compile_listing(wam, src_str) {
EvalSession::Error(_) => panic!("failed to parse batch from string."),
_ => {}
}
}
fn prolog_repl() {

View File

@@ -3,6 +3,7 @@ use prolog::fixtures::*;
use prolog::targets::*;
use std::cell::Cell;
use std::rc::Rc;
pub trait Allocator<'a>
{
@@ -12,7 +13,7 @@ pub trait Allocator<'a>
where Target: CompilationTarget<'a>;
fn mark_non_var<Target>(&mut self, Level, GenContext, &'a Cell<RegType>, &mut Vec<Target>)
where Target: CompilationTarget<'a>;
fn mark_var<Target>(&mut self, &'a Var, Level, &'a Cell<VarReg>, GenContext, &mut Vec<Target>)
fn mark_var<Target>(&mut self, Rc<Var>, Level, &'a Cell<VarReg>, GenContext, &mut Vec<Target>)
where Target: CompilationTarget<'a>;
fn reset(&mut self);
@@ -21,10 +22,10 @@ pub trait Allocator<'a>
fn advance_arg(&mut self);
fn bindings(&self) -> &AllocVarDict<'a>;
fn bindings_mut(&mut self) -> &mut AllocVarDict<'a>;
fn bindings(&self) -> &AllocVarDict;
fn bindings_mut(&mut self) -> &mut AllocVarDict;
fn take_bindings(self) -> AllocVarDict<'a>;
fn take_bindings(self) -> AllocVarDict;
fn drain_var_data(&mut self, vs: VariableFixtures<'a>) -> VariableFixtures<'a>
{
@@ -33,10 +34,10 @@ pub trait Allocator<'a>
for (var, (var_status, cells)) in vs.into_iter() {
match var_status {
VarStatus::Temp(chunk_num, tvd) => {
self.bindings_mut().insert(var, VarData::Temp(chunk_num, 0, tvd));
self.bindings_mut().insert(var.clone(), VarData::Temp(chunk_num, 0, tvd));
},
VarStatus::Perm(_) => {
self.bindings_mut().insert(var, VarData::Perm(0));
self.bindings_mut().insert(var.clone(), VarData::Perm(0));
perm_vs.insert(var, (var_status, cells));
}
};
@@ -45,12 +46,12 @@ pub trait Allocator<'a>
perm_vs
}
fn get(&self, var: &'a Var) -> RegType {
self.bindings().get(var).unwrap().as_reg_type()
fn get(&self, var: Rc<Var>) -> RegType {
self.bindings().get(&var).unwrap().as_reg_type()
}
fn record_register(&mut self, var: &'a Var, r: RegType) {
match self.bindings_mut().get_mut(var).unwrap() {
fn record_register(&mut self, var: Rc<Var>, r: RegType) {
match self.bindings_mut().get_mut(&var).unwrap() {
&mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
&mut VarData::Perm(ref mut s) => *s = r.reg_num()
}

View File

@@ -1,8 +1,8 @@
use prolog::ast::*;
use prolog::fixtures::*;
use std::cell::Cell;
use std::cmp::{min, max};
use std::rc::Rc;
use std::vec::Vec;
pub struct ArithInstructionIterator<'a> {
@@ -31,7 +31,7 @@ impl<'a> ArithInstructionIterator<'a> {
&Term::Cons(_, _, _) =>
return Err(ArithmeticError::InvalidTerm),
&Term::Var(ref cell, ref var) =>
TermIterState::Var(Level::Shallow, cell, var)
TermIterState::Var(Level::Shallow, cell, (*var).clone())
};
Ok(ArithInstructionIterator { state_stack: vec![state] })
@@ -41,7 +41,7 @@ impl<'a> ArithInstructionIterator<'a> {
pub enum ArithTermRef<'a> {
Constant(&'a Constant),
Op(ClauseName, usize), // name, arity.
Var(&'a Cell<VarReg>, &'a Var)
Var(&'a Cell<VarReg>, Rc<Var>)
}
impl<'a> Iterator for ArithInstructionIterator<'a> {
@@ -65,7 +65,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
TermIterState::Constant(_, _, c) =>
return Some(Ok(ArithTermRef::Constant(c))),
TermIterState::Var(_, cell, var) =>
return Some(Ok(ArithTermRef::Var(cell, var))),
return Some(Ok(ArithTermRef::Var(cell, var.clone()))),
_ =>
return Some(Err(ArithmeticError::InvalidTerm))
};
@@ -76,7 +76,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
}
pub struct ArithmeticEvaluator<'a> {
bindings: &'a AllocVarDict<'a>,
bindings: &'a AllocVarDict,
interm: Vec<ArithmeticTerm>,
interm_c: usize
}
@@ -97,7 +97,7 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
impl<'a> ArithmeticEvaluator<'a>
{
pub fn new(bindings: &'a AllocVarDict<'a>, target_int: usize) -> Self {
pub fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
ArithmeticEvaluator { bindings, interm: Vec::new(), interm_c: target_int }
}
@@ -207,7 +207,7 @@ impl<'a> ArithmeticEvaluator<'a>
ArithTermRef::Constant(c) => self.push_constant(c)?,
ArithTermRef::Var(cell, name) => {
let r = if cell.get().norm().reg_num() == 0 {
match self.bindings.get(name) {
match self.bindings.get(&name) {
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
_ => return Err(ArithmeticError::UninstantiatedVar)

View File

@@ -6,7 +6,7 @@ use prolog::tabled_rc::*;
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::{HashMap, VecDeque};
use std::collections::{BTreeSet, HashMap, VecDeque};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::io::Error as IOError;
@@ -66,8 +66,90 @@ impl PredicateClause {
}
}
pub type OpDirKey = (ClauseName, Fixity);
// name and fixity -> operator type and precedence.
pub type OpDir = HashMap<OpDirKey, (Specifier, usize)>;
pub type CodeDir = HashMap<PredicateKey, (PredicateKeyType, usize, ClauseName)>;
pub type PredicateKey = (ClauseName, usize); // name, arity.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum PredicateKeyType {
BuiltIn,
User
}
pub struct ModuleDecl {
pub name: ClauseName,
pub exports: Vec<PredicateKey>
}
pub struct Module {
pub module_decl: ModuleDecl,
pub code_dir: CodeDir,
pub op_dir: OpDir
}
impl Module {
pub fn new(module_decl: ModuleDecl) -> Self {
Module { module_decl,
code_dir: CodeDir::new(),
op_dir: OpDir::new() }
}
}
impl SubModuleUser for Module {
fn op_dir(&mut self) -> &mut OpDir {
&mut self.op_dir
}
fn code_dir(&mut self) -> &mut CodeDir {
&mut self.code_dir
}
}
pub trait SubModuleUser {
fn op_dir(&mut self) -> &mut OpDir;
fn code_dir(&mut self) -> &mut CodeDir;
fn use_module(&mut self, submodule: &Module) -> EvalSession {
for (name, arity) in submodule.module_decl.exports.iter().cloned() {
let name = name.defrock_brackets();
if arity == 1 {
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Pre)) {
self.op_dir().insert((name.clone(), Fixity::Pre), op_data.clone());
}
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::Post)) {
self.op_dir().insert((name.clone(), Fixity::Post), op_data.clone());
}
} else if arity == 2 {
if let Some(op_data) = submodule.op_dir.get(&(name.clone(), Fixity::In)) {
self.op_dir().insert((name.clone(), Fixity::In), op_data.clone());
}
}
if self.code_dir().contains_key(&(name.clone(), arity)) {
println!("warning: overwriting {}/{}", &name, arity);
}
if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
self.code_dir().insert((name, arity), code_data.clone());
} else {
return EvalSession::from(EvalError::ModuleDoesNotContainExport);
}
}
EvalSession::EntrySuccess
}
}
pub enum Declaration {
Op(usize, Specifier, ClauseName)
Module(ModuleDecl),
Op(OpDecl),
UseModule(ClauseName)
}
pub enum TopLevel {
@@ -233,6 +315,104 @@ macro_rules! prefix {
($x:expr) => ($x & (FX | FY))
}
// labeled with chunk numbers.
pub enum VarStatus {
Perm(usize), Temp(usize, TempVarData) // Perm(chunk_num) | Temp(chunk_num, _)
}
pub type OccurrenceSet = BTreeSet<(GenContext, usize)>;
// Perm: 0 initially, a stack register once processed.
// Temp: labeled with chunk_num and temp offset (unassigned if 0).
pub enum VarData {
Perm(usize), Temp(usize, usize, TempVarData)
}
pub struct TempVarData {
pub last_term_arity: usize,
pub use_set: OccurrenceSet,
pub no_use_set: BTreeSet<usize>,
pub conflict_set: BTreeSet<usize>
}
pub type HeapVarDict = HashMap<Rc<Var>, Addr>;
pub type AllocVarDict = HashMap<Rc<Var>, VarData>;
pub enum EvalError {
ImpermissibleEntry(String),
ModuleDoesNotContainExport,
ModuleNotFound,
NamelessEntry,
OpIsInfixAndPostFix,
ParserError(ParserError),
QueryFailure,
QueryFailureWithException(String)
}
pub enum EvalSession {
EntrySuccess,
Error(EvalError),
InitialQuerySuccess(AllocVarDict, HeapVarDict),
SubsequentQuerySuccess,
}
impl From<EvalError> for EvalSession {
fn from(err: EvalError) -> Self {
EvalSession::Error(err)
}
}
impl From<ParserError> for EvalError {
fn from(err: ParserError) -> Self {
EvalError::ParserError(err)
}
}
impl From<ParserError> for EvalSession {
fn from(err: ParserError) -> Self {
EvalSession::from(EvalError::ParserError(err))
}
}
pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
impl OpDecl {
pub fn submit(&self, op_dir: &mut OpDir) -> Result<(), EvalError>
{
let (prec, spec, name) = (self.0, self.1, self.2.clone());
if is_infix!(spec) {
match op_dir.get(&(name.clone(), Fixity::Post)) {
Some(_) => return Err(EvalError::OpIsInfixAndPostFix),
_ => {}
};
}
if is_postfix!(spec) {
match op_dir.get(&(name.clone(), Fixity::In)) {
Some(_) => return Err(EvalError::OpIsInfixAndPostFix),
_ => {}
};
}
if prec > 0 {
match spec {
XFY | XFX | YFX => op_dir.insert((name.clone(), Fixity::In),
(spec, prec)),
XF | YF => op_dir.insert((name.clone(), Fixity::Post), (spec, prec)),
FX | FY => op_dir.insert((name.clone(), Fixity::Pre), (spec,prec)),
_ => None
};
} else {
op_dir.remove(&(name.clone(), Fixity::Pre));
op_dir.remove(&(name.clone(), Fixity::In));
op_dir.remove(&(name.clone(), Fixity::Post));
}
Ok(())
}
}
#[derive(Debug, Clone, Copy)]
pub enum ArithmeticError {
InvalidAtom,
@@ -260,7 +440,10 @@ pub enum ParserError
InadmissibleQueryTerm,
IncompleteReduction,
InconsistentEntry, // was InconsistentDeclaration.
InvalidModuleDecl,
InvalidModuleExport,
InvalidRuleHead,
InvalidUseModuleDecl,
ParseBigInt,
ParseFloat(ParseFloatError),
// TokenTooLong,
@@ -305,6 +488,22 @@ pub enum Constant {
EmptyList
}
impl Constant {
pub fn to_atom(self) -> Option<ClauseName> {
match self {
Constant::Atom(a) => Some(a),
_ => None
}
}
pub fn to_integer(self) -> Option<Rc<BigInt>> {
match self {
Constant::Number(Number::Integer(b)) => Some(b),
_ => None
}
}
}
impl fmt::Display for Constant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
@@ -494,7 +693,7 @@ pub enum ClauseName {
impl Hash for ClauseName {
fn hash<H: Hasher>(&self, state: &mut H) {
(*self.as_str()).hash(state)
}
}
}
impl PartialEq for ClauseName {
@@ -523,6 +722,14 @@ impl<'a> From<&'a TabledRc<Atom>> for ClauseName {
}
}
fn defrock_brackets(s: &str) -> &str {
if s.starts_with('(') && s.ends_with(')') {
&s[1 .. s.len() - 1]
} else {
s
}
}
impl ClauseName {
pub fn as_str(&self) -> &str {
match self {
@@ -530,6 +737,16 @@ impl ClauseName {
&ClauseName::User(ref name) => name.as_ref()
}
}
fn defrock_brackets(self) -> Self {
match self {
ClauseName::BuiltIn(s) =>
ClauseName::BuiltIn(defrock_brackets(s)),
ClauseName::User(s) =>
ClauseName::User(tabled_rc!(defrock_brackets(s.as_str()).to_owned(),
s.atom_tbl()))
}
}
}
impl ClauseType {
@@ -599,7 +816,7 @@ pub enum TermRef<'a> {
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Constant(Level, &'a Cell<RegType>, &'a Constant),
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<VarReg>, &'a Var)
Var(Level, &'a Cell<VarReg>, Rc<Var>)
}
impl<'a> TermRef<'a> {
@@ -1196,18 +1413,27 @@ impl HeapCellValue {
}
}
#[derive(Clone, Copy, PartialEq)]
#[derive(Clone, PartialEq)]
pub enum CodePtr {
DirEntry(usize),
DirEntry(usize, ClauseName), // offset, resident module name.
TopLevel(usize, usize) // chunk_num, offset.
}
impl CodePtr {
pub fn module_name(&self) -> ClauseName {
match self {
&CodePtr::DirEntry(_, ref name) => name.clone(),
_ => ClauseName::BuiltIn("user")
}
}
}
impl PartialOrd<CodePtr> for CodePtr {
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
match (self, other) {
(&CodePtr::DirEntry(p1), &CodePtr::DirEntry(ref p2)) =>
p1.partial_cmp(p2),
(&CodePtr::DirEntry(_), &CodePtr::TopLevel(_, _)) =>
(&CodePtr::DirEntry(p1, _), &CodePtr::DirEntry(p2, _)) =>
p1.partial_cmp(&p2),
(&CodePtr::DirEntry(..), &CodePtr::TopLevel(_, _)) =>
Some(Ordering::Less),
(&CodePtr::TopLevel(_, p1), &CodePtr::TopLevel(_, ref p2)) =>
p1.partial_cmp(p2),
@@ -1227,7 +1453,7 @@ impl Add<usize> for CodePtr {
fn add(self, rhs: usize) -> Self::Output {
match self {
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
CodePtr::DirEntry(p, name) => CodePtr::DirEntry(p + rhs, name),
CodePtr::TopLevel(cn, p) => CodePtr::TopLevel(cn, p + rhs)
}
}
@@ -1236,7 +1462,7 @@ impl Add<usize> for CodePtr {
impl AddAssign<usize> for CodePtr {
fn add_assign(&mut self, rhs: usize) {
match self {
&mut CodePtr::DirEntry(ref mut p) |
&mut CodePtr::DirEntry(ref mut p, _) |
&mut CodePtr::TopLevel(_, ref mut p) => *p += rhs
}
}
@@ -1296,6 +1522,13 @@ impl IndexMut<usize> for Heap {
pub type Registers = Vec<Addr>;
impl Term {
pub fn to_constant(self) -> Option<Constant> {
match self {
Term::Constant(_, c) => Some(c),
_ => None
}
}
pub fn first_arg(&self) -> Option<&Term> {
match self {
&Term::Clause(_, _, ref terms, _) =>
@@ -1326,7 +1559,7 @@ pub enum TermIterState<'a> {
Clause(Level, usize, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Var(Level, &'a Cell<VarReg>, &'a Var)
Var(Level, &'a Cell<VarReg>, Rc<Var>)
}
impl<'a> TermIterState<'a> {
@@ -1334,13 +1567,13 @@ impl<'a> TermIterState<'a> {
match term {
&Term::AnonVar =>
TermIterState::AnonVar(lvl),
&Term::Clause(ref cell, ref name, ref subterms, fixity) => {
&Term::Clause(ref cell, ref name, ref subterms, fixity) => {
let ct = if let Some(fixity) = fixity {
ClauseType::Op(name.clone(), fixity)
} else {
ClauseType::Named(name.clone())
};
TermIterState::Clause(lvl, 0, cell, ct, subterms)
},
&Term::Cons(ref cell, ref head, ref tail) =>
@@ -1348,7 +1581,7 @@ impl<'a> TermIterState<'a> {
&Term::Constant(ref cell, ref constant) =>
TermIterState::Constant(lvl, cell, constant),
&Term::Var(ref cell, ref var) =>
TermIterState::Var(lvl, cell, var)
TermIterState::Var(lvl, cell, (*var).clone())
}
}
}

View File

@@ -4,20 +4,6 @@ use prolog::num::bigint::{BigInt};
use std::collections::HashMap;
use std::rc::Rc;
pub type PredicateKey = (ClauseName, usize); // name, arity, type.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum PredicateKeyType {
BuiltIn,
User
}
pub type OpDirKey = (ClauseName, Fixity);
// name and fixity -> operator type and precedence.
pub type OpDir = HashMap<OpDirKey, (Specifier, usize)>;
pub type CodeDir = HashMap<PredicateKey, (PredicateKeyType, usize)>;
fn get_builtins() -> Code {
vec![internal_call_n!(), // callN/N, 0.
is_atomic!(temp_v!(1)), // atomic/1, 1.
@@ -278,7 +264,7 @@ fn get_builtins() -> Code {
proceed!(),
dynamic_num_test!(cmp_gte!()), // >=/2, 200.
proceed!(),
dynamic_num_test!(cmp_lte!()), // <=/2, 202.
dynamic_num_test!(cmp_lte!()), // =</2, 202.
proceed!(),
dynamic_num_test!(cmp_ne!()), // =\=, 204.
proceed!(),
@@ -582,7 +568,7 @@ fn get_builtins() -> Code {
query![put_value!(perm_v!(4), 1),
put_value!(perm_v!(3), 2),
put_value!(perm_v!(1), 3),
put_value!(perm_v!(2), 4)],
put_value!(perm_v!(2), 4)],
deallocate!(),
goto_execute!(452, 4), // goto end_block/4, 452
default_trust_me!(), // 423
@@ -602,7 +588,7 @@ fn get_builtins() -> Code {
put_value!(perm_v!(1), 3)],
deallocate!(),
goto_execute!(444, 3), // goto handle_ile/3, 442.
try_me_else!(5), // the inner clause.
try_me_else!(5), // the inner clause.
query![put_value!(temp_v!(2), 1)],
get_ball!(),
neck_cut!(),
@@ -638,13 +624,11 @@ fn get_builtins() -> Code {
]
}
pub fn build_code_dir() -> (Code, CodeDir, OpDir)
pub fn build_code_and_op_dirs() -> (CodeDir, OpDir)
{
let mut code_dir = HashMap::new();
let mut op_dir = HashMap::new();
let builtin_code = get_builtins();
op_dir.insert((clause_name!(":-"), Fixity::In), (XFX, 1200));
op_dir.insert((clause_name!(":-"), Fixity::Pre), (FX, 1200));
op_dir.insert((clause_name!("?-"), Fixity::Pre), (FX, 1200));
@@ -693,64 +677,168 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir)
op_dir.insert((clause_name!("=@="), Fixity::In), (XFX, 700));
op_dir.insert((clause_name!("\\=@="), Fixity::In), (XFX, 700));
let builtin = ClauseName::BuiltIn("builtin");
// there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62
// (an extra register is needed for the predicate name)
for arity in 0 .. 63 {
code_dir.insert((clause_name!("call"), arity), (PredicateKeyType::BuiltIn, 0));
code_dir.insert((clause_name!("call"), arity),
(PredicateKeyType::BuiltIn, 0, builtin.clone()));
}
code_dir.insert((clause_name!("atomic"), 1), (PredicateKeyType::BuiltIn, 1));
code_dir.insert((clause_name!("var"), 1), (PredicateKeyType::BuiltIn, 3));
code_dir.insert((clause_name!("false"), 0), (PredicateKeyType::BuiltIn, 61));
code_dir.insert((clause_name!("\\+"), 1), (PredicateKeyType::BuiltIn, 62));
code_dir.insert((clause_name!("duplicate_term"), 2), (PredicateKeyType::BuiltIn, 71));
code_dir.insert((clause_name!("catch"), 3), (PredicateKeyType::BuiltIn, 5));
code_dir.insert((clause_name!("throw"), 1), (PredicateKeyType::BuiltIn, 59));
code_dir.insert((clause_name!("="), 2), (PredicateKeyType::BuiltIn, 73));
code_dir.insert((clause_name!("true"), 0), (PredicateKeyType::BuiltIn, 75));
code_dir.insert((clause_name!("atomic"), 1),
(PredicateKeyType::BuiltIn, 1, builtin.clone()));
code_dir.insert((clause_name!("var"), 1),
(PredicateKeyType::BuiltIn, 3, builtin.clone()));
code_dir.insert((clause_name!("false"), 0),
(PredicateKeyType::BuiltIn, 61, builtin.clone()));
code_dir.insert((clause_name!("\\+"), 1),
(PredicateKeyType::BuiltIn, 62, builtin.clone()));
code_dir.insert((clause_name!("duplicate_term"), 2),
(PredicateKeyType::BuiltIn, 71, builtin.clone()));
code_dir.insert((clause_name!("catch"), 3),
(PredicateKeyType::BuiltIn, 5, builtin.clone()));
code_dir.insert((clause_name!("throw"), 1),
(PredicateKeyType::BuiltIn, 59, builtin.clone()));
code_dir.insert((clause_name!("="), 2),
(PredicateKeyType::BuiltIn, 73, builtin.clone()));
code_dir.insert((clause_name!("true"), 0),
(PredicateKeyType::BuiltIn, 75, builtin.clone()));
code_dir.insert((clause_name!(","), 2), (PredicateKeyType::BuiltIn, 76));
code_dir.insert((clause_name!(";"), 2), (PredicateKeyType::BuiltIn, 120));
code_dir.insert((clause_name!("->"), 2), (PredicateKeyType::BuiltIn, 138));
code_dir.insert((clause_name!(","), 2),
(PredicateKeyType::BuiltIn, 76, builtin.clone()));
code_dir.insert((clause_name!(";"), 2),
(PredicateKeyType::BuiltIn, 120, builtin.clone()));
code_dir.insert((clause_name!("->"), 2),
(PredicateKeyType::BuiltIn, 138, builtin.clone()));
code_dir.insert((clause_name!("functor"), 3), (PredicateKeyType::BuiltIn, 146));
code_dir.insert((clause_name!("arg"), 3), (PredicateKeyType::BuiltIn, 150));
code_dir.insert((clause_name!("integer"), 1), (PredicateKeyType::BuiltIn, 147));
code_dir.insert((clause_name!("display"), 1), (PredicateKeyType::BuiltIn, 192));
code_dir.insert((clause_name!("functor"), 3),
(PredicateKeyType::BuiltIn, 146, builtin.clone()));
code_dir.insert((clause_name!("arg"), 3),
(PredicateKeyType::BuiltIn, 150, builtin.clone()));
code_dir.insert((clause_name!("integer"), 1),
(PredicateKeyType::BuiltIn, 147, builtin.clone()));
code_dir.insert((clause_name!("display"), 1),
(PredicateKeyType::BuiltIn, 192, builtin.clone()));
code_dir.insert((clause_name!("is"), 2), (PredicateKeyType::BuiltIn, 194));
code_dir.insert((clause_name!(">"), 2), (PredicateKeyType::BuiltIn, 196));
code_dir.insert((clause_name!("<"), 2), (PredicateKeyType::BuiltIn, 198));
code_dir.insert((clause_name!(">="), 2), (PredicateKeyType::BuiltIn, 200));
code_dir.insert((clause_name!("<="), 2), (PredicateKeyType::BuiltIn, 202));
code_dir.insert((clause_name!("=\\="), 2), (PredicateKeyType::BuiltIn, 204));
code_dir.insert((clause_name!("=:="), 2), (PredicateKeyType::BuiltIn, 206));
code_dir.insert((clause_name!("=.."), 2), (PredicateKeyType::BuiltIn, 208));
code_dir.insert((clause_name!("is"), 2),
(PredicateKeyType::BuiltIn, 194, builtin.clone()));
code_dir.insert((clause_name!(">"), 2),
(PredicateKeyType::BuiltIn, 196, builtin.clone()));
code_dir.insert((clause_name!("<"), 2),
(PredicateKeyType::BuiltIn, 198, builtin.clone()));
code_dir.insert((clause_name!(">="), 2),
(PredicateKeyType::BuiltIn, 200, builtin.clone()));
code_dir.insert((clause_name!("=<"), 2),
(PredicateKeyType::BuiltIn, 202, builtin.clone()));
code_dir.insert((clause_name!("=\\="), 2),
(PredicateKeyType::BuiltIn, 204, builtin.clone()));
code_dir.insert((clause_name!("=:="), 2),
(PredicateKeyType::BuiltIn, 206, builtin.clone()));
code_dir.insert((clause_name!("=.."), 2),
(PredicateKeyType::BuiltIn, 208, builtin.clone()));
code_dir.insert((clause_name!("length"), 2), (PredicateKeyType::BuiltIn, 261));
code_dir.insert((clause_name!("length"), 2),
(PredicateKeyType::BuiltIn, 261, builtin.clone()));
code_dir.insert((clause_name!("setup_call_cleanup"), 3),
(PredicateKeyType::BuiltIn, 294));
(PredicateKeyType::BuiltIn, 294, builtin.clone()));
code_dir.insert((clause_name!("call_with_inference_limit"), 3),
(PredicateKeyType::BuiltIn, 393));
code_dir.insert((clause_name!("_handle_inference_limit_exceeded"), 2),
(PredicateKeyType::BuiltIn, 421));
(PredicateKeyType::BuiltIn, 393, builtin.clone()));
code_dir.insert((clause_name!("compound"), 1), (PredicateKeyType::BuiltIn, 372));
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!("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!("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 }
}

View File

@@ -8,39 +8,12 @@ use prolog::targets::*;
use std::cell::Cell;
use std::collections::HashMap;
use std::rc::Rc;
use std::vec::Vec;
pub struct CodeGenerator<'a, TermMarker> {
pub struct CodeGenerator<TermMarker> {
marker: TermMarker,
var_count: HashMap<&'a Var, usize>
}
pub enum EvalError {
OpIsInfixAndPostFix,
NamelessEntry,
ParserError(ParserError),
ImpermissibleEntry(String),
QueryFailure,
QueryFailureWithException(String)
}
pub enum EvalSession<'a> {
EntrySuccess,
Error(EvalError),
InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
SubsequentQuerySuccess,
}
impl<'a> From<EvalError> for EvalSession<'a> {
fn from(err: EvalError) -> Self {
EvalSession::Error(err)
}
}
impl<'a> From<ParserError> for EvalSession<'a> {
fn from(err: ParserError) -> Self {
EvalSession::from(EvalError::ParserError(err))
}
var_count: HashMap<Rc<Var>, usize>
}
pub struct ConjunctInfo<'a> {
@@ -69,14 +42,14 @@ impl<'a> ConjunctInfo<'a>
}
}
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker>
{
pub fn new() -> Self {
CodeGenerator { marker: Allocator::new(),
var_count: HashMap::new() }
}
pub fn take_vars(self) -> AllocVarDict<'a> {
pub fn take_vars(self) -> AllocVarDict {
self.marker.take_bindings()
}
@@ -94,11 +67,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
*self.var_count.get(var).unwrap()
}
fn mark_non_callable(&mut self, name: &'a Atom, arity: usize, term_loc: GenContext,
fn mark_non_callable(&mut self, name: Rc<Atom>, arity: usize, term_loc: GenContext,
vr: &'a Cell<VarReg>, code: &mut Code)
-> RegType
{
match self.marker.bindings().get(name) {
match self.marker.bindings().get(&name) {
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
_ => {
@@ -149,7 +122,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
target.push(Target::constant_subterm(constant.clone())),
&Term::Var(ref cell, ref var) =>
if is_exposed || self.get_var_count(var) > 1 {
self.marker.mark_var(var, Level::Deep, cell, term_loc, target);
self.marker.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
} else {
Self::add_or_increment_void_instr(target);
}
@@ -189,8 +162,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
} else {
self.marker.mark_anon_var(lvl, &mut target);
},
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
self.marker.mark_var(var, lvl, cell, term_loc, &mut target),
TermRef::Var(lvl @ Level::Shallow, cell, var) =>
self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target),
_ => {}
};
}
@@ -211,7 +184,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
} else {
GenContext::Last(chunk_num)
}
};
};
self.update_var_count(chunked_term.post_order_iter());
vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc);
@@ -356,7 +329,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(succeed!());
},
&Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name, 1, term_loc, vr, code);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_atomic!(r));
}
},
@@ -366,7 +339,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(succeed!());
},
&Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name, 1, term_loc, vr, code);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_compound!(r));
},
_ => {
@@ -379,7 +352,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(succeed!());
},
&Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name, 1, term_loc, vr, code);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_rational!(r));
},
_ => {
@@ -392,7 +365,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(succeed!());
},
&Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name, 1, term_loc, vr, code);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_float!(r));
},
_ => {
@@ -405,7 +378,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(succeed!());
},
&Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name, 1, term_loc, vr, code);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_string!(r));
},
_ => {
@@ -418,7 +391,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(fail!());
},
&Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name, 1, term_loc, vr, code);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_nonvar!(r));
},
_ => {
@@ -431,7 +404,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(succeed!());
},
&Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name, 1, term_loc, vr, code);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_integer!(r));
},
_ => {
@@ -447,7 +420,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(succeed!());
},
&Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name, 1, term_loc, vr, code);
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(is_var!(r));
}
}
@@ -492,7 +465,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
let mut target = Vec::new();
self.marker.reset_arg(2);
self.marker.mark_var(name, Level::Shallow, vr,
self.marker.mark_var(name.clone(), Level::Shallow, vr,
term_loc, &mut target);
if !target.is_empty() {

View File

@@ -1,28 +1,28 @@
use prolog::allocator::*;
use prolog::ast::*;
use prolog::fixtures::*;
use prolog::targets::*;
use std::cell::Cell;
use std::collections::{BTreeSet, HashMap};
use std::rc::Rc;
pub struct DebrayAllocator<'a> {
bindings: HashMap<&'a Var, VarData>,
pub struct DebrayAllocator {
bindings: HashMap<Rc<Var>, VarData>,
arg_c: usize,
temp_lb: usize,
contents: HashMap<usize, &'a Var>,
contents: HashMap<usize, Rc<Var>>,
in_use: BTreeSet<usize>,
}
impl<'a> DebrayAllocator<'a> {
fn is_curr_arg_distinct_from(&self, var: &'a Var) -> bool {
impl DebrayAllocator {
fn is_curr_arg_distinct_from(&self, var: &Var) -> bool {
match self.contents.get(&self.arg_c) {
Some(t_var) if **t_var != *var => true,
_ => false
}
}
fn occurs_shallowly_in_head(&self, var: &'a Var, r: usize) -> bool
fn occurs_shallowly_in_head(&self, var: &Var, r: usize) -> bool
{
match self.bindings.get(var).unwrap() {
&VarData::Temp(_, _, ref tvd) =>
@@ -31,7 +31,7 @@ impl<'a> DebrayAllocator<'a> {
}
}
fn alloc_with_cr(&self, var: &'a Var) -> usize
fn alloc_with_cr(&self, var: &Var) -> usize
{
match self.bindings.get(var) {
Some(&VarData::Temp(_, _, ref tvd)) => {
@@ -58,7 +58,7 @@ impl<'a> DebrayAllocator<'a> {
}
}
fn alloc_with_ca(&self, var: &'a Var) -> usize
fn alloc_with_ca(&self, var: &Var) -> usize
{
match self.bindings.get(var) {
Some(&VarData::Temp(_, _, ref tvd)) => {
@@ -87,7 +87,7 @@ impl<'a> DebrayAllocator<'a> {
}
}
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(&'a Var, usize)>
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc<Var>, usize)>
{
// we want to allocate a register to the k^{th} parameter, par_k.
// par_k may not be a temporary variable.
@@ -103,7 +103,7 @@ impl<'a> DebrayAllocator<'a> {
let tvd = self.bindings.get(t_var).unwrap();
if let &VarData::Temp(_, _, ref tvd) = tvd {
if !tvd.use_set.contains(&(GenContext::Last(chunk_num), k)) {
return Some((t_var, self.alloc_with_ca(t_var)));
return Some((t_var.clone(), self.alloc_with_ca(t_var)));
}
}
@@ -113,7 +113,7 @@ impl<'a> DebrayAllocator<'a> {
}
}
fn evacuate_arg<Target>(&mut self, chunk_num: usize, target: &mut Vec<Target>)
fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec<Target>)
where Target: CompilationTarget<'a>
{
match self.alloc_in_last_goal_hint(chunk_num) {
@@ -127,7 +127,7 @@ impl<'a> DebrayAllocator<'a> {
target.push(Target::move_to_register(r, k));
self.contents.remove(&k);
self.contents.insert(r.reg_num(), var);
self.contents.insert(r.reg_num(), var.clone());
self.record_register(var, r);
self.in_use.insert(r.reg_num());
@@ -138,8 +138,8 @@ impl<'a> DebrayAllocator<'a> {
};
}
fn alloc_reg_to_var<Target>(&mut self, var: &'a Var, lvl: Level, term_loc: GenContext,
target: &mut Vec<Target>)
fn alloc_reg_to_var<'a, Target>(&mut self, var: &Var, lvl: Level, term_loc: GenContext,
target: &mut Vec<Target>)
-> usize
where Target: CompilationTarget<'a>
{
@@ -179,7 +179,7 @@ impl<'a> DebrayAllocator<'a> {
final_index
}
fn in_place(&self, var: &'a Var, term_loc: GenContext, r: RegType, k: usize) -> bool
fn in_place(&self, var: &Var, term_loc: GenContext, r: RegType, k: usize) -> bool
{
match term_loc {
GenContext::Head if !r.is_perm() => r.reg_num() == k,
@@ -191,9 +191,9 @@ impl<'a> DebrayAllocator<'a> {
}
}
impl<'a> Allocator<'a> for DebrayAllocator<'a>
impl<'a> Allocator<'a> for DebrayAllocator
{
fn new() -> DebrayAllocator<'a> {
fn new() -> DebrayAllocator {
DebrayAllocator {
arg_c: 1,
temp_lb: 1,
@@ -244,14 +244,14 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
}
}
fn mark_var<Target>(&mut self, var: &'a Var, lvl: Level, cell: &'a Cell<VarReg>,
fn mark_var<Target>(&mut self, var: Rc<Var>, lvl: Level, cell: &Cell<VarReg>,
term_loc: GenContext, target: &mut Vec<Target>)
where Target: CompilationTarget<'a>
{
let (r, is_new_var) = match self.get(var) {
let (r, is_new_var) = match self.get(var.clone()) {
RegType::Temp(0) => {
// here, r is temporary *and* unassigned.
let o = self.alloc_reg_to_var(var, lvl, term_loc, target);
let o = self.alloc_reg_to_var(&var, lvl, term_loc, target);
cell.set(VarReg::Norm(RegType::Temp(o)));
@@ -259,7 +259,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
},
RegType::Perm(0) => {
let pr = cell.get().norm();
self.record_register(var, pr);
self.record_register(var.clone(), pr);
(pr, true)
},
@@ -270,7 +270,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
Level::Root | Level::Shallow => {
let k = self.arg_c;
if self.is_curr_arg_distinct_from(var) {
if self.is_curr_arg_distinct_from(&var) {
self.evacuate_arg(term_loc.chunk_num(), target);
}
@@ -278,7 +278,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
cell.set(VarReg::ArgAndNorm(r, k));
if !self.in_place(var, term_loc, r, k) {
if !self.in_place(&var, term_loc, r, k) {
if is_new_var {
target.push(Target::argument_to_variable(r, k));
} else {
@@ -288,7 +288,7 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
},
Level::Deep if is_new_var =>
if let GenContext::Head = term_loc {
if self.occurs_shallowly_in_head(var, r.reg_num()) {
if self.occurs_shallowly_in_head(&var, r.reg_num()) {
target.push(Target::subterm_to_value(r));
} else {
target.push(Target::subterm_to_variable(r));
@@ -303,8 +303,8 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
if !r.is_perm() {
let o = r.reg_num();
self.contents.insert(o, var);
self.record_register(var, r);
self.contents.insert(o, var.clone());
self.record_register(var.clone(), r);
self.in_use.insert(o);
}
}
@@ -324,15 +324,15 @@ impl<'a> Allocator<'a> for DebrayAllocator<'a>
self.arg_c += 1;
}
fn bindings(&self) -> &AllocVarDict<'a> {
fn bindings(&self) -> &AllocVarDict {
&self.bindings
}
fn bindings_mut(&mut self) -> &mut AllocVarDict<'a> {
fn bindings_mut(&mut self) -> &mut AllocVarDict {
&mut self.bindings
}
fn take_bindings(self) -> AllocVarDict<'a> {
fn take_bindings(self) -> AllocVarDict {
self.bindings
}

View File

@@ -5,31 +5,9 @@ use std::cell::Cell;
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::collections::btree_map::{IntoIter, IterMut, Values};
use std::mem::swap;
use std::rc::Rc;
use std::vec::Vec;
pub type OccurrenceSet = BTreeSet<(GenContext, usize)>;
pub type HeapVarDict<'a> = HashMap<&'a Var, Addr>;
pub type AllocVarDict<'a> = HashMap<&'a Var, VarData>;
pub struct TempVarData {
last_term_arity: usize,
pub use_set: OccurrenceSet,
pub no_use_set: BTreeSet<usize>,
pub conflict_set: BTreeSet<usize>
}
// labeled with chunk numbers.
pub enum VarStatus {
Perm(usize), Temp(usize, TempVarData) // Perm(chunk_num) | Temp(chunk_num, _)
}
// Perm: 0 initially, a stack register once processed.
// Temp: labeled with chunk_num and temp offset (unassigned if 0).
pub enum VarData {
Perm(usize), Temp(usize, usize, TempVarData)
}
impl VarData {
pub fn as_reg_type(&self) -> RegType {
match self {
@@ -73,8 +51,8 @@ impl TempVarData {
}
}
type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
pub struct VariableFixtures<'a>(BTreeMap<&'a Var, VariableFixture<'a>>);
type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
pub struct VariableFixtures<'a>(BTreeMap<Rc<Var>, VariableFixture<'a>>);
impl<'a> VariableFixtures<'a>
{
@@ -82,7 +60,7 @@ impl<'a> VariableFixtures<'a>
VariableFixtures(BTreeMap::new())
}
pub fn insert(&mut self, var: &'a Var, vs: VariableFixture<'a>) {
pub fn insert(&mut self, var: Rc<Var>, vs: VariableFixture<'a>) {
self.0.insert(var, vs);
}
@@ -98,14 +76,14 @@ impl<'a> VariableFixtures<'a>
// Compute the conflict set of u.
// 1.
let mut use_sets : HashMap<&'a Var, OccurrenceSet> = HashMap::new();
let mut use_sets: HashMap<Rc<Var>, OccurrenceSet> = HashMap::new();
for (ref var, &mut (ref mut var_status, _)) in self.iter_mut() {
for (var, &mut (ref mut var_status, _)) in self.iter_mut() {
if let &mut VarStatus::Temp(_, ref mut var_data) = var_status {
let mut use_set = OccurrenceSet::new();
swap(&mut var_data.use_set, &mut use_set);
use_sets.insert(var, use_set);
use_sets.insert((*var).clone(), use_set);
}
}
@@ -136,11 +114,11 @@ impl<'a> VariableFixtures<'a>
}
}
fn get_mut(&mut self, u: &'a Var) -> Option<&mut VariableFixture<'a>> {
self.0.get_mut(u)
fn get_mut(&mut self, u: Rc<Var>) -> Option<&mut VariableFixture<'a>> {
self.0.get_mut(&u)
}
fn iter_mut(&mut self) -> IterMut<&'a Var, VariableFixture<'a>> {
fn iter_mut(&mut self) -> IterMut<Rc<Var>, VariableFixture<'a>> {
self.0.iter_mut()
}
@@ -179,7 +157,7 @@ impl<'a> VariableFixtures<'a>
let mut arg_c = 1;
for term_ref in iter {
if let TermRef::Var(lvl, cell, var) = term_ref {
if let &TermRef::Var(lvl, cell, ref var) = &term_ref {
let mut status = self.0.remove(var)
.unwrap_or((VarStatus::Temp(chunk_num, TempVarData::new(lt_arity)), Vec::new()));
@@ -194,7 +172,7 @@ impl<'a> VariableFixtures<'a>
_ => status.0 = VarStatus::Perm(chunk_num)
};
self.0.insert(var, status);
self.0.insert(var.clone(), status);
}
if let Level::Shallow = term_ref.level() {
@@ -203,11 +181,11 @@ impl<'a> VariableFixtures<'a>
}
}
pub fn into_iter(self) -> IntoIter<&'a Var, VariableFixture<'a>> {
pub fn into_iter(self) -> IntoIter<Rc<Var>, VariableFixture<'a>> {
self.0.into_iter()
}
fn values(&self) -> Values<&'a Var, VariableFixture<'a>> {
fn values(&self) -> Values<Rc<Var>, VariableFixture<'a>> {
self.0.values()
}

View File

@@ -1,7 +1,7 @@
use prolog::ast::*;
use prolog::builtins::*;
use prolog::codegen::*;
use prolog::debray_allocator::*;
use prolog::fixtures::*;
use prolog::heap_print::*;
use prolog::machine::*;
use prolog::parser::toplevel::*;
@@ -306,9 +306,11 @@ impl fmt::Display for IndexingInstruction {
impl fmt::Display for EvalError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&EvalError::ModuleNotFound => write!(f, "module not found."),
&EvalError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."),
&EvalError::QueryFailure => write!(f, "false."),
&EvalError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)),
&EvalError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite builtin {}", msg),
&EvalError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite builtin {}.", msg),
&EvalError::OpIsInfixAndPostFix =>
write!(f, "cannot define an op to be both postfix and infix."),
&EvalError::NamelessEntry => write!(f, "the predicate head is not an atom or clause."),
@@ -438,16 +440,10 @@ pub fn print_code(code: &Code) {
}
}
pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
pub fn parse_code(wam: &Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
{
let mut worker = TopLevelWorker::new(wam.atom_tbl(), wam.op_dir());
worker.parse_code(buffer)
}
pub fn parse_batch(wam: &mut Machine, buffer: &str) -> Result<Vec<TopLevelPacket>, ParserError>
{
let mut worker = TopLevelWorker::new(wam.atom_tbl(), wam.op_dir());
worker.parse_batch(buffer)
let mut worker = TopLevelWorker::new(buffer.as_bytes(), wam.atom_tbl());
worker.parse_code(&wam.op_dir)
}
pub fn read() -> String {
@@ -512,7 +508,7 @@ fn set_first_index(code: &mut Code)
}
}
fn compile_appendix(code: &mut Code, queue: &Vec<TopLevel>) -> Result<(), ParserError>
fn compile_appendix(code: &mut Code, queue: Vec<TopLevel>) -> Result<(), ParserError>
{
for tl in queue.iter() {
set_first_index(code);
@@ -522,31 +518,31 @@ fn compile_appendix(code: &mut Code, queue: &Vec<TopLevel>) -> Result<(), Parser
Ok(())
}
fn compile_query<'a>(terms: &'a Vec<QueryTerm>, queue: &'a Vec<TopLevel>)
-> Result<(Code, AllocVarDict<'a>), ParserError>
fn compile_query(terms: Vec<QueryTerm>, queue: Vec<TopLevel>)
-> Result<(Code, AllocVarDict), ParserError>
{
let mut cg = CodeGenerator::<DebrayAllocator>::new();
let mut code = try!(cg.compile_query(terms));
let mut code = try!(cg.compile_query(&terms));
compile_appendix(&mut code, queue)?;
Ok((code, cg.take_vars()))
}
fn compile_decl<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel, queue: &'b Vec<TopLevel>)
-> EvalSession<'b>
fn compile_decl(wam: &mut Machine, tl: TopLevel, queue: Vec<TopLevel>) -> EvalSession
{
match tl {
&TopLevel::Declaration(ref decl) => wam.submit_decl(decl),
TopLevel::Declaration(Declaration::Op(op_decl)) => {
try_eval_session!(op_decl.submit(&mut wam.op_dir));
EvalSession::EntrySuccess
},
TopLevel::Declaration(Declaration::UseModule(name)) =>
wam.use_module_in_toplevel(name),
TopLevel::Declaration(_) =>
EvalSession::from(ParserError::InvalidModuleDecl),
_ => {
let mut code = match compile_relation(tl) {
Ok(code) => code,
Err(e) => return EvalSession::from(EvalError::ParserError(e))
};
if let Err(e) = compile_appendix(&mut code, queue) {
return EvalSession::from(e);
};
let mut code = try_eval_session!(compile_relation(&tl));
try_eval_session!(compile_appendix(&mut code, queue));
if !code.is_empty() {
if let Some(name) = tl.name() {
@@ -561,36 +557,87 @@ fn compile_decl<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel, queue: &'b V
}
}
pub fn compile<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevelPacket) -> EvalSession<'b>
pub fn compile_packet(wam: &mut Machine, tl: TopLevelPacket) -> EvalSession
{
match tl {
&TopLevelPacket::Query(ref terms, ref queue) =>
TopLevelPacket::Query(terms, queue) =>
match compile_query(terms, queue) {
Ok((code, vars)) => wam.submit_query(code, vars),
Ok((mut code, vars)) => wam.submit_query(code, vars),
Err(e) => EvalSession::from(e)
},
&TopLevelPacket::Decl(ref tl, ref queue) =>
TopLevelPacket::Decl(tl, queue) =>
compile_decl(wam, tl, queue)
}
}
pub fn compile_batch<'a, 'b: 'a>(wam: &'a mut Machine, tls: &'b Vec<TopLevelPacket>)
-> EvalSession<'b>
pub fn compile_listing(wam: &mut Machine, src_str: &str) -> EvalSession
{
fn get_module_name(module: &Option<Module>) -> ClauseName {
match module {
&Some(ref module) => module.module_decl.name.clone(),
_ => ClauseName::BuiltIn("builtin")
}
}
let mut module: Option<Module> = None;
let (mut code_dir, mut op_dir) = build_code_and_op_dirs();
let mut code = Vec::new();
let mut worker = TopLevelWorker::new(src_str.as_bytes(), wam.atom_tbl());
let tls = try_eval_session!(worker.parse_batch(&mut op_dir));
for tl in tls {
match tl {
&TopLevelPacket::Query(..) =>
TopLevelPacket::Query(..) =>
return EvalSession::from(ParserError::ExpectedRel),
&TopLevelPacket::Decl(ref tl, ref queue) => {
let result = compile_decl(wam, tl, queue);
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Module(module_decl)), _) =>
if module.is_none() {
let (builtin_code_dir, builtin_op_dir) = build_code_and_op_dirs();
if let &EvalSession::Error(_) = &result {
return result;
code_dir.extend(builtin_code_dir.into_iter());
op_dir.extend(builtin_op_dir.into_iter());
module = Some(Module::new(module_decl));
} else {
return EvalSession::from(ParserError::InvalidModuleDecl);
},
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::UseModule(name)), _) => {
if let Some(ref submodule) = wam.get_module(name.clone()) {
if let Some(ref mut module) = module {
module.use_module(submodule);
continue;
}
} else {
return EvalSession::from(EvalError::ModuleNotFound);
}
wam.use_module_in_toplevel(name);
},
TopLevelPacket::Decl(TopLevel::Declaration(Declaration::Op(..)), _) => {},
TopLevelPacket::Decl(decl, queue) => {
let p = code.len() + wam.code_size();
let mut decl_code = try_eval_session!(compile_relation(&decl));
try_eval_session!(compile_appendix(&mut decl_code, queue));
code.extend(decl_code.into_iter());
code_dir.insert((decl.name().unwrap(), decl.arity()),
(PredicateKeyType::User, p, get_module_name(&module)));
}
}
}
if let Some(mut module) = module {
module.code_dir = code_dir;
module.op_dir = op_dir;
wam.add_module(module, code);
} else {
wam.add_batched_code(code, code_dir);
wam.add_batched_ops(op_dir);
}
EvalSession::EntrySuccess
}

View File

@@ -34,7 +34,7 @@ impl<'a> QueryIterator<'a> {
&Term::Constant(_, _) =>
return QueryIterator { state_stack: vec![] },
&Term::Var(ref cell, ref var) =>
TermIterState::Var(Level::Root, cell, var)
TermIterState::Var(Level::Root, cell, (*var).clone())
};
QueryIterator { state_stack: vec![state] }
@@ -138,7 +138,7 @@ impl<'a> FactIterator<'a> {
&Term::Constant(ref cell, ref constant) =>
vec![TermIterState::Constant(Level::Root, cell, constant)],
&Term::Var(ref cell, ref var) =>
vec![TermIterState::Var(Level::Root, cell, var)]
vec![TermIterState::Var(Level::Root, cell, var.clone())]
};
FactIterator { state_queue: VecDeque::from(states) }

View File

@@ -1,9 +1,13 @@
:- module(control, [(\=)/2, between/3, call_cleanup/2, once/1]).
:- op(700, xfx, \=).
once(G) :- G, !.
\=(X, X) :- !, false.
\=(_, _).
X \= X :- !, false.
_ \= _.
call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
between(Lower, Upper, Lower) :-
Lower =< Upper.

View File

@@ -1,3 +1,7 @@
:- module(lists, [member/2, select/3, append/3, memberchk/2, reverse/2, maplist/2,
maplist/3, maplist/4, maplist/5, maplist/6, maplist/7, maplist/8,
maplist/9]).
member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).

View File

@@ -1,5 +1,4 @@
use prolog::and_stack::*;
use prolog::builtins::CodeDir;
use prolog::ast::*;
use prolog::copier::*;
use prolog::num::{BigInt, BigUint, Zero, One};
@@ -8,10 +7,40 @@ use prolog::tabled_rc::*;
use downcast::Any;
use std::collections::HashMap;
use std::mem::swap;
use std::ops::{Index, IndexMut};
use std::rc::Rc;
pub(crate) struct CodeDirs<'a> {
code_dir: &'a CodeDir,
modules: &'a HashMap<ClauseName, Module>
}
impl<'a> CodeDirs<'a> {
pub(super) fn new(code_dir: &'a CodeDir, modules: &'a HashMap<ClauseName, Module>) -> Self {
CodeDirs { code_dir, modules }
}
fn get_current_code_dir(&self, p: &CodePtr) -> &CodeDir {
let module_name = p.module_name();
match module_name {
ClauseName::BuiltIn("user") | ClauseName::BuiltIn("builtin") =>
self.code_dir,
_ =>
&self.modules.get(&module_name).unwrap().code_dir
}
}
pub(crate) fn get(&self, name: ClauseName, arity: usize, p: &CodePtr)
-> Option<(usize, ClauseName)>
{
let code_dir = self.get_current_code_dir(p);
code_dir.get(&(name, arity)).map(|idx| (idx.1, idx.2.clone()))
}
}
pub(super) struct DuplicateTerm<'a> {
state: &'a mut MachineState
}
@@ -184,36 +213,40 @@ pub struct MachineState {
pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
pub(crate) trait CallPolicy: Any {
fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
name: ClauseName, arity: usize)
-> CallResult
fn try_call<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
name: ClauseName, arity: usize)
-> CallResult
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
let compiled_tl_index = code_dirs.get(name, arity, &machine_st.p);
match compiled_tl_index {
Some(compiled_tl_index) => {
machine_st.cp = machine_st.p + 1;
let module_name = compiled_tl_index.1.clone();
machine_st.cp = machine_st.p.clone() + 1;
machine_st.num_of_args = arity;
machine_st.b0 = machine_st.b;
machine_st.p = CodePtr::DirEntry(compiled_tl_index);
machine_st.p = CodePtr::DirEntry(compiled_tl_index.0, module_name);
},
None => machine_st.fail = true
};
Ok(())
}
fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
name: ClauseName, arity: usize)
-> CallResult
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
name: ClauseName, arity: usize)
-> CallResult
{
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
let compiled_tl_index = code_dirs.get(name, arity, &machine_st.p);
match compiled_tl_index {
Some(compiled_tl_index) => {
let module_name = compiled_tl_index.1.clone();
machine_st.num_of_args = arity;
machine_st.b0 = machine_st.b;
machine_st.p = CodePtr::DirEntry(compiled_tl_index);
machine_st.p = CodePtr::DirEntry(compiled_tl_index.0, module_name);
},
None => machine_st.fail = true
};
@@ -231,9 +264,9 @@ pub(crate) trait CallPolicy: Any {
}
machine_st.e = machine_st.or_stack[b].e;
machine_st.cp = machine_st.or_stack[b].cp;
machine_st.cp = machine_st.or_stack[b].cp.clone();
machine_st.or_stack[b].bp = machine_st.p + offset;
machine_st.or_stack[b].bp = machine_st.p.clone() + offset;
let old_tr = machine_st.or_stack[b].tr;
let curr_tr = machine_st.tr;
@@ -261,9 +294,9 @@ pub(crate) trait CallPolicy: Any {
}
machine_st.e = machine_st.or_stack[b].e;
machine_st.cp = machine_st.or_stack[b].cp;
machine_st.cp = machine_st.or_stack[b].cp.clone();
machine_st.or_stack[b].bp = machine_st.p + 1;
machine_st.or_stack[b].bp = machine_st.p.clone() + 1;
let old_tr = machine_st.or_stack[b].tr;
let curr_tr = machine_st.tr;
@@ -291,7 +324,7 @@ pub(crate) trait CallPolicy: Any {
}
machine_st.e = machine_st.or_stack[b].e;
machine_st.cp = machine_st.or_stack[b].cp;
machine_st.cp = machine_st.or_stack[b].cp.clone();
let old_tr = machine_st.or_stack[b].tr;
let curr_tr = machine_st.tr;
@@ -322,7 +355,7 @@ pub(crate) trait CallPolicy: Any {
}
machine_st.e = machine_st.or_stack[b].e;
machine_st.cp = machine_st.or_stack[b].cp;
machine_st.cp = machine_st.or_stack[b].cp.clone();
let old_tr = machine_st.or_stack[b].tr;
let curr_tr = machine_st.tr;
@@ -351,7 +384,7 @@ pub(crate) struct DefaultCallPolicy {}
impl CallPolicy for DefaultCallPolicy {}
pub(crate) struct CallWithInferenceLimitCallPolicy {
pub(crate) struct CallWithInferenceLimitCallPolicy {
pub(crate) prev_policy: Box<CallPolicy>,
count: BigUint,
limits: Vec<(BigUint, usize)>
@@ -378,7 +411,7 @@ impl CallWithInferenceLimitCallPolicy {
self.count += BigUint::one();
}
}
Ok(())
}
@@ -418,19 +451,19 @@ impl CallWithInferenceLimitCallPolicy {
}
impl CallPolicy for CallWithInferenceLimitCallPolicy {
fn try_call(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
name: ClauseName, arity: usize)
fn try_call<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
name: ClauseName, arity: usize)
-> CallResult
{
self.prev_policy.try_call(machine_st, code_dir, name, arity)?;
self.prev_policy.try_call(machine_st, code_dirs, name, arity)?;
self.increment()
}
fn try_execute(&mut self, machine_st: &mut MachineState, code_dir: &CodeDir,
name: ClauseName, arity: usize)
-> CallResult
fn try_execute<'a>(&mut self, machine_st: &mut MachineState, code_dirs: CodeDirs<'a>,
name: ClauseName, arity: usize)
-> CallResult
{
self.prev_policy.try_execute(machine_st, code_dir, name, arity)?;
self.prev_policy.try_execute(machine_st, code_dirs, name, arity)?;
self.increment()
}
@@ -527,10 +560,11 @@ impl CutPolicy for SetupCallCleanupCutPolicy {
machine_st.p += 1;
if !self.out_of_cont_pts() {
machine_st.cp = machine_st.p;
machine_st.cp = machine_st.p.clone();
machine_st.num_of_args = 0;
machine_st.b0 = machine_st.b;
machine_st.p = CodePtr::DirEntry(354); // goto_call run_cleaners_without_handling/0, 354.
// goto_call run_cleaners_without_handling/0, 354.
machine_st.p = CodePtr::DirEntry(354, clause_name!("builtin"));
}
}
}

View File

@@ -1,6 +1,5 @@
use prolog::and_stack::*;
use prolog::ast::*;
use prolog::builtins::*;
use prolog::copier::*;
use prolog::heap_iter::*;
use prolog::heap_print::*;
@@ -908,7 +907,8 @@ impl MachineState {
}
}
fn handle_internal_call_n(&mut self, call_policy: &mut Box<CallPolicy>, code_dir: &CodeDir)
fn handle_internal_call_n<'a>(&mut self, call_policy: &mut Box<CallPolicy>,
code_dirs: CodeDirs<'a>)
{
let arity = self.num_of_args + 1;
let pred = self.registers[1].clone();
@@ -921,7 +921,7 @@ impl MachineState {
self.registers[arity - 1] = pred;
if let Some((name, arity)) = self.setup_call_n(arity - 1) {
try_or_fail!(self, call_policy.try_execute(self, code_dir, name, arity));
try_or_fail!(self, call_policy.try_execute(self, code_dirs, name, arity));
}
} else {
self.fail = true;
@@ -931,7 +931,7 @@ impl MachineState {
fn goto_throw(&mut self) {
self.num_of_args = 1;
self.b0 = self.b;
self.p = CodePtr::DirEntry(59);
self.p = CodePtr::DirEntry(59, clause_name!("builtin"));
}
fn throw_exception(&mut self, hcv: Vec<HeapCellValue>) {
@@ -1209,10 +1209,10 @@ impl MachineState {
};
}
pub(super) fn execute_built_in_instr(&mut self, code_dir: &CodeDir,
call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,
instr: &BuiltInInstruction)
pub(super) fn execute_built_in_instr<'a>(&mut self, code_dirs: CodeDirs<'a>,
call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,
instr: &BuiltInInstruction)
{
match instr {
&BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) => {
@@ -1253,7 +1253,7 @@ impl MachineState {
&BuiltInInstruction::GetArgExecute =>
try_or_fail!(self, {
let val = self.try_get_arg();
self.p = self.cp;
self.p = self.cp.clone();
val
}),
&BuiltInInstruction::GetCurrentBlock => {
@@ -1537,7 +1537,7 @@ impl MachineState {
self.fail = true;
},
&BuiltInInstruction::InternalCallN =>
self.handle_internal_call_n(call_policy, code_dir),
self.handle_internal_call_n(call_policy, code_dirs),
&BuiltInInstruction::Fail => {
self.fail = true;
self.p += 1;
@@ -1728,10 +1728,10 @@ impl MachineState {
false
}
pub(super) fn execute_ctrl_instr(&mut self, code_dir: &CodeDir,
call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,
instr: &ControlInstruction)
pub(super) fn execute_ctrl_instr<'a>(&mut self, code_dirs: CodeDirs<'a>,
call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>,
instr: &ControlInstruction)
{
match instr {
&ControlInstruction::Allocate(num_cells) => {
@@ -1749,7 +1749,7 @@ impl MachineState {
let index = self.e + 1;
self.and_stack[index].e = self.e;
self.and_stack[index].cp = self.cp;
self.and_stack[index].cp = self.cp.clone();
self.and_stack[index].global_index = gi;
self.and_stack.resize(index, num_cells);
@@ -1760,48 +1760,49 @@ impl MachineState {
}
}
self.and_stack.push(gi, self.e, self.cp, num_cells);
self.and_stack.push(gi, self.e, self.cp.clone(), num_cells);
self.e = self.and_stack.len() - 1;
},
&ControlInstruction::ArgCall => {
self.cp = self.p + 1;
self.cp = self.p.clone() + 1;
self.num_of_args = 3;
self.b0 = self.b;
self.p = CodePtr::DirEntry(150);
self.p = CodePtr::DirEntry(150, clause_name!("builtin"));
},
&ControlInstruction::ArgExecute => {
self.num_of_args = 3;
self.b0 = self.b;
self.p = CodePtr::DirEntry(150);
self.p = CodePtr::DirEntry(150, clause_name!("builtin"));
},
&ControlInstruction::Call(ref name, arity, _) =>
try_or_fail!(self, call_policy.try_call(self, code_dir, name.clone(), arity)),
try_or_fail!(self, call_policy.try_call(self, code_dirs, name.clone(), arity)),
&ControlInstruction::CatchCall => {
self.cp = self.p + 1;
self.cp = self.p.clone() + 1;
self.num_of_args = 3;
self.b0 = self.b;
self.p = CodePtr::DirEntry(5);
self.p = CodePtr::DirEntry(5, clause_name!("builtin"));
},
&ControlInstruction::CatchExecute => {
self.num_of_args = 3;
self.b0 = self.b;
self.p = CodePtr::DirEntry(5);
self.p = CodePtr::DirEntry(5, clause_name!("builtin"));
},
&ControlInstruction::CallN(arity) =>
if let Some((name, arity)) = self.setup_call_n(arity) {
try_or_fail!(self, call_policy.try_call(self, code_dir, name, arity))
try_or_fail!(self, call_policy.try_call(self, code_dirs, name, arity))
},
&ControlInstruction::CheckCpExecute => {
let a = self.store(self.deref(self[temp_v!(2)].clone()));
match a {
Addr::Con(Constant::Usize(old_b)) if self.b > old_b + 1 => {
self.p = self.cp;
self.p = self.cp.clone();
},
_ => {
self.num_of_args = 2;
self.b0 = self.b;
self.p = CodePtr::DirEntry(366); // goto sgc_on_success/2, 366.
// goto sgc_on_success/2, 366.
self.p = CodePtr::DirEntry(366, clause_name!("builtin"));
}
};
},
@@ -1833,7 +1834,7 @@ impl MachineState {
self.unify(a1, c);
self.p = self.cp;
self.p = self.cp.clone();
},
&ControlInstruction::CompareTermCall(qt) => {
match qt {
@@ -1855,12 +1856,12 @@ impl MachineState {
_ => self.compare_term(qt)
};
self.p = self.cp;
self.p = self.cp.clone();
},
&ControlInstruction::Deallocate => {
let e = self.e;
self.cp = self.and_stack[e].cp;
self.cp = self.and_stack[e].cp.clone();
self.e = self.and_stack[e].e;
self.p += 1;
@@ -1881,7 +1882,7 @@ impl MachineState {
println!("{}", output.result());
self.p = self.cp;
self.p = self.cp.clone();
},
&ControlInstruction::DuplicateTermCall => {
self.duplicate_term();
@@ -1889,7 +1890,7 @@ impl MachineState {
},
&ControlInstruction::DuplicateTermExecute => {
self.duplicate_term();
self.p = self.cp;
self.p = self.cp.clone();
},
&ControlInstruction::DynamicIs => {
let a = self[temp_v!(1)].clone();
@@ -1904,7 +1905,7 @@ impl MachineState {
},
&ControlInstruction::EqExecute => {
self.fail = self.eq_test();
self.p = self.cp;
self.p = self.cp.clone();
},
&ControlInstruction::GroundCall => {
self.fail = self.ground_test();
@@ -1912,13 +1913,13 @@ impl MachineState {
},
&ControlInstruction::GroundExecute => {
self.fail = self.ground_test();
self.p = self.cp;
self.p = self.cp.clone();
},
&ControlInstruction::Execute(ref name, arity) =>
try_or_fail!(self, call_policy.try_execute(self, code_dir, name.clone(), arity)),
try_or_fail!(self, call_policy.try_execute(self, code_dirs, name.clone(), arity)),
&ControlInstruction::ExecuteN(arity) =>
if let Some((name, arity)) = self.setup_call_n(arity) {
try_or_fail!(self, call_policy.try_execute(self, code_dir, name, arity))
try_or_fail!(self, call_policy.try_execute(self, code_dirs, name, arity))
},
&ControlInstruction::FunctorCall =>
try_or_fail!(self, {
@@ -1929,7 +1930,7 @@ impl MachineState {
&ControlInstruction::FunctorExecute =>
try_or_fail!(self, {
let val = self.try_functor();
self.p = self.cp;
self.p = self.cp.clone();
val
}),
&ControlInstruction::GetCleanerCall => {
@@ -1958,15 +1959,15 @@ impl MachineState {
self.fail = true;
},
&ControlInstruction::GotoCall(p, arity) => {
self.cp = self.p + 1;
self.cp = self.p.clone() + 1;
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(p);
self.p = CodePtr::DirEntry(p, clause_name!("builtin"));
},
&ControlInstruction::GotoExecute(p, arity) => {
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(p);
self.p = CodePtr::DirEntry(p, clause_name!("builtin"));
},
&ControlInstruction::IsCall(r, ref at) => {
let a1 = self[r].clone();
@@ -1980,10 +1981,10 @@ impl MachineState {
let a2 = try_or_fail!(self, self.get_number(at));
self.unify(a1, Addr::Con(Constant::Number(a2)));
self.p = self.cp;
self.p = self.cp.clone();
},
&ControlInstruction::JmpByCall(arity, offset) => {
self.cp = self.p + 1;
self.cp = self.p.clone() + 1;
self.num_of_args = arity;
self.b0 = self.b;
self.p += offset;
@@ -1999,12 +2000,12 @@ impl MachineState {
},
&ControlInstruction::NotEqExecute => {
self.fail = !self.eq_test();
self.p = self.cp;
self.p = self.cp.clone();
},
&ControlInstruction::Proceed =>
self.p = self.cp,
self.p = self.cp.clone(),
&ControlInstruction::ThrowCall => {
self.cp = self.p + 1;
self.cp = self.p.clone() + 1;
self.goto_throw();
},
&ControlInstruction::ThrowExecute => {
@@ -2023,9 +2024,9 @@ impl MachineState {
self.or_stack.push(gi,
self.e,
self.cp,
self.cp.clone(),
self.b,
self.p + 1,
self.p.clone() + 1,
self.tr,
self.heap.h,
self.b0,
@@ -2058,9 +2059,9 @@ impl MachineState {
self.or_stack.push(gi,
self.e,
self.cp,
self.cp.clone(),
self.b,
self.p + offset,
self.p.clone() + offset,
self.tr,
self.heap.h,
self.b0,

View File

@@ -1,8 +1,6 @@
use prolog::ast::*;
use prolog::builtins::*;
use prolog::codegen::*;
use prolog::heap_print::*;
use prolog::fixtures::*;
use prolog::tabled_rc::*;
pub(crate) mod machine_state;
@@ -17,13 +15,19 @@ use std::mem::swap;
use std::ops::Index;
use std::rc::Rc;
struct MachineCodeIndex<'a> {
code_dir: &'a mut CodeDir,
op_dir: &'a mut OpDir
}
pub struct Machine {
ms: MachineState,
call_policy: Box<CallPolicy>,
cut_policy: Box<CutPolicy>,
code: Code,
code_dir: CodeDir,
op_dir: OpDir,
pub op_dir: OpDir,
modules: HashMap<ClauseName, Module>,
cached_query: Option<Code>
}
@@ -38,16 +42,26 @@ impl Index<CodePtr> for Machine {
&None => panic!("Out-of-bounds top level index.")
}
},
CodePtr::DirEntry(p) => &self.code[p]
CodePtr::DirEntry(p, _) => &self.code[p]
}
}
}
impl<'a> SubModuleUser for MachineCodeIndex<'a> {
fn op_dir(&mut self) -> &mut OpDir {
self.op_dir
}
fn code_dir(&mut self) -> &mut CodeDir {
self.code_dir
}
}
impl Machine {
pub fn new() -> Self {
let atom_tbl = Rc::new(RefCell::new(HashSet::new()));
let (code, code_dir, op_dir) = build_code_dir();
let (code, code_dir, op_dir) = default_build();
Machine {
ms: MachineState::new(atom_tbl),
call_policy: Box::new(DefaultCallPolicy {}),
@@ -55,6 +69,7 @@ impl Machine {
code,
code_dir,
op_dir,
modules: HashMap::new(),
cached_query: None
}
}
@@ -67,30 +82,62 @@ impl Machine {
self.ms.atom_tbl.clone()
}
pub fn add_user_code<'a>(&mut self, name: ClauseName, arity: usize, mut code: Code)
-> EvalSession<'a>
pub fn use_module_in_toplevel(&mut self, name: ClauseName) -> EvalSession {
match self.modules.get(&name) {
Some(ref module) => {
let mut indices = MachineCodeIndex { code_dir: &mut self.code_dir,
op_dir: &mut self.op_dir };
indices.use_module(module)
},
None => EvalSession::from(EvalError::ModuleNotFound)
}
}
pub fn get_module(&self, name: ClauseName) -> Option<&Module> {
self.modules.get(&name)
}
pub fn add_batched_code(&mut self, mut code: Code, code_dir: CodeDir) {
self.code.append(&mut code);
self.code_dir.extend(code_dir.into_iter());
}
pub fn add_batched_ops(&mut self, op_dir: OpDir) {
self.op_dir.extend(op_dir.into_iter());
}
pub fn add_module(&mut self, module: Module, code: Code) {
self.modules.insert(module.module_decl.name.clone(), module);
self.code.extend(code.into_iter());
}
pub fn add_user_code(&mut self, name: ClauseName, arity: usize, code: Code) -> EvalSession
{
match self.code_dir.get(&(name.clone(), arity)) {
Some(&(PredicateKeyType::BuiltIn, _)) =>
Some(&(PredicateKeyType::BuiltIn, _, _)) =>
return EvalSession::from(EvalError::ImpermissibleEntry(format!("{}/{}", name, arity))),
_ => {}
};
let offset = self.code.len();
self.code.append(&mut code);
self.code_dir.insert((name, arity), (PredicateKeyType::User, offset));
self.code.extend(code.into_iter());
self.code_dir.insert((name, arity), (PredicateKeyType::User, offset, clause_name!("user")));
EvalSession::EntrySuccess
}
pub fn code_size(&self) -> usize {
self.code.len()
}
fn cached_query_size(&self) -> usize {
match &self.cached_query {
&Some(ref query) => query.len(),
_ => 0
}
}
fn execute_instr(&mut self)
{
let instr = match self.ms.p {
@@ -100,22 +147,26 @@ impl Machine {
&None => return
}
},
CodePtr::DirEntry(p) => &self.code[p]
CodePtr::DirEntry(p, _) => &self.code[p]
};
match instr {
&Line::Arithmetic(ref arith_instr) =>
self.ms.execute_arith_instr(arith_instr),
&Line::BuiltIn(ref built_in_instr) =>
self.ms.execute_built_in_instr(&self.code_dir, &mut self.call_policy,
&mut self.cut_policy, built_in_instr),
&Line::BuiltIn(ref built_in_instr) => {
let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
self.ms.execute_built_in_instr(code_dirs, &mut self.call_policy,
&mut self.cut_policy, built_in_instr);
},
&Line::Choice(ref choice_instr) =>
self.ms.execute_choice_instr(choice_instr, &mut self.call_policy),
&Line::Cut(ref cut_instr) =>
self.ms.execute_cut_instr(cut_instr, &mut self.cut_policy),
&Line::Control(ref control_instr) =>
self.ms.execute_ctrl_instr(&self.code_dir, &mut self.call_policy,
&mut self.cut_policy, control_instr),
&Line::Control(ref control_instr) => {
let code_dirs = CodeDirs::new(&self.code_dir, &self.modules);
self.ms.execute_ctrl_instr(code_dirs, &mut self.call_policy,
&mut self.cut_policy, control_instr)
},
&Line::Fact(ref fact) => {
for fact_instr in fact {
if self.failed() {
@@ -151,7 +202,7 @@ impl Machine {
let b = self.ms.b - 1;
self.ms.b0 = self.ms.or_stack[b].b0;
self.ms.p = self.ms.or_stack[b].bp;
self.ms.p = self.ms.or_stack[b].bp.clone();
if let CodePtr::TopLevel(_, p) = self.ms.p {
self.ms.fail = p == 0;
@@ -173,14 +224,14 @@ impl Machine {
}
match self.ms.p {
CodePtr::DirEntry(p) if p < self.code.len() => {},
CodePtr::DirEntry(p, _) if p < self.code.len() => {},
_ => break
};
}
}
fn record_var_places<'a>(&self, chunk_num: usize,
alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
fn record_var_places(&self, chunk_num: usize, alloc_locs: &AllocVarDict,
heap_locs: &mut HeapVarDict)
{
for (var, var_data) in alloc_locs {
match var_data {
@@ -190,14 +241,14 @@ impl Machine {
let r = var_data.as_reg_type().reg_num();
let addr = self.ms.and_stack[e][r].clone();
heap_locs.insert(var, addr);
heap_locs.insert(var.clone(), addr);
},
&VarData::Temp(cn, _, _) if cn == chunk_num => {
let r = var_data.as_reg_type();
if r.reg_num() != 0 {
let addr = self.ms[r].clone();
heap_locs.insert(var, addr);
heap_locs.insert(var.clone(), addr);
}
},
_ => {}
@@ -205,7 +256,7 @@ impl Machine {
}
}
fn run_query<'a>(&mut self, alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
fn run_query(&mut self, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict)
{
let end_ptr = CodePtr::TopLevel(0, self.cached_query_size());
@@ -237,7 +288,7 @@ impl Machine {
}
}
fn fail<'a>(&mut self) -> EvalSession<'a>
fn fail(&mut self) -> EvalSession
{
if self.ms.ball.1.len() > 0 {
let h = self.ms.heap.h;
@@ -253,45 +304,8 @@ impl Machine {
EvalSession::from(EvalError::QueryFailure)
}
}
pub fn submit_decl<'a>(&mut self, decl: &Declaration) -> EvalSession<'a>
{
match decl {
&Declaration::Op(prec, spec, ref name) => {
if is_infix!(spec) {
match self.op_dir.get(&(name.clone(), Fixity::Post)) {
Some(_) => return EvalSession::from(EvalError::OpIsInfixAndPostFix),
_ => {}
};
}
if is_postfix!(spec) {
match self.op_dir.get(&(name.clone(), Fixity::In)) {
Some(_) => return EvalSession::from(EvalError::OpIsInfixAndPostFix),
_ => {}
};
}
if prec > 0 {
match spec {
XFY | XFX | YFX => self.op_dir.insert((name.clone(), Fixity::In),
(spec, prec)),
XF | YF => self.op_dir.insert((name.clone(), Fixity::Post), (spec, prec)),
FX | FY => self.op_dir.insert((name.clone(), Fixity::Pre), (spec,prec)),
_ => None
};
} else {
self.op_dir.remove(&(name.clone(), Fixity::Pre));
self.op_dir.remove(&(name.clone(), Fixity::In));
self.op_dir.remove(&(name.clone(), Fixity::Post));
}
EvalSession::EntrySuccess
}
}
}
pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
pub fn submit_query(&mut self, code: Code, alloc_locs: AllocVarDict) -> EvalSession
{
let mut heap_locs = HashMap::new();
@@ -305,12 +319,11 @@ impl Machine {
}
}
pub fn continue_query<'a>(&mut self, alloc_l: &AllocVarDict<'a>, heap_l: &mut HeapVarDict<'a>)
-> EvalSession<'a>
pub fn continue_query(&mut self, alloc_l: &AllocVarDict, heap_l: &mut HeapVarDict) -> EvalSession
{
if !self.or_stack_is_empty() {
let b = self.ms.b - 1;
self.ms.p = self.ms.or_stack[b].bp;
self.ms.p = self.ms.or_stack[b].bp.clone();
if let CodePtr::TopLevel(_, 0) = self.ms.p {
return EvalSession::from(EvalError::QueryFailure);
@@ -356,8 +369,4 @@ impl Machine {
self.cut_policy = Box::new(DefaultCutPolicy {});
self.ms.reset();
}
pub fn op_dir(&self) -> &OpDir {
&self.op_dir
}
}

View File

@@ -686,3 +686,18 @@ macro_rules! compare_execute {
Line::Control(ControlInstruction::CompareExecute)
)
}
macro_rules! module_decl {
($name:expr, $decls:expr) => (
ModuleDecl { name: $name, exports: $decls }
)
}
macro_rules! try_eval_session {
($e:expr) => (
match $e {
Ok(result) => result,
Err(e) => return EvalSession::from(e)
}
)
}

View File

@@ -4,9 +4,10 @@ extern crate ordered_float;
pub mod allocator;
pub mod and_stack;
#[macro_use]
pub mod macros;
#[macro_use]
pub mod ast;
#[macro_use]
pub mod macros;
pub mod arithmetic;
pub mod builtins;
pub mod codegen;
@@ -20,6 +21,7 @@ pub mod io;
pub mod iterators;
pub mod machine;
pub mod or_stack;
#[macro_use]
pub mod parser;
pub mod targets;
pub mod tabled_rc;

View File

@@ -54,6 +54,10 @@ impl<T: Hash + Eq> TabledRc<T> {
TabledRc { atom, table }
}
pub fn atom_tbl(&self) -> TabledData<T> {
self.table.clone()
}
}
impl<T: Hash + Eq> Drop for TabledRc<T> {

View File

@@ -1,5 +1,4 @@
use prolog::codegen::*;
use prolog::fixtures::*;
use prolog::ast::*;
use prolog::heap_print::*;
use prolog::io::*;
use prolog::machine::*;
@@ -63,9 +62,8 @@ impl HeapCellValueOutputter for TestOutputter {
}
}
pub fn collect_test_output<'a>(wam: &mut Machine, alloc_locs: AllocVarDict<'a>,
mut heap_locs: HeapVarDict<'a>)
-> Vec<HashSet<String>>
pub fn collect_test_output(wam: &mut Machine, alloc_locs: AllocVarDict, mut heap_locs: HeapVarDict)
-> Vec<HashSet<String>>
{
let mut output = TestOutputter::new();
@@ -81,9 +79,9 @@ pub fn collect_test_output<'a>(wam: &mut Machine, alloc_locs: AllocVarDict<'a>,
output.result()
}
pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVarDict<'a>,
mut heap_locs: HeapVarDict<'a>, limit: usize)
-> Vec<HashSet<String>>
pub fn collect_test_output_with_limit(wam: &mut Machine, alloc_locs: AllocVarDict,
mut heap_locs: HeapVarDict, limit: usize)
-> Vec<HashSet<String>>
{
let mut output = TestOutputter::new();
@@ -118,7 +116,7 @@ pub fn submit(wam: &mut Machine, buffer: &str) -> bool
match parse_code(wam, buffer) {
Ok(tl) =>
match compile(wam, &tl) {
match compile_packet(wam, tl) {
EvalSession::InitialQuerySuccess(_, _) |
EvalSession::EntrySuccess |
EvalSession::SubsequentQuerySuccess =>
@@ -136,7 +134,7 @@ pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>
match parse_code(wam, buffer) {
Ok(tl) =>
match compile(wam, &tl) {
match compile_packet(wam, tl) {
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
result == collect_test_output(wam, alloc_locs, heap_locs),
EvalSession::EntrySuccess => true,
@@ -155,7 +153,7 @@ pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
match parse_code(wam, buffer) {
Ok(tl) =>
match compile(wam, &tl) {
match compile_packet(wam, tl) {
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
result == collect_test_output_with_limit(wam, alloc_locs,
heap_locs, limit),