add provisions for arithmetic support.
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
|||||||
[root]
|
[root]
|
||||||
name = "rusty-wam"
|
name = "rusty-wam"
|
||||||
version = "0.7.1"
|
version = "0.7.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rusty-wam"
|
name = "rusty-wam"
|
||||||
version = "0.7.1"
|
version = "0.7.2"
|
||||||
authors = ["Mark Thom"]
|
authors = ["Mark Thom"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -19,15 +19,15 @@ Extend rusty-wam to include the following, among other features:
|
|||||||
* ISO Prolog compliant throw/catch (_done_).
|
* ISO Prolog compliant throw/catch (_done_).
|
||||||
* Built-in and user-defined operators of all fixities, with custom
|
* Built-in and user-defined operators of all fixities, with custom
|
||||||
associativity and precedence (_done_).
|
associativity and precedence (_done_).
|
||||||
* Bignum and floating point arithmetic.
|
* Bignum and floating point arithmetic (_in progress_).
|
||||||
* Built-in control operators (`,`, `;`, `->`, etc.).
|
* Built-in control operators (`,`, `;`, `->`, etc.).
|
||||||
|
* Built-in predicates for list processing and top-level declarative
|
||||||
|
control (`setup_call_control/3`, `call_with_inference_limit/3`,
|
||||||
|
etc.)
|
||||||
* Attributed variables using the SICStus Prolog interface and
|
* Attributed variables using the SICStus Prolog interface and
|
||||||
semantics. Adding coroutines like `dif/2`, `freeze/2`, etc.
|
semantics. Adding coroutines like `dif/2`, `freeze/2`, etc.
|
||||||
is straightforward with attributed variables.
|
is straightforward with attributed variables.
|
||||||
* An occurs check.
|
* An occurs check.
|
||||||
* Built-in predicates for list processing and top-level declarative
|
|
||||||
control (`setup_call_control/3`, `call_with_inference_limit/3`,
|
|
||||||
etc.)
|
|
||||||
* Mode declarations.
|
* Mode declarations.
|
||||||
* Extensions for clp(FD).
|
* Extensions for clp(FD).
|
||||||
* `if_` and related predicates, following the developments of the
|
* `if_` and related predicates, following the developments of the
|
||||||
@@ -46,6 +46,8 @@ ideally, very fast) [Shen](http://shenlanguage.org) implementation.
|
|||||||
|
|
||||||
The following predicates are built-in to rusty-wam.
|
The following predicates are built-in to rusty-wam.
|
||||||
|
|
||||||
|
* Arithmetic support:
|
||||||
|
** is/2 works for (+)/2, (-)/{1,2}, (*)/2, (//)/2, (div)/2.
|
||||||
* atomic/1
|
* atomic/1
|
||||||
* call/N (1 <= N <= 63)
|
* call/N (1 <= N <= 63)
|
||||||
* catch/3
|
* catch/3
|
||||||
@@ -128,14 +130,11 @@ Note that the values of variables belonging to successful queries are
|
|||||||
printed out, on one line each. Uninstantiated variables are denoted by
|
printed out, on one line each. Uninstantiated variables are denoted by
|
||||||
a number preceded by an underscore (`X = _0` in an example above).
|
a number preceded by an underscore (`X = _0` in an example above).
|
||||||
|
|
||||||
Lastly, rusty-wam supports dynamic operators:
|
Lastly, rusty-wam supports dynamic operators. Using the built-in
|
||||||
|
arithmetic operators with the usual precedences,
|
||||||
|
|
||||||
```
|
```
|
||||||
prolog> :- op(500, yfx, +).
|
prolog> ?- X = -5 + 3 - (2 * 4) // 8.
|
||||||
prolog> :- op(500, yfx, -).
|
|
||||||
prolog> :- op(200, fy, -).
|
|
||||||
prolog> :- op(400, yfx, *).
|
|
||||||
prolog> :- op(400, yfx, /).
|
|
||||||
prolog> ?- X = -5 + 3 - (2 * 4) / 8.
|
|
||||||
true.
|
true.
|
||||||
X = -(+(-(5), 3), /(*(2, 4), 8)).
|
X = -(+(-(5), 3), /(*(2, 4), 8)).
|
||||||
```
|
```
|
||||||
35
src/main.rs
35
src/main.rs
@@ -734,6 +734,41 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(submit(&mut wam, "?- catch(f(X), E, handle_top(E))."), true);
|
assert_eq!(submit(&mut wam, "?- catch(f(X), E, handle_top(E))."), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_queries_on_arithmetic()
|
||||||
|
{
|
||||||
|
let mut wam = Machine::new();
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- X is 1, X is X."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- X is 1, X is X + 1."), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- X is 1, X is X + 0."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- X is 1, X is X * 1."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- X is 1, X is X * 2."), false);
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- X is 1 + a."), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- X is 1 + Y."), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- Y is 2 + 2 - 2, X is 1 + Y, X = 3."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- Y is 2 + 2 - 2, X is 1 + Y, X = 2."), false);
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- 6 is 6."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- 6 is 3 + 3."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- 6 is 3 * 2."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- 7 is 3 * 2."), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- 7 is 3.5 * 2."), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- 7.0 is 3.5 * 2."), true);
|
||||||
|
|
||||||
|
submit(&mut wam, "f(X) :- X is 5 // 0.");
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- catch(f(X), evaluation_error(E), true), E = zero_divisor."),
|
||||||
|
true);
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- X is ((3 + 4) // 2) + 2 - 1 // 1, Y is 2+2, Z is X+Y."),
|
||||||
|
true);
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- X is ((3 + 4) // 2) + 2 - 1 // 1, Y is 2+2, Z = 8, Y is 4."),
|
||||||
|
true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_buffer(wam: &mut Machine, buffer: &str)
|
fn process_buffer(wam: &mut Machine, buffer: &str)
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ pub struct Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self {
|
fn new(global_index: usize, sz: usize, e: usize, cp: CodePtr, n: usize) -> Self {
|
||||||
Frame {
|
Frame {
|
||||||
global_index: global_index,
|
global_index: global_index,
|
||||||
b0: 0,
|
b0: 0,
|
||||||
e: e,
|
e: e,
|
||||||
cp: cp,
|
cp: cp,
|
||||||
perms: vec![Addr::HeapCell(0); n]
|
perms: (1 .. n+1).map(|i| Addr::StackCell(sz, i)).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,8 @@ impl AndStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
|
pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
|
||||||
self.0.push(Frame::new(global_index, e, cp, n));
|
let len = self.0.len();
|
||||||
|
self.0.push(Frame::new(global_index, len, e, cp, n));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -46,13 +47,6 @@ impl AndStack {
|
|||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.0.clear()
|
self.0.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
// drop the last n frames.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn drop_frames(&mut self, n: usize) {
|
|
||||||
let len = self.0.len();
|
|
||||||
self.0.truncate(len - n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for AndStack {
|
impl Index<usize> for AndStack {
|
||||||
|
|||||||
233
src/prolog/arithmetic.rs
Normal file
233
src/prolog/arithmetic.rs
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
use prolog::ast::*;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::cmp::{min, max};
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
pub struct ArithExprIterator<'a> {
|
||||||
|
state_stack: Vec<IteratorState<'a>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ArithExprIterator<'a> {
|
||||||
|
fn push_clause(&mut self, child_num: usize, ct: ClauseType<'a>, child_terms: &'a Vec<Box<Term>>)
|
||||||
|
{
|
||||||
|
self.state_stack.push(IteratorState::Clause(child_num, ct, child_terms));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||||
|
self.state_stack.push(IteratorState::to_state(lvl, term));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_final_cons(&mut self, lvl: Level, cell: &'a Cell<RegType>, head: &'a Term, tail: &'a Term)
|
||||||
|
{
|
||||||
|
self.state_stack.push(IteratorState::FinalCons(lvl, cell, head, tail));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(term: &'a Term) -> Result<Self, ArithmeticError> {
|
||||||
|
let state = match term {
|
||||||
|
&Term::AnonVar =>
|
||||||
|
return Err(ArithmeticError::InvalidTerm),
|
||||||
|
&Term::Clause(_, _, ref terms) =>
|
||||||
|
IteratorState::Clause(0, ClauseType::Root, terms),
|
||||||
|
&Term::Constant(ref cell, ref cons) =>
|
||||||
|
IteratorState::Constant(Level::Shallow, cell, cons),
|
||||||
|
&Term::Cons(_, _, _) =>
|
||||||
|
return Err(ArithmeticError::InvalidTerm),
|
||||||
|
&Term::Var(ref cell, ref var) =>
|
||||||
|
IteratorState::Var(Level::Shallow, cell, var)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ArithExprIterator { state_stack: vec![state] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Term {
|
||||||
|
pub fn arith_expr_iter<'a>(&'a self) -> Result<ArithExprIterator<'a>, ArithmeticError> {
|
||||||
|
ArithExprIterator::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for ArithExprIterator<'a> {
|
||||||
|
type Item = TermRef<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some(iter_state) = self.state_stack.pop() {
|
||||||
|
match iter_state {
|
||||||
|
IteratorState::AnonVar(lvl) =>
|
||||||
|
return Some(TermRef::AnonVar(lvl)),
|
||||||
|
IteratorState::Clause(child_num, ct, child_terms) => {
|
||||||
|
if child_num == child_terms.len() {
|
||||||
|
return Some(TermRef::Clause(ct, child_terms));
|
||||||
|
} else {
|
||||||
|
self.push_clause(child_num + 1, ct, child_terms);
|
||||||
|
self.push_subterm(ct.level_of_subterms(), child_terms[child_num].as_ref());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IteratorState::InitialCons(lvl, cell, head, tail) => {
|
||||||
|
self.push_final_cons(lvl, cell, head, tail);
|
||||||
|
self.push_subterm(Level::Deep, tail);
|
||||||
|
self.push_subterm(Level::Deep, head);
|
||||||
|
},
|
||||||
|
IteratorState::FinalCons(lvl, cell, head, tail) =>
|
||||||
|
return Some(TermRef::Cons(lvl, cell, head, tail)),
|
||||||
|
IteratorState::Constant(lvl, cell, constant) =>
|
||||||
|
return Some(TermRef::Constant(lvl, cell, constant)),
|
||||||
|
IteratorState::Var(lvl, cell, var) =>
|
||||||
|
return Some(TermRef::Var(lvl, cell, var))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ArithmeticEvaluator {
|
||||||
|
interm: Vec<ArithmeticTerm>,
|
||||||
|
interm_c: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArithmeticEvaluator {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ArithmeticEvaluator { interm: Vec::new(), interm_c: 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_un_instr(name: &Atom, a1: ArithmeticTerm, t: ArithEvalPlace)
|
||||||
|
-> Result<ArithmeticInstruction, ArithmeticError>
|
||||||
|
{
|
||||||
|
match name.as_str() {
|
||||||
|
"-" => Ok(ArithmeticInstruction::Neg(a1, t)),
|
||||||
|
_ => Err(ArithmeticError::InvalidOp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_bin_instr(name: &Atom, a1: ArithmeticTerm, a2: ArithmeticTerm, t: ArithEvalPlace)
|
||||||
|
-> Result<ArithmeticInstruction, ArithmeticError>
|
||||||
|
{
|
||||||
|
match name.as_str() {
|
||||||
|
"+" => Ok(ArithmeticInstruction::Add(a1, a2, t)),
|
||||||
|
"-" => Ok(ArithmeticInstruction::Sub(a1, a2, t)),
|
||||||
|
"//" => Ok(ArithmeticInstruction::IDiv(a1, a2, t)),
|
||||||
|
"div" => Ok(ArithmeticInstruction::IDiv(a1, a2, t)),
|
||||||
|
"*" => Ok(ArithmeticInstruction::Mul(a1, a2, t)),
|
||||||
|
_ => Err(ArithmeticError::InvalidOp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn incr_interm(&mut self) -> usize {
|
||||||
|
let temp = self.interm_c;
|
||||||
|
|
||||||
|
self.interm.push(ArithmeticTerm::Interm(temp));
|
||||||
|
self.interm_c += 1;
|
||||||
|
|
||||||
|
temp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instr_from_clause<'a>(&mut self, name: &'a Atom, terms: &'a Vec<Box<Term>>, deep: bool)
|
||||||
|
-> Result<ArithmeticInstruction, ArithmeticError>
|
||||||
|
{
|
||||||
|
match terms.len() {
|
||||||
|
1 => {
|
||||||
|
let a1 = self.interm.pop().unwrap();
|
||||||
|
|
||||||
|
if deep {
|
||||||
|
let ninterm = if a1.interm_or(0) == 0 {
|
||||||
|
self.incr_interm()
|
||||||
|
} else {
|
||||||
|
self.interm.push(a1.clone());
|
||||||
|
a1.interm_or(0)
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::get_un_instr(name, a1, ArithEvalPlace::Interm(ninterm))
|
||||||
|
} else {
|
||||||
|
Self::get_un_instr(name, a1, ArithEvalPlace::Reg(RegType::Temp(2)))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
2 => {
|
||||||
|
let a2 = self.interm.pop().unwrap();
|
||||||
|
let a1 = self.interm.pop().unwrap();
|
||||||
|
|
||||||
|
if deep {
|
||||||
|
let min_interm = min(a1.interm_or(0), a2.interm_or(0));
|
||||||
|
|
||||||
|
let ninterm = if min_interm == 0 {
|
||||||
|
let max_interm = max(a1.interm_or(0), a2.interm_or(0));
|
||||||
|
|
||||||
|
if max_interm == 0 {
|
||||||
|
self.incr_interm()
|
||||||
|
} else {
|
||||||
|
self.interm.push(ArithmeticTerm::Interm(max_interm));
|
||||||
|
self.interm_c = max_interm + 1;
|
||||||
|
max_interm
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.interm.push(ArithmeticTerm::Interm(min_interm));
|
||||||
|
self.interm_c = min_interm + 1;
|
||||||
|
min_interm
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::gen_bin_instr(name, a1, a2, ArithEvalPlace::Interm(ninterm))
|
||||||
|
} else {
|
||||||
|
Self::gen_bin_instr(name, a1, a2, ArithEvalPlace::Reg(RegType::Temp(2)))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => Err(ArithmeticError::InvalidOp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> {
|
||||||
|
match c {
|
||||||
|
&Constant::Float(fl) =>
|
||||||
|
self.interm.push(ArithmeticTerm::Float(fl)),
|
||||||
|
&Constant::Integer(ref bi) =>
|
||||||
|
self.interm.push(ArithmeticTerm::Integer(bi.clone())),
|
||||||
|
_ =>
|
||||||
|
return Err(ArithmeticError::InvalidAtom),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval(&mut self, term: &Term) -> Result<Code, ArithmeticError> {
|
||||||
|
let mut code = Vec::new();
|
||||||
|
|
||||||
|
for term_ref in term.arith_expr_iter()? {
|
||||||
|
match term_ref {
|
||||||
|
TermRef::Constant(_, _, c) =>
|
||||||
|
try!(self.push_constant(c)),
|
||||||
|
TermRef::Var(_, var_reg, _) =>
|
||||||
|
if var_reg.get().norm().reg_num() == 0 {
|
||||||
|
return Err(ArithmeticError::UninstantiatedVar);
|
||||||
|
} else {
|
||||||
|
self.interm.push(ArithmeticTerm::Reg(var_reg.get().norm()));
|
||||||
|
},
|
||||||
|
TermRef::Clause(ClauseType::Deep(_, _, name), terms) => {
|
||||||
|
code.push(Line::Arithmetic(self.instr_from_clause(name, terms, true)?));
|
||||||
|
},
|
||||||
|
TermRef::Clause(ClauseType::Root, terms) => {
|
||||||
|
let name = term.name().unwrap();
|
||||||
|
code.push(Line::Arithmetic(self.instr_from_clause(name, terms, false)?));
|
||||||
|
},
|
||||||
|
_ =>
|
||||||
|
return Err(ArithmeticError::InvalidTerm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arith_term) = self.interm.pop() {
|
||||||
|
match arith_term {
|
||||||
|
ArithmeticTerm::Integer(n) => {
|
||||||
|
let n = Constant::Integer(n);
|
||||||
|
code.push(query![put_constant!(Level::Shallow, n, temp_v!(2))]);
|
||||||
|
},
|
||||||
|
ArithmeticTerm::Float(n) => {
|
||||||
|
let n = Constant::Float(n);
|
||||||
|
code.push(query![put_constant!(Level::Shallow, n, temp_v!(2))]);
|
||||||
|
},
|
||||||
|
ArithmeticTerm::Reg(r) =>
|
||||||
|
code.push(query![put_value!(r, 2)]),
|
||||||
|
_ => return Err(ArithmeticError::InvalidTerm)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use prolog::num::bigint::BigInt;
|
use prolog::num::bigint::BigInt;
|
||||||
|
use prolog::num::ToPrimitive;
|
||||||
|
|
||||||
use prolog::ordered_float::*;
|
use prolog::ordered_float::*;
|
||||||
|
|
||||||
@@ -8,7 +9,7 @@ use std::collections::{HashMap, VecDeque};
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Error as IOError;
|
use std::io::Error as IOError;
|
||||||
use std::num::{ParseFloatError};
|
use std::num::{ParseFloatError};
|
||||||
use std::ops::{Add, AddAssign};
|
use std::ops::{Add, AddAssign, Sub, Mul, Div, Neg};
|
||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
@@ -189,6 +190,14 @@ macro_rules! prefix {
|
|||||||
($x:expr) => ($x & (FX | FY))
|
($x:expr) => ($x & (FX | FY))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum ArithmeticError {
|
||||||
|
InvalidAtom,
|
||||||
|
InvalidOp,
|
||||||
|
InvalidTerm,
|
||||||
|
UninstantiatedVar
|
||||||
|
}
|
||||||
|
|
||||||
/* 'TokenTooLong' is hard to detect reliably if we don't process the
|
/* 'TokenTooLong' is hard to detect reliably if we don't process the
|
||||||
input one character at a time. It would be easy to detect if the regex
|
input one character at a time. It would be easy to detect if the regex
|
||||||
library supported matching on iterator inputs, but it currently does
|
library supported matching on iterator inputs, but it currently does
|
||||||
@@ -198,6 +207,7 @@ tokens exceeding 4096 chars in length. */
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParserError
|
pub enum ParserError
|
||||||
{
|
{
|
||||||
|
Arithmetic(ArithmeticError),
|
||||||
CommaArityMismatch,
|
CommaArityMismatch,
|
||||||
UnexpectedEOF,
|
UnexpectedEOF,
|
||||||
FailedMatch(String),
|
FailedMatch(String),
|
||||||
@@ -206,13 +216,19 @@ pub enum ParserError
|
|||||||
InadmissibleQueryTerm,
|
InadmissibleQueryTerm,
|
||||||
IncompleteReduction,
|
IncompleteReduction,
|
||||||
InconsistentDeclaration,
|
InconsistentDeclaration,
|
||||||
InconsistentPredicate,
|
InconsistentPredicate,
|
||||||
ParseBigInt,
|
ParseBigInt,
|
||||||
ParseFloat(ParseFloatError),
|
ParseFloat(ParseFloatError),
|
||||||
// TokenTooLong,
|
// TokenTooLong,
|
||||||
Utf8Conversion(Utf8Error)
|
Utf8Conversion(Utf8Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ArithmeticError> for ParserError {
|
||||||
|
fn from(err: ArithmeticError) -> ParserError {
|
||||||
|
ParserError::Arithmetic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<IOError> for ParserError {
|
impl From<IOError> for ParserError {
|
||||||
fn from(err: IOError) -> ParserError {
|
fn from(err: IOError) -> ParserError {
|
||||||
ParserError::IO(err)
|
ParserError::IO(err)
|
||||||
@@ -265,6 +281,15 @@ impl fmt::Display for Constant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Number> for Constant {
|
||||||
|
fn from(n: Number) -> Self {
|
||||||
|
match n {
|
||||||
|
Number::Integer(n) => Constant::Integer(n),
|
||||||
|
Number::Float(f) => Constant::Float(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Term {
|
pub enum Term {
|
||||||
AnonVar,
|
AnonVar,
|
||||||
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
|
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
|
||||||
@@ -273,10 +298,11 @@ pub enum Term {
|
|||||||
Var(Cell<VarReg>, Var)
|
Var(Cell<VarReg>, Var)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum QueryTerm {
|
pub enum QueryTerm {
|
||||||
CallN(Vec<Box<Term>>),
|
CallN(Vec<Box<Term>>),
|
||||||
Catch(Vec<Box<Term>>),
|
Catch(Vec<Box<Term>>),
|
||||||
Cut,
|
Cut,
|
||||||
|
Is(Vec<Box<Term>>),
|
||||||
IsAtomic(Vec<Box<Term>>),
|
IsAtomic(Vec<Box<Term>>),
|
||||||
IsVar(Vec<Box<Term>>),
|
IsVar(Vec<Box<Term>>),
|
||||||
Term(Term),
|
Term(Term),
|
||||||
@@ -292,6 +318,8 @@ impl QueryTerm {
|
|||||||
QueryTermRef::Catch(terms),
|
QueryTermRef::Catch(terms),
|
||||||
&QueryTerm::Cut =>
|
&QueryTerm::Cut =>
|
||||||
QueryTermRef::Cut,
|
QueryTermRef::Cut,
|
||||||
|
&QueryTerm::Is(ref terms) =>
|
||||||
|
QueryTermRef::Is(terms),
|
||||||
&QueryTerm::IsAtomic(ref terms) =>
|
&QueryTerm::IsAtomic(ref terms) =>
|
||||||
QueryTermRef::IsAtomic(terms.first().unwrap()),
|
QueryTermRef::IsAtomic(terms.first().unwrap()),
|
||||||
&QueryTerm::IsVar(ref terms) =>
|
&QueryTerm::IsVar(ref terms) =>
|
||||||
@@ -314,13 +342,14 @@ pub enum ClauseType<'a> {
|
|||||||
CallN,
|
CallN,
|
||||||
Catch,
|
Catch,
|
||||||
Deep(Level, &'a Cell<RegType>, &'a Atom),
|
Deep(Level, &'a Cell<RegType>, &'a Atom),
|
||||||
|
Is,
|
||||||
Root,
|
Root,
|
||||||
Throw,
|
Throw,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ClauseType<'a> {
|
impl<'a> ClauseType<'a> {
|
||||||
pub fn level_of_subterms(self) -> Level {
|
pub fn level_of_subterms(self) -> Level {
|
||||||
match self {
|
match self {
|
||||||
ClauseType::Deep(_, _, _) => Level::Deep,
|
ClauseType::Deep(_, _, _) => Level::Deep,
|
||||||
_ => Level::Shallow
|
_ => Level::Shallow
|
||||||
}
|
}
|
||||||
@@ -354,6 +383,7 @@ pub enum QueryTermRef<'a> {
|
|||||||
CallN(&'a Vec<Box<Term>>),
|
CallN(&'a Vec<Box<Term>>),
|
||||||
Catch(&'a Vec<Box<Term>>),
|
Catch(&'a Vec<Box<Term>>),
|
||||||
Cut,
|
Cut,
|
||||||
|
Is(&'a Vec<Box<Term>>),
|
||||||
IsAtomic(&'a Term),
|
IsAtomic(&'a Term),
|
||||||
IsVar(&'a Term),
|
IsVar(&'a Term),
|
||||||
Term(&'a Term),
|
Term(&'a Term),
|
||||||
@@ -365,6 +395,7 @@ impl<'a> QueryTermRef<'a> {
|
|||||||
match self {
|
match self {
|
||||||
QueryTermRef::Catch(_) => 3,
|
QueryTermRef::Catch(_) => 3,
|
||||||
QueryTermRef::Throw(_) => 1,
|
QueryTermRef::Throw(_) => 1,
|
||||||
|
QueryTermRef::Is(_) => 2,
|
||||||
QueryTermRef::IsAtomic(_) => 1,
|
QueryTermRef::IsAtomic(_) => 1,
|
||||||
QueryTermRef::IsVar(_) => 1,
|
QueryTermRef::IsVar(_) => 1,
|
||||||
QueryTermRef::CallN(terms) => terms.len(),
|
QueryTermRef::CallN(terms) => terms.len(),
|
||||||
@@ -412,6 +443,132 @@ impl IndexedChoiceInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Number {
|
||||||
|
Float(OrderedFloat<f64>),
|
||||||
|
Integer(BigInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Number> for Number {
|
||||||
|
type Output = Number;
|
||||||
|
|
||||||
|
fn add(self, rhs: Number) -> Self::Output {
|
||||||
|
match (self, rhs) {
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) =>
|
||||||
|
Number::Integer(n1 + n2),
|
||||||
|
(Number::Float(n1), Number::Float(n2)) =>
|
||||||
|
Number::Float(OrderedFloat(n1.into_inner() + n2.into_inner())),
|
||||||
|
(Number::Integer(n1), Number::Float(n2))
|
||||||
|
| (Number::Float(n2), Number::Integer(n1)) =>
|
||||||
|
match n1.to_f64() {
|
||||||
|
Some(n1) => Number::Float(OrderedFloat(n1 + n2.into_inner())),
|
||||||
|
None => Number::Integer(n1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<Number> for Number {
|
||||||
|
type Output = Number;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Number) -> Self::Output {
|
||||||
|
match (self, rhs) {
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) =>
|
||||||
|
Number::Integer(n1 - n2),
|
||||||
|
(Number::Float(n1), Number::Float(n2)) =>
|
||||||
|
Number::Float(OrderedFloat(n1.into_inner() - n2.into_inner())),
|
||||||
|
(Number::Integer(n1), Number::Float(n2))
|
||||||
|
| (Number::Float(n2), Number::Integer(n1)) =>
|
||||||
|
match n1.to_f64() {
|
||||||
|
Some(n1) => Number::Float(OrderedFloat(n1 - n2.into_inner())),
|
||||||
|
None => Number::Integer(n1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Number> for Number {
|
||||||
|
type Output = Number;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Number) -> Self::Output {
|
||||||
|
match (self, rhs) {
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) =>
|
||||||
|
Number::Integer(n1 * n2),
|
||||||
|
(Number::Float(n1), Number::Float(n2)) =>
|
||||||
|
Number::Float(OrderedFloat(n1.into_inner() * n2.into_inner())),
|
||||||
|
(Number::Integer(n1), Number::Float(n2))
|
||||||
|
| (Number::Float(n2), Number::Integer(n1)) =>
|
||||||
|
match n1.to_f64() {
|
||||||
|
Some(n1) => Number::Float(OrderedFloat(n1 * n2.into_inner())),
|
||||||
|
None => Number::Integer(n1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*TODO: reserved for proper division.
|
||||||
|
impl Div<Number> for Number {
|
||||||
|
type Output = Number;
|
||||||
|
|
||||||
|
fn div(self, rhs: Number) -> Self::Output {
|
||||||
|
match (self, rhs) {
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) =>
|
||||||
|
Number::Integer(n1 / n2),
|
||||||
|
(Number::Float(n1), Number::Float(n2)) =>
|
||||||
|
Number::Float(OrderedFloat(n1.into_inner() / n2.into_inner())),
|
||||||
|
(Number::Integer(n1), Number::Float(n2))
|
||||||
|
| (Number::Float(n2), Number::Integer(n1)) =>
|
||||||
|
match n1.to_f64() {
|
||||||
|
Some(n1) => Number::Float(OrderedFloat(n1 / n2.into_inner())),
|
||||||
|
None => Number::Integer(n1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
impl Neg for Number {
|
||||||
|
type Output = Number;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
Number::Integer(n) => Number::Integer(-n),
|
||||||
|
Number::Float(f) => Number::Float(OrderedFloat(-1.0 * f.into_inner()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ArithmeticTerm {
|
||||||
|
Reg(RegType),
|
||||||
|
Interm(usize),
|
||||||
|
Float(OrderedFloat<f64>),
|
||||||
|
Integer(BigInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArithmeticTerm {
|
||||||
|
pub fn interm_or(&self, interm: usize) -> usize {
|
||||||
|
if let &ArithmeticTerm::Interm(interm) = self {
|
||||||
|
interm
|
||||||
|
} else {
|
||||||
|
interm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum ArithEvalPlace {
|
||||||
|
Interm(usize), Reg(RegType)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ArithmeticInstruction {
|
||||||
|
Add(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace),
|
||||||
|
Sub(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace),
|
||||||
|
Mul(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace),
|
||||||
|
IDiv(ArithmeticTerm, ArithmeticTerm, ArithEvalPlace),
|
||||||
|
Neg(ArithmeticTerm, ArithEvalPlace)
|
||||||
|
}
|
||||||
|
|
||||||
pub enum BuiltInInstruction {
|
pub enum BuiltInInstruction {
|
||||||
CleanUpBlock,
|
CleanUpBlock,
|
||||||
DuplicateTerm,
|
DuplicateTerm,
|
||||||
@@ -442,7 +599,9 @@ pub enum ControlInstruction {
|
|||||||
Goto(usize, usize), // p, arity.
|
Goto(usize, usize), // p, arity.
|
||||||
Proceed,
|
Proceed,
|
||||||
ThrowCall,
|
ThrowCall,
|
||||||
ThrowExecute
|
ThrowExecute,
|
||||||
|
UnifyCall,
|
||||||
|
UnifyExecute
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ControlInstruction {
|
impl ControlInstruction {
|
||||||
@@ -458,6 +617,8 @@ impl ControlInstruction {
|
|||||||
&ControlInstruction::ThrowExecute => true,
|
&ControlInstruction::ThrowExecute => true,
|
||||||
&ControlInstruction::Goto(_, _) => true,
|
&ControlInstruction::Goto(_, _) => true,
|
||||||
&ControlInstruction::Proceed => true,
|
&ControlInstruction::Proceed => true,
|
||||||
|
&ControlInstruction::UnifyCall => true,
|
||||||
|
&ControlInstruction::UnifyExecute => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -508,6 +669,7 @@ pub type CompiledFact = Vec<FactInstruction>;
|
|||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
pub type CompiledQuery = Vec<QueryInstruction>;
|
||||||
|
|
||||||
pub enum Line {
|
pub enum Line {
|
||||||
|
Arithmetic(ArithmeticInstruction),
|
||||||
BuiltIn(BuiltInInstruction),
|
BuiltIn(BuiltInInstruction),
|
||||||
Choice(ChoiceInstruction),
|
Choice(ChoiceInstruction),
|
||||||
Control(ControlInstruction),
|
Control(ControlInstruction),
|
||||||
@@ -700,3 +862,29 @@ impl Term {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum IteratorState<'a> {
|
||||||
|
AnonVar(Level),
|
||||||
|
Clause(usize, ClauseType<'a>, &'a Vec<Box<Term>>),
|
||||||
|
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IteratorState<'a> {
|
||||||
|
pub fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a> {
|
||||||
|
match term {
|
||||||
|
&Term::AnonVar =>
|
||||||
|
IteratorState::AnonVar(lvl),
|
||||||
|
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
||||||
|
IteratorState::Clause(0, ClauseType::Deep(lvl, cell, atom), child_terms),
|
||||||
|
&Term::Cons(ref cell, ref head, ref tail) =>
|
||||||
|
IteratorState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()),
|
||||||
|
&Term::Constant(ref cell, ref constant) =>
|
||||||
|
IteratorState::Constant(lvl, cell, constant),
|
||||||
|
&Term::Var(ref cell, ref var) =>
|
||||||
|
IteratorState::Var(lvl, cell, var)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ fn get_builtins() -> Code {
|
|||||||
proceed!(),
|
proceed!(),
|
||||||
fact![get_value!(temp_v!(1), 2)], // =/2, 73.
|
fact![get_value!(temp_v!(1), 2)], // =/2, 73.
|
||||||
proceed!(),
|
proceed!(),
|
||||||
succeed!(), // true/0, 75.
|
proceed!() // true/0, 75.
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,8 +118,19 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir)
|
|||||||
op_dir.insert((String::from(":-"), Fixity::In), (XFX, 1200));
|
op_dir.insert((String::from(":-"), Fixity::In), (XFX, 1200));
|
||||||
op_dir.insert((String::from(":-"), Fixity::Pre), (FX, 1200));
|
op_dir.insert((String::from(":-"), Fixity::Pre), (FX, 1200));
|
||||||
op_dir.insert((String::from("?-"), Fixity::Pre), (FX, 1200));
|
op_dir.insert((String::from("?-"), Fixity::Pre), (FX, 1200));
|
||||||
|
|
||||||
|
// control operators.
|
||||||
op_dir.insert((String::from("\\+"), Fixity::Pre), (FY, 900));
|
op_dir.insert((String::from("\\+"), Fixity::Pre), (FY, 900));
|
||||||
op_dir.insert((String::from("="), Fixity::In), (XFX, 700));
|
op_dir.insert((String::from("="), Fixity::In), (XFX, 700));
|
||||||
|
|
||||||
|
// arithmetic operators.
|
||||||
|
op_dir.insert((String::from("is"), Fixity::In), (XFX, 700));
|
||||||
|
op_dir.insert((String::from("+"), Fixity::In), (YFX, 500));
|
||||||
|
op_dir.insert((String::from("-"), Fixity::In), (YFX, 500));
|
||||||
|
op_dir.insert((String::from("//"), Fixity::In), (YFX, 400));
|
||||||
|
op_dir.insert((String::from("div"), Fixity::In), (YFX, 400));
|
||||||
|
op_dir.insert((String::from("*"), Fixity::In), (YFX, 400));
|
||||||
|
op_dir.insert((String::from("-"), Fixity::Pre), (FY, 200));
|
||||||
|
|
||||||
// there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62
|
// 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)
|
// (an extra register is needed for the predicate name)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use prolog::allocator::*;
|
use prolog::allocator::*;
|
||||||
|
use prolog::arithmetic::*;
|
||||||
use prolog::ast::*;
|
use prolog::ast::*;
|
||||||
use prolog::fixtures::*;
|
use prolog::fixtures::*;
|
||||||
use prolog::indexing::*;
|
use prolog::indexing::*;
|
||||||
@@ -14,7 +15,10 @@ pub struct CodeGenerator<'a, TermMarker> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum EvalSession<'a> {
|
pub enum EvalSession<'a> {
|
||||||
EntryFailure(String),
|
OpIsInfixAndPostFix,
|
||||||
|
NamelessEntry,
|
||||||
|
ParserError(ParserError),
|
||||||
|
ImpermissibleEntry(String),
|
||||||
EntrySuccess,
|
EntrySuccess,
|
||||||
InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
|
InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
|
||||||
QueryFailure,
|
QueryFailure,
|
||||||
@@ -256,11 +260,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
|
if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
|
||||||
*ctrl = ControlInstruction::ThrowExecute;
|
*ctrl = ControlInstruction::ThrowExecute;
|
||||||
},
|
},
|
||||||
QueryTermRef::IsAtomic(_) => {
|
QueryTermRef::Is(_) =>
|
||||||
dealloc_index = code.len();
|
if let &mut Line::Control(ref mut ctrl) = code.last_mut().unwrap() {
|
||||||
code.push(proceed!());
|
*ctrl = ControlInstruction::UnifyExecute;
|
||||||
},
|
},
|
||||||
QueryTermRef::IsVar(_) => {
|
QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) => {
|
||||||
dealloc_index = code.len();
|
dealloc_index = code.len();
|
||||||
code.push(proceed!());
|
code.push(proceed!());
|
||||||
},
|
},
|
||||||
@@ -275,6 +279,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
conjunct_info: &ConjunctInfo<'a>,
|
conjunct_info: &ConjunctInfo<'a>,
|
||||||
code: &mut Code,
|
code: &mut Code,
|
||||||
is_exposed: bool)
|
is_exposed: bool)
|
||||||
|
-> Result<(), ParserError>
|
||||||
{
|
{
|
||||||
for (chunk_num, _, terms) in iter {
|
for (chunk_num, _, terms) in iter {
|
||||||
for (i, term) in terms.iter().enumerate()
|
for (i, term) in terms.iter().enumerate()
|
||||||
@@ -300,13 +305,47 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
Line::Cut(CutInstruction::Cut(Terminal::Terminal))
|
Line::Cut(CutInstruction::Cut(Terminal::Terminal))
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
&QueryTermRef::Is(terms) => {
|
||||||
|
let mut evaluator = ArithmeticEvaluator::new();
|
||||||
|
|
||||||
|
let mut arith_code = evaluator.eval(terms[1].as_ref())?;
|
||||||
|
code.append(&mut arith_code);
|
||||||
|
|
||||||
|
match terms[0].as_ref() {
|
||||||
|
&Term::Var(ref vr, ref name) => {
|
||||||
|
let mut target = Vec::new();
|
||||||
|
|
||||||
|
self.marker.advance(term_loc, *term);
|
||||||
|
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
|
||||||
|
|
||||||
|
code.push(Line::Query(target));
|
||||||
|
code.push(unify_call!());
|
||||||
|
},
|
||||||
|
&Term::Constant(_, Constant::Float(fl)) => {
|
||||||
|
code.push(query![put_constant!(Level::Shallow,
|
||||||
|
Constant::Float(fl),
|
||||||
|
temp_v!(1))]);
|
||||||
|
code.push(unify_call!());
|
||||||
|
},
|
||||||
|
&Term::Constant(_, Constant::Integer(ref bi)) => {
|
||||||
|
let bi = bi.clone();
|
||||||
|
code.push(query![put_constant!(Level::Shallow,
|
||||||
|
Constant::Integer(bi),
|
||||||
|
temp_v!(1))]);
|
||||||
|
code.push(unify_call!());
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return Err(ParserError::from(ArithmeticError::InvalidTerm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
&QueryTermRef::IsAtomic(inner_term) =>
|
&QueryTermRef::IsAtomic(inner_term) =>
|
||||||
match inner_term {
|
match inner_term {
|
||||||
&Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
|
&Term::AnonVar | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
|
||||||
code.push(fail!()); //goto!(61, 0)); // goto false/0.
|
code.push(fail!());
|
||||||
},
|
},
|
||||||
&Term::Constant(_, _) => {
|
&Term::Constant(_, _) => {
|
||||||
code.push(succeed!()); //goto!(75, 0)); // goto succeed/0.
|
code.push(succeed!());
|
||||||
},
|
},
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
let mut target = Vec::new();
|
let mut target = Vec::new();
|
||||||
@@ -321,10 +360,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
&QueryTermRef::IsVar(inner_term) =>
|
&QueryTermRef::IsVar(inner_term) =>
|
||||||
match inner_term {
|
match inner_term {
|
||||||
&Term::Constant(_, _) | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
|
&Term::Constant(_, _) | &Term::Clause(_, _, _) | &Term::Cons(_, _, _) => {
|
||||||
code.push(fail!()); //goto!(61, 0)); // goto false/0.
|
code.push(fail!());
|
||||||
},
|
},
|
||||||
&Term::AnonVar => {
|
&Term::AnonVar => {
|
||||||
code.push(succeed!()); //goto!(75, 0)); // goto succeed/0.
|
code.push(succeed!());
|
||||||
},
|
},
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
let mut target = Vec::new();
|
let mut target = Vec::new();
|
||||||
@@ -352,6 +391,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
self.marker.reset_contents();
|
self.marker.reset_contents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_seq_prelude(&mut self, conjunct_info: &ConjunctInfo, body: &mut Code)
|
fn compile_seq_prelude(&mut self, conjunct_info: &ConjunctInfo, body: &mut Code)
|
||||||
@@ -376,7 +417,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Code
|
pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result<Code, ParserError>
|
||||||
{
|
{
|
||||||
let iter = ChunkedIterator::from_rule(rule);
|
let iter = ChunkedIterator::from_rule(rule);
|
||||||
let conjunct_info = self.collect_var_data(iter);
|
let conjunct_info = self.collect_var_data(iter);
|
||||||
@@ -393,7 +434,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
}
|
}
|
||||||
|
|
||||||
let iter = ChunkedIterator::from_rule_body(p1, clauses);
|
let iter = ChunkedIterator::from_rule_body(p1, clauses);
|
||||||
self.compile_seq(iter, &conjunct_info, &mut code, false);
|
try!(self.compile_seq(iter, &conjunct_info, &mut code, false));
|
||||||
|
|
||||||
if conjunct_info.allocates() {
|
if conjunct_info.allocates() {
|
||||||
let index = if let &Line::Control(_) = code.last().unwrap() {
|
let index = if let &Line::Control(_) = code.last().unwrap() {
|
||||||
@@ -408,7 +449,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1).to_ref());
|
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1).to_ref());
|
||||||
code
|
Ok(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact)
|
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact)
|
||||||
@@ -476,7 +517,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
Self::add_conditional_call(code, term, index);
|
Self::add_conditional_call(code, term, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_query(&mut self, query: &'a Vec<QueryTerm>) -> Code
|
pub fn compile_query(&mut self, query: &'a Vec<QueryTerm>) -> Result<Code, ParserError>
|
||||||
{
|
{
|
||||||
let iter = ChunkedIterator::from_term_sequence(query);
|
let iter = ChunkedIterator::from_term_sequence(query);
|
||||||
let conjunct_info = self.collect_var_data(iter);
|
let conjunct_info = self.collect_var_data(iter);
|
||||||
@@ -485,7 +526,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
self.compile_seq_prelude(&conjunct_info, &mut code);
|
self.compile_seq_prelude(&conjunct_info, &mut code);
|
||||||
|
|
||||||
let iter = ChunkedIterator::from_term_sequence(query);
|
let iter = ChunkedIterator::from_term_sequence(query);
|
||||||
self.compile_seq(iter, &conjunct_info, &mut code, true);
|
try!(self.compile_seq(iter, &conjunct_info, &mut code, true));
|
||||||
|
|
||||||
if conjunct_info.allocates() {
|
if conjunct_info.allocates() {
|
||||||
let index = if let &Line::Control(_) = code.last().unwrap() {
|
let index = if let &Line::Control(_) = code.last().unwrap() {
|
||||||
@@ -500,7 +541,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Self::compile_cleanup(&mut code, &conjunct_info, query.last().unwrap().to_ref());
|
Self::compile_cleanup(&mut code, &conjunct_info, query.last().unwrap().to_ref());
|
||||||
code
|
Ok(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_predicate(clauses: &Vec<PredicateClause>) -> Vec<(usize, usize)>
|
fn split_predicate(clauses: &Vec<PredicateClause>) -> Vec<(usize, usize)>
|
||||||
@@ -529,7 +570,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
subseqs
|
subseqs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_pred_subseq<'b: 'a>(&mut self, clauses: &'b [PredicateClause]) -> Code
|
fn compile_pred_subseq<'b: 'a>(&mut self, clauses: &'b [PredicateClause])
|
||||||
|
-> Result<Code, ParserError>
|
||||||
{
|
{
|
||||||
let mut code_body = Vec::new();
|
let mut code_body = Vec::new();
|
||||||
let mut code_offsets = CodeOffsets::new();
|
let mut code_offsets = CodeOffsets::new();
|
||||||
@@ -543,7 +585,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
&PredicateClause::Fact(ref fact) =>
|
&PredicateClause::Fact(ref fact) =>
|
||||||
self.compile_fact(fact),
|
self.compile_fact(fact),
|
||||||
&PredicateClause::Rule(ref rule) =>
|
&PredicateClause::Rule(ref rule) =>
|
||||||
self.compile_rule(rule)
|
try!(self.compile_rule(rule))
|
||||||
};
|
};
|
||||||
|
|
||||||
if num_clauses > 1 {
|
if num_clauses > 1 {
|
||||||
@@ -567,17 +609,18 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
let mut code = Vec::new();
|
let mut code = Vec::new();
|
||||||
|
|
||||||
code_offsets.add_indices(&mut code, code_body);
|
code_offsets.add_indices(&mut code, code_body);
|
||||||
code
|
Ok(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_predicate<'b: 'a>(&mut self, clauses: &'b Vec<PredicateClause>) -> Code
|
pub fn compile_predicate<'b: 'a>(&mut self, clauses: &'b Vec<PredicateClause>)
|
||||||
|
-> Result<Code, ParserError>
|
||||||
{
|
{
|
||||||
let mut code = Vec::new();
|
let mut code = Vec::new();
|
||||||
let split_pred = Self::split_predicate(&clauses);
|
let split_pred = Self::split_predicate(&clauses);
|
||||||
let multi_seq = split_pred.len() > 1;
|
let multi_seq = split_pred.len() > 1;
|
||||||
|
|
||||||
for (l, r) in split_pred {
|
for (l, r) in split_pred {
|
||||||
let mut code_segment = self.compile_pred_subseq(&clauses[l .. r]);
|
let mut code_segment = try!(self.compile_pred_subseq(&clauses[l .. r]));
|
||||||
|
|
||||||
if multi_seq {
|
if multi_seq {
|
||||||
let choice = match l {
|
let choice = match l {
|
||||||
@@ -592,6 +635,6 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
|||||||
code.append(&mut code_segment);
|
code.append(&mut code_segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
code
|
Ok(code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,11 @@ impl fmt::Display for ControlInstruction {
|
|||||||
&ControlInstruction::ThrowCall =>
|
&ControlInstruction::ThrowCall =>
|
||||||
write!(f, "call_throw"),
|
write!(f, "call_throw"),
|
||||||
&ControlInstruction::ThrowExecute =>
|
&ControlInstruction::ThrowExecute =>
|
||||||
write!(f, "execute_throw")
|
write!(f, "execute_throw"),
|
||||||
|
&ControlInstruction::UnifyCall =>
|
||||||
|
write!(f, "unify_call"),
|
||||||
|
&ControlInstruction::UnifyExecute =>
|
||||||
|
write!(f, "unify_execute"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,10 +158,10 @@ impl fmt::Display for BuiltInInstruction {
|
|||||||
write!(f, "set_ball"),
|
write!(f, "set_ball"),
|
||||||
&BuiltInInstruction::Succeed =>
|
&BuiltInInstruction::Succeed =>
|
||||||
write!(f, "true"),
|
write!(f, "true"),
|
||||||
|
&BuiltInInstruction::UnwindStack =>
|
||||||
|
write!(f, "unwind_stack"),
|
||||||
&BuiltInInstruction::Unify =>
|
&BuiltInInstruction::Unify =>
|
||||||
write!(f, "unify"),
|
write!(f, "unify"),
|
||||||
&BuiltInInstruction::UnwindStack =>
|
|
||||||
write!(f, "unwind_stack")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,6 +192,45 @@ impl fmt::Display for IndexingInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ArithmeticTerm {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&ArithmeticTerm::Reg(r) => write!(f, "{}", r),
|
||||||
|
&ArithmeticTerm::Interm(i) => write!(f, "@{}", i),
|
||||||
|
&ArithmeticTerm::Float(fl) => write!(f, "{}", fl),
|
||||||
|
&ArithmeticTerm::Integer(ref bi) => write!(f, "{}", bi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ArithEvalPlace {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&ArithEvalPlace::Reg(r) =>
|
||||||
|
write!(f, "{}", r),
|
||||||
|
&ArithEvalPlace::Interm(i) =>
|
||||||
|
write!(f, "@{}", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ArithmeticInstruction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&ArithmeticInstruction::Add(ref a1, ref a2, ref t) =>
|
||||||
|
write!(f, "add {}, {}, {}", a1, a2, t),
|
||||||
|
&ArithmeticInstruction::Sub(ref a1, ref a2, ref t) =>
|
||||||
|
write!(f, "sub {}, {}, {}", a1, a2, t),
|
||||||
|
&ArithmeticInstruction::Mul(ref a1, ref a2, ref t) =>
|
||||||
|
write!(f, "mul {}, {}, {}", a1, a2, t),
|
||||||
|
&ArithmeticInstruction::IDiv(ref a1, ref a2, ref t) =>
|
||||||
|
write!(f, "idiv {}, {}, {}", a1, a2, t),
|
||||||
|
&ArithmeticInstruction::Neg(ref a, ref t) =>
|
||||||
|
write!(f, "neg {}, {}", a, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for CutInstruction {
|
impl fmt::Display for CutInstruction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -236,6 +279,8 @@ impl fmt::Display for RegType {
|
|||||||
pub fn print_code(code: &Code) {
|
pub fn print_code(code: &Code) {
|
||||||
for clause in code {
|
for clause in code {
|
||||||
match clause {
|
match clause {
|
||||||
|
&Line::Arithmetic(ref arith) =>
|
||||||
|
println!("{}", arith),
|
||||||
&Line::Fact(ref fact) =>
|
&Line::Fact(ref fact) =>
|
||||||
for fact_instr in fact {
|
for fact_instr in fact {
|
||||||
println!("{}", fact_instr);
|
println!("{}", fact_instr);
|
||||||
@@ -294,7 +339,11 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'
|
|||||||
&TopLevel::Predicate(ref clauses) => {
|
&TopLevel::Predicate(ref clauses) => {
|
||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||||
|
|
||||||
let compiled_pred = cg.compile_predicate(clauses);
|
let compiled_pred = match cg.compile_predicate(clauses) {
|
||||||
|
Ok(pred) => pred,
|
||||||
|
Err(e) => return EvalSession::ParserError(e)
|
||||||
|
};
|
||||||
|
|
||||||
wam.add_predicate(clauses, compiled_pred)
|
wam.add_predicate(clauses, compiled_pred)
|
||||||
},
|
},
|
||||||
&TopLevel::Fact(ref fact) => {
|
&TopLevel::Fact(ref fact) => {
|
||||||
@@ -306,13 +355,21 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'
|
|||||||
&TopLevel::Rule(ref rule) => {
|
&TopLevel::Rule(ref rule) => {
|
||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||||
|
|
||||||
let compiled_rule = cg.compile_rule(rule);
|
let compiled_rule = match cg.compile_rule(rule) {
|
||||||
|
Ok(rule) => rule,
|
||||||
|
Err(e) => return EvalSession::ParserError(e)
|
||||||
|
};
|
||||||
|
|
||||||
wam.add_rule(rule, compiled_rule)
|
wam.add_rule(rule, compiled_rule)
|
||||||
},
|
},
|
||||||
&TopLevel::Query(ref query) => {
|
&TopLevel::Query(ref query) => {
|
||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||||
|
|
||||||
let compiled_query = cg.compile_query(query);
|
let compiled_query = match cg.compile_query(query) {
|
||||||
|
Ok(query) => query,
|
||||||
|
Err(e) => return EvalSession::ParserError(e)
|
||||||
|
};
|
||||||
|
|
||||||
wam.submit_query(compiled_query, cg.take_vars())
|
wam.submit_query(compiled_query, cg.take_vars())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,7 +442,10 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
|
|||||||
},
|
},
|
||||||
EvalSession::QueryFailure => println!("false."),
|
EvalSession::QueryFailure => println!("false."),
|
||||||
EvalSession::QueryFailureWithException(e) => println!("{}", error_string(&e)),
|
EvalSession::QueryFailureWithException(e) => println!("{}", error_string(&e)),
|
||||||
EvalSession::EntryFailure(msg) => println!("{}", msg),
|
EvalSession::ImpermissibleEntry(msg) => println!("cannot overwrite builtin {}", msg),
|
||||||
|
EvalSession::OpIsInfixAndPostFix => println!("cannot define an op to be both postfix and infix."),
|
||||||
|
EvalSession::NamelessEntry => println!("the predicate head is not an atom or clause."),
|
||||||
|
EvalSession::ParserError(e) => println!("{:?}", e),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,32 +5,6 @@ use std::collections::VecDeque;
|
|||||||
use std::iter::*;
|
use std::iter::*;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
enum IteratorState<'a> {
|
|
||||||
AnonVar(Level),
|
|
||||||
Clause(usize, ClauseType<'a>, &'a Vec<Box<Term>>),
|
|
||||||
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IteratorState<'a> {
|
|
||||||
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a> {
|
|
||||||
match term {
|
|
||||||
&Term::AnonVar =>
|
|
||||||
IteratorState::AnonVar(lvl),
|
|
||||||
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
|
||||||
IteratorState::Clause(0, ClauseType::Deep(lvl, cell, atom), child_terms),
|
|
||||||
&Term::Cons(ref cell, ref head, ref tail) =>
|
|
||||||
IteratorState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()),
|
|
||||||
&Term::Constant(ref cell, ref constant) =>
|
|
||||||
IteratorState::Constant(lvl, cell, constant),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::Var(lvl, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct QueryIterator<'a> {
|
pub struct QueryIterator<'a> {
|
||||||
state_stack: Vec<IteratorState<'a>>
|
state_stack: Vec<IteratorState<'a>>
|
||||||
}
|
}
|
||||||
@@ -77,13 +51,17 @@ impl<'a> QueryIterator<'a> {
|
|||||||
let state = IteratorState::Clause(0, ClauseType::Catch, terms);
|
let state = IteratorState::Clause(0, ClauseType::Catch, terms);
|
||||||
QueryIterator { state_stack: vec![state] }
|
QueryIterator { state_stack: vec![state] }
|
||||||
},
|
},
|
||||||
|
QueryTermRef::Is(terms) => {
|
||||||
|
let state = IteratorState::Clause(0, ClauseType::Is, terms);
|
||||||
|
QueryIterator { state_stack: vec![state] }
|
||||||
|
},
|
||||||
QueryTermRef::IsAtomic(term) | QueryTermRef::IsVar(term) | QueryTermRef::Term(term) =>
|
QueryTermRef::IsAtomic(term) | QueryTermRef::IsVar(term) | QueryTermRef::Term(term) =>
|
||||||
Self::from_term(term),
|
Self::from_term(term),
|
||||||
QueryTermRef::Throw(term) => {
|
QueryTermRef::Throw(term) => {
|
||||||
let state = IteratorState::Clause(0, ClauseType::Throw, term);
|
let state = IteratorState::Clause(0, ClauseType::Throw, term);
|
||||||
QueryIterator { state_stack: vec![state] }
|
QueryIterator { state_stack: vec![state] }
|
||||||
},
|
},
|
||||||
_ => QueryIterator { state_stack: vec![] }
|
QueryTermRef::Cut => QueryIterator { state_stack: vec![] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,6 +296,11 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
arity = child_terms.len();
|
arity = child_terms.len();
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
|
QueryTermRef::Is(_) => {
|
||||||
|
result.push(term);
|
||||||
|
arity = 2;
|
||||||
|
break;
|
||||||
|
},
|
||||||
QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) =>
|
QueryTermRef::IsAtomic(_) | QueryTermRef::IsVar(_) =>
|
||||||
result.push(term),
|
result.push(term),
|
||||||
QueryTermRef::Cut => {
|
QueryTermRef::Cut => {
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ use prolog::codegen::*;
|
|||||||
use prolog::copier::*;
|
use prolog::copier::*;
|
||||||
use prolog::heapview::*;
|
use prolog::heapview::*;
|
||||||
use prolog::and_stack::*;
|
use prolog::and_stack::*;
|
||||||
|
use prolog::num::Zero;
|
||||||
|
use prolog::num::bigint::BigInt;
|
||||||
use prolog::or_stack::*;
|
use prolog::or_stack::*;
|
||||||
|
use prolog::ordered_float::OrderedFloat;
|
||||||
use prolog::fixtures::*;
|
use prolog::fixtures::*;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -36,7 +39,8 @@ struct MachineState {
|
|||||||
tr: usize,
|
tr: usize,
|
||||||
hb: usize,
|
hb: usize,
|
||||||
block: usize, // an offset into the OR stack.
|
block: usize, // an offset into the OR stack.
|
||||||
ball: (usize, Heap) // heap boundary, and a term copy
|
ball: (usize, Heap), // heap boundary, and a term copy
|
||||||
|
interms: Vec<Number> // intermediate numbers.
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DuplicateTerm<'a> {
|
struct DuplicateTerm<'a> {
|
||||||
@@ -225,9 +229,7 @@ impl Machine {
|
|||||||
{
|
{
|
||||||
match self.code_dir.get(&(name.clone(), arity)) {
|
match self.code_dir.get(&(name.clone(), arity)) {
|
||||||
Some(&(PredicateKeyType::BuiltIn, _)) =>
|
Some(&(PredicateKeyType::BuiltIn, _)) =>
|
||||||
return EvalSession::EntryFailure(format!("error: cannot replace built-in predicate {}/{}",
|
return EvalSession::ImpermissibleEntry(format!("{}/{}", name, arity)),
|
||||||
name,
|
|
||||||
arity)),
|
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -246,7 +248,7 @@ impl Machine {
|
|||||||
self.code.append(&mut code);
|
self.code.append(&mut code);
|
||||||
self.add_user_code(name, arity, p)
|
self.add_user_code(name, arity, p)
|
||||||
} else {
|
} else {
|
||||||
EvalSession::EntryFailure(format!("error: the fact has no name."))
|
EvalSession::NamelessEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +263,7 @@ impl Machine {
|
|||||||
self.code.append(&mut code);
|
self.code.append(&mut code);
|
||||||
self.add_user_code(name, arity, p)
|
self.add_user_code(name, arity, p)
|
||||||
} else {
|
} else {
|
||||||
EvalSession::EntryFailure(format!("error: the rule has no name."))
|
EvalSession::NamelessEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,6 +299,8 @@ impl Machine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match instr {
|
match instr {
|
||||||
|
&Line::Arithmetic(ref arith_instr) =>
|
||||||
|
self.ms.execute_arith_instr(arith_instr),
|
||||||
&Line::BuiltIn(ref built_in_instr) =>
|
&Line::BuiltIn(ref built_in_instr) =>
|
||||||
self.ms.execute_built_in_instr(&self.code_dir, built_in_instr),
|
self.ms.execute_built_in_instr(&self.code_dir, built_in_instr),
|
||||||
&Line::Choice(ref choice_instr) =>
|
&Line::Choice(ref choice_instr) =>
|
||||||
@@ -408,11 +412,11 @@ impl Machine {
|
|||||||
|
|
||||||
while self.ms.p < end_ptr {
|
while self.ms.p < end_ptr {
|
||||||
if let CodePtr::TopLevel(mut cn, p) = self.ms.p {
|
if let CodePtr::TopLevel(mut cn, p) = self.ms.p {
|
||||||
match &self[CodePtr::TopLevel(cn, p)] {
|
match &self[CodePtr::TopLevel(cn, p)] {
|
||||||
&Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
|
&Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
|
||||||
self.record_var_places(cn, alloc_locs, heap_locs);
|
self.record_var_places(cn, alloc_locs, heap_locs);
|
||||||
cn += 1;
|
cn += 1;
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,10 +426,10 @@ impl Machine {
|
|||||||
self.query_stepper();
|
self.query_stepper();
|
||||||
|
|
||||||
match self.ms.p {
|
match self.ms.p {
|
||||||
CodePtr::TopLevel(_, p) if p > 0 => {},
|
CodePtr::TopLevel(_, p) if p > 0 => {},
|
||||||
_ => break
|
_ => break
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fail<'a>(&mut self) -> EvalSession<'a>
|
fn fail<'a>(&mut self) -> EvalSession<'a>
|
||||||
@@ -443,21 +447,16 @@ impl Machine {
|
|||||||
pub fn submit_decl<'a>(&mut self, decl: &Declaration) -> EvalSession<'a> {
|
pub fn submit_decl<'a>(&mut self, decl: &Declaration) -> EvalSession<'a> {
|
||||||
match decl {
|
match decl {
|
||||||
&Declaration::Op(prec, spec, ref name) => {
|
&Declaration::Op(prec, spec, ref name) => {
|
||||||
lazy_static! {
|
|
||||||
static ref ERR_STRING: String = String::from("an operator can't be both \
|
|
||||||
infix and postfix.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_infix!(spec) {
|
if is_infix!(spec) {
|
||||||
match self.op_dir.get(&(name.clone(), Fixity::Post)) {
|
match self.op_dir.get(&(name.clone(), Fixity::Post)) {
|
||||||
Some(_) => return EvalSession::EntryFailure(ERR_STRING.clone()),
|
Some(_) => return EvalSession::OpIsInfixAndPostFix,
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_postfix!(spec) {
|
if is_postfix!(spec) {
|
||||||
match self.op_dir.get(&(name.clone(), Fixity::In)) {
|
match self.op_dir.get(&(name.clone(), Fixity::In)) {
|
||||||
Some(_) => return EvalSession::EntryFailure(ERR_STRING.clone()),
|
Some(_) => return EvalSession::OpIsInfixAndPostFix,
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -598,6 +597,18 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! try_or_fail {
|
||||||
|
($s:ident, $e:expr) => {{
|
||||||
|
match $e {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(msg) => {
|
||||||
|
$s.throw_exception(string!(msg));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
fn new() -> MachineState {
|
fn new() -> MachineState {
|
||||||
MachineState { h: 0,
|
MachineState { h: 0,
|
||||||
@@ -618,7 +629,8 @@ impl MachineState {
|
|||||||
tr: 0,
|
tr: 0,
|
||||||
hb: 0,
|
hb: 0,
|
||||||
block: 0,
|
block: 0,
|
||||||
ball: (0, Vec::new())
|
ball: (0, Vec::new()),
|
||||||
|
interms: vec![Number::Float(OrderedFloat(0f64)); 256],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,7 +765,7 @@ impl MachineState {
|
|||||||
Ref::HeapCell(r) =>
|
Ref::HeapCell(r) =>
|
||||||
self.heap[r] = HeapCellValue::Ref(Ref::HeapCell(r)),
|
self.heap[r] = HeapCellValue::Ref(Ref::HeapCell(r)),
|
||||||
Ref::StackCell(fr, sc) =>
|
Ref::StackCell(fr, sc) =>
|
||||||
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
|
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -821,6 +833,92 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_number(&self, at: &ArithmeticTerm) -> Result<Number, &'static str> {
|
||||||
|
match at {
|
||||||
|
&ArithmeticTerm::Reg(r) => {
|
||||||
|
let addr = self[r].clone();
|
||||||
|
let item = self.deref(addr);
|
||||||
|
|
||||||
|
match item {
|
||||||
|
Addr::Con(Constant::Integer(bi)) =>
|
||||||
|
Ok(Number::Integer(bi)),
|
||||||
|
Addr::Con(Constant::Float(fl)) =>
|
||||||
|
Ok(Number::Float(fl)),
|
||||||
|
_ =>
|
||||||
|
Err("is/2: variable not instantiated to number.")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&ArithmeticTerm::Interm(i) => Ok(self.interms[i].clone()),
|
||||||
|
&ArithmeticTerm::Float(fl) => Ok(Number::Float(fl)),
|
||||||
|
&ArithmeticTerm::Integer(ref bi) => Ok(Number::Integer(bi.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assign_arith(&mut self, t: ArithEvalPlace, n: Number) {
|
||||||
|
match t {
|
||||||
|
ArithEvalPlace::Reg(r) =>
|
||||||
|
self[r] = Addr::Con(Constant::from(n)),
|
||||||
|
ArithEvalPlace::Interm(i) =>
|
||||||
|
self.interms[i] = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) {
|
||||||
|
match instr {
|
||||||
|
&ArithmeticInstruction::Add(ref a1, ref a2, t) => {
|
||||||
|
let n1 = try_or_fail!(self, self.get_number(a1));
|
||||||
|
let n2 = try_or_fail!(self, self.get_number(a2));
|
||||||
|
|
||||||
|
self.assign_arith(t, n1 + n2);
|
||||||
|
self.p += 1;
|
||||||
|
},
|
||||||
|
&ArithmeticInstruction::Sub(ref a1, ref a2, t) => {
|
||||||
|
let n1 = try_or_fail!(self, self.get_number(a1));
|
||||||
|
let n2 = try_or_fail!(self, self.get_number(a2));
|
||||||
|
|
||||||
|
self.assign_arith(t, n1 - n2);
|
||||||
|
self.p += 1;
|
||||||
|
},
|
||||||
|
&ArithmeticInstruction::Mul(ref a1, ref a2, t) => {
|
||||||
|
let n1 = try_or_fail!(self, self.get_number(a1));
|
||||||
|
let n2 = try_or_fail!(self, self.get_number(a2));
|
||||||
|
|
||||||
|
self.assign_arith(t, n1 * n2);
|
||||||
|
self.p += 1;
|
||||||
|
},
|
||||||
|
&ArithmeticInstruction::IDiv(ref a1, ref a2, t) => {
|
||||||
|
let n1 = try_or_fail!(self, self.get_number(a1));
|
||||||
|
let n2 = try_or_fail!(self, self.get_number(a2));
|
||||||
|
|
||||||
|
match (n1, n2) {
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||||
|
if n2 == BigInt::zero() {
|
||||||
|
self.throw_exception(functor!("evaluation_error",
|
||||||
|
1,
|
||||||
|
[atom!("zero_divisor")]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assign_arith(t, Number::Integer(n1 / n2));
|
||||||
|
self.p += 1;
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
self.throw_exception(functor!("evaluation_error",
|
||||||
|
1,
|
||||||
|
[atom!("expected_integer_args")]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&ArithmeticInstruction::Neg(ref a1, t) => {
|
||||||
|
let n1 = try_or_fail!(self, self.get_number(a1));
|
||||||
|
|
||||||
|
self.assign_arith(t, - n1);
|
||||||
|
self.p += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
||||||
match instr {
|
match instr {
|
||||||
&FactInstruction::GetConstant(_, ref c, reg) => {
|
&FactInstruction::GetConstant(_, ref c, reg) => {
|
||||||
@@ -1306,13 +1404,6 @@ impl MachineState {
|
|||||||
self.write_constant_to_var(addr, &c);
|
self.write_constant_to_var(addr, &c);
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
},
|
},
|
||||||
&BuiltInInstruction::Unify => {
|
|
||||||
let a1 = self[temp_v!(1)].clone();
|
|
||||||
let a2 = self[temp_v!(2)].clone();
|
|
||||||
|
|
||||||
self.unify(a1, a2);
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&BuiltInInstruction::EraseBall => {
|
&BuiltInInstruction::EraseBall => {
|
||||||
self.ball.0 = 0;
|
self.ball.0 = 0;
|
||||||
self.ball.1.truncate(0);
|
self.ball.1.truncate(0);
|
||||||
@@ -1414,16 +1505,26 @@ impl MachineState {
|
|||||||
},
|
},
|
||||||
&BuiltInInstruction::Succeed => {
|
&BuiltInInstruction::Succeed => {
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
|
},
|
||||||
|
&BuiltInInstruction::Unify => {
|
||||||
|
self.inline_unify();
|
||||||
|
self.p += 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inline_unify(&mut self) {
|
||||||
|
let a1 = self[temp_v!(1)].clone();
|
||||||
|
let a2 = self[temp_v!(2)].clone();
|
||||||
|
|
||||||
|
self.unify(a1, a2);
|
||||||
|
}
|
||||||
|
|
||||||
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
||||||
{
|
{
|
||||||
match instr {
|
match instr {
|
||||||
&ControlInstruction::Allocate(num_cells) => {
|
&ControlInstruction::Allocate(num_cells) => {
|
||||||
let num_frames = self.num_frames();
|
let num_frames = self.num_frames();
|
||||||
|
|
||||||
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
|
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
|
||||||
|
|
||||||
self.e = self.and_stack.len() - 1;
|
self.e = self.and_stack.len() - 1;
|
||||||
@@ -1473,7 +1574,15 @@ impl MachineState {
|
|||||||
},
|
},
|
||||||
&ControlInstruction::ThrowExecute => {
|
&ControlInstruction::ThrowExecute => {
|
||||||
self.goto_throw();
|
self.goto_throw();
|
||||||
}
|
},
|
||||||
|
&ControlInstruction::UnifyCall => {
|
||||||
|
self.inline_unify();
|
||||||
|
self.p += 1;
|
||||||
|
},
|
||||||
|
&ControlInstruction::UnifyExecute => {
|
||||||
|
self.inline_unify();
|
||||||
|
self.p = self.cp;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1512,7 +1621,7 @@ impl MachineState {
|
|||||||
self.registers[i] = self.or_stack[b][i].clone();
|
self.registers[i] = self.or_stack[b][i].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.e = self.or_stack[b].e;
|
self.e = self.or_stack[b].e;
|
||||||
self.cp = self.or_stack[b].cp;
|
self.cp = self.or_stack[b].cp;
|
||||||
|
|
||||||
self.or_stack[b].bp = self.p + 1;
|
self.or_stack[b].bp = self.p + 1;
|
||||||
@@ -1559,7 +1668,7 @@ impl MachineState {
|
|||||||
|
|
||||||
self.hb = self.h;
|
self.hb = self.h;
|
||||||
self.p += l;
|
self.p += l;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1598,7 +1707,7 @@ impl MachineState {
|
|||||||
self.registers[i] = self.or_stack[b][i].clone();
|
self.registers[i] = self.or_stack[b][i].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.e = self.or_stack[b].e;
|
self.e = self.or_stack[b].e;
|
||||||
self.cp = self.or_stack[b].cp;
|
self.cp = self.or_stack[b].cp;
|
||||||
|
|
||||||
self.or_stack[b].bp = self.p + offset;
|
self.or_stack[b].bp = self.p + offset;
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ macro_rules! query {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! string {
|
||||||
|
($str:expr) => {
|
||||||
|
vec![HeapCellValue::Con(Constant::String(String::from($str)))]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! functor {
|
macro_rules! functor {
|
||||||
($name:expr, $len:expr, [$($args:expr),*]) => {{
|
($name:expr, $len:expr, [$($args:expr),*]) => {{
|
||||||
if $len > 0 {
|
if $len > 0 {
|
||||||
@@ -81,6 +87,12 @@ macro_rules! put_var {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! put_constant {
|
||||||
|
($lvl:expr, $cons:expr, $r:expr) => (
|
||||||
|
QueryInstruction::PutConstant($lvl, $cons, $r)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! put_value {
|
macro_rules! put_value {
|
||||||
($r:expr, $arg:expr) => (
|
($r:expr, $arg:expr) => (
|
||||||
QueryInstruction::PutValue($r, $arg)
|
QueryInstruction::PutValue($r, $arg)
|
||||||
@@ -197,6 +209,12 @@ macro_rules! unify {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! unify_call {
|
||||||
|
() => (
|
||||||
|
Line::Control(ControlInstruction::UnifyCall)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! unwind_stack {
|
macro_rules! unwind_stack {
|
||||||
() => (
|
() => (
|
||||||
Line::BuiltIn(BuiltInInstruction::UnwindStack)
|
Line::BuiltIn(BuiltInInstruction::UnwindStack)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ pub mod and_stack;
|
|||||||
pub mod ast;
|
pub mod ast;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
pub mod arithmetic;
|
||||||
pub mod builtins;
|
pub mod builtins;
|
||||||
pub mod codegen;
|
pub mod codegen;
|
||||||
pub mod copier;
|
pub mod copier;
|
||||||
|
|||||||
Submodule src/prolog/parser updated: da30488df7...ebecfec050
Reference in New Issue
Block a user