add provisional module support.
This commit is contained in:
25
README.md
25
README.md
@@ -29,7 +29,7 @@ Extend rusty-wam to include the following, among other features:
|
||||
* Built-in predicates for list processing and top-level declarative
|
||||
control (`setup_call_control/3`, `call_with_inference_limit/3`,
|
||||
etc.) (_done_).
|
||||
* A rudimentary module system.
|
||||
* A rudimentary module system (_in progress_).
|
||||
* Attributed variables using the SICStus Prolog interface and
|
||||
semantics. Adding coroutines like `dif/2`, `freeze/2`, etc.
|
||||
is straightforward with attributed variables.
|
||||
@@ -102,6 +102,7 @@ The following predicates are built-in to rusty-wam.
|
||||
* `atomic/1`
|
||||
* `between/3`
|
||||
* `call/1..63`
|
||||
* `call_cleanup/2`
|
||||
* `call_with_inference_limit/3`
|
||||
* `catch/3`
|
||||
* `compare/3`
|
||||
@@ -199,11 +200,31 @@ Note that the values of variables belonging to successful queries are
|
||||
printed out, on one line each. Uninstantiated variables are denoted by
|
||||
a number preceded by an underscore (`X = _0` in an example above).
|
||||
|
||||
Lastly, rusty-wam supports dynamic operators. Using the built-in
|
||||
### Dynamic operators
|
||||
|
||||
rusty-wam supports dynamic operators. Using the built-in
|
||||
arithmetic operators with the usual precedences,
|
||||
|
||||
```
|
||||
prolog> ?- display(-5 + 3 - (2 * 4) // 8).
|
||||
'-'('+'('-'(5), 3), '//'('*'(2, 4), 8))
|
||||
true.
|
||||
```
|
||||
|
||||
New operators can be defined using the `op` declaration.
|
||||
|
||||
### Modules
|
||||
|
||||
rusty-wam has seemingly correct but presently untested support for a
|
||||
basic predicate-based module system. It provides a way to separate
|
||||
units of code into distinct namespaces, for both predicates and
|
||||
operators. See the files `src/prolog/lib/*.pl` for examples.
|
||||
|
||||
At the time of this writing, several control and list processing
|
||||
operators are hidden within their own modules that have not
|
||||
been exported to the toplevel. To export them, write
|
||||
|
||||
```
|
||||
prolog> :- use_module(library(lists)).
|
||||
prolog> :- use_module(library(control)).
|
||||
```
|
||||
15
src/main.rs
15
src/main.rs
@@ -5,6 +5,7 @@ extern crate termion;
|
||||
mod prolog;
|
||||
#[macro_use] mod test_utils;
|
||||
|
||||
use prolog::ast::*;
|
||||
use prolog::io::*;
|
||||
use prolog::machine::*;
|
||||
|
||||
@@ -17,20 +18,20 @@ pub static CONTROL: &str = include_str!("./prolog/lib/control.pl");
|
||||
fn process_buffer(wam: &mut Machine, buffer: &str)
|
||||
{
|
||||
match parse_code(wam, buffer) {
|
||||
Ok(tl) => {
|
||||
let result = compile(wam, &tl);
|
||||
Ok(packet) => {
|
||||
let result = compile_packet(wam, packet);
|
||||
print(wam, result);
|
||||
},
|
||||
Err(s) => println!("{:?}", s)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn load_init_str(wam: &mut Machine, src_str: &str)
|
||||
{
|
||||
match parse_batch(wam, src_str) {
|
||||
Ok(tls) => compile_batch(wam, &tls),
|
||||
Err(_) => panic!("failed to parse batch from string.")
|
||||
};
|
||||
match compile_listing(wam, src_str) {
|
||||
EvalSession::Error(_) => panic!("failed to parse batch from string."),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn prolog_repl() {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
123
src/prolog/io.rs
123
src/prolog/io.rs
@@ -1,7 +1,7 @@
|
||||
use prolog::ast::*;
|
||||
use prolog::builtins::*;
|
||||
use prolog::codegen::*;
|
||||
use prolog::debray_allocator::*;
|
||||
use prolog::fixtures::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::machine::*;
|
||||
use prolog::parser::toplevel::*;
|
||||
@@ -306,9 +306,11 @@ impl fmt::Display for IndexingInstruction {
|
||||
impl fmt::Display for EvalError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&EvalError::ModuleNotFound => write!(f, "module not found."),
|
||||
&EvalError::ModuleDoesNotContainExport => write!(f, "module does not contain claimed export."),
|
||||
&EvalError::QueryFailure => write!(f, "false."),
|
||||
&EvalError::QueryFailureWithException(ref e) => write!(f, "{}", error_string(e)),
|
||||
&EvalError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite builtin {}", msg),
|
||||
&EvalError::ImpermissibleEntry(ref msg) => write!(f, "cannot overwrite builtin {}.", msg),
|
||||
&EvalError::OpIsInfixAndPostFix =>
|
||||
write!(f, "cannot define an op to be both postfix and infix."),
|
||||
&EvalError::NamelessEntry => write!(f, "the predicate head is not an atom or clause."),
|
||||
@@ -438,16 +440,10 @@ pub fn print_code(code: &Code) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result<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
|
||||
}
|
||||
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Submodule src/prolog/parser updated: 5b74536d6e...efb52afa2c
@@ -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> {
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user