prepare for batch processing.
This commit is contained in:
@@ -23,7 +23,7 @@ Extend rusty-wam to include the following, among other features:
|
|||||||
* Built-in control operators (`,`, `;`, `->`, etc.) (_done_).
|
* Built-in control operators (`,`, `;`, `->`, etc.) (_done_).
|
||||||
* Built-in predicates for list processing and top-level declarative
|
* Built-in predicates for list processing and top-level declarative
|
||||||
control (`setup_call_control/3`, `call_with_inference_limit/3`,
|
control (`setup_call_control/3`, `call_with_inference_limit/3`,
|
||||||
etc.)
|
etc.) (_in progress_).
|
||||||
* Add a rudimentary module system.
|
* Add a rudimentary module system.
|
||||||
* 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.
|
||||||
@@ -84,7 +84,7 @@ The following predicates are built-in to rusty-wam.
|
|||||||
* `(;)/2`
|
* `(;)/2`
|
||||||
* `arg/3`
|
* `arg/3`
|
||||||
* `atomic/1`
|
* `atomic/1`
|
||||||
* `call/N` (1 <= N <= 63)
|
* `call/1..63`
|
||||||
* `catch/3`
|
* `catch/3`
|
||||||
* `display/1`
|
* `display/1`
|
||||||
* `duplicate_term/2`
|
* `duplicate_term/2`
|
||||||
@@ -171,7 +171,7 @@ Lastly, rusty-wam supports dynamic operators. Using the built-in
|
|||||||
arithmetic operators with the usual precedences,
|
arithmetic operators with the usual precedences,
|
||||||
|
|
||||||
```
|
```
|
||||||
prolog> ?- X = -5 + 3 - (2 * 4) // 8.
|
prolog> ?- display(-5 + 3 - (2 * 4) // 8).
|
||||||
|
'-'('+'('-'(5), 3), '//'('*'(2, 4), 8))
|
||||||
true.
|
true.
|
||||||
X = -(+(-(5), 3), //(*(2, 4), 8)).
|
|
||||||
```
|
```
|
||||||
@@ -7,6 +7,10 @@ mod prolog;
|
|||||||
use prolog::io::*;
|
use prolog::io::*;
|
||||||
use prolog::machine::*;
|
use prolog::machine::*;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
@@ -24,6 +28,8 @@ fn process_buffer(wam: &mut Machine, buffer: &str)
|
|||||||
fn prolog_repl() {
|
fn prolog_repl() {
|
||||||
let mut wam = Machine::new();
|
let mut wam = Machine::new();
|
||||||
|
|
||||||
|
load_init_file(&mut wam, "lists.pl");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
print!("prolog> ");
|
print!("prolog> ");
|
||||||
|
|
||||||
|
|||||||
@@ -409,6 +409,8 @@ pub struct Rule {
|
|||||||
pub clauses: Vec<QueryTerm>
|
pub clauses: Vec<QueryTerm>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ClauseType<'a> {
|
pub enum ClauseType<'a> {
|
||||||
Arg,
|
Arg,
|
||||||
|
|||||||
@@ -16,21 +16,31 @@ pub struct CodeGenerator<'a, TermMarker> {
|
|||||||
var_count: HashMap<&'a Var, usize>
|
var_count: HashMap<&'a Var, usize>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum EvalSession<'a> {
|
pub enum EvalError {
|
||||||
OpIsInfixAndPostFix,
|
OpIsInfixAndPostFix,
|
||||||
NamelessEntry,
|
NamelessEntry,
|
||||||
ParserError(ParserError),
|
ParserError(ParserError),
|
||||||
ImpermissibleEntry(String),
|
ImpermissibleEntry(String),
|
||||||
EntrySuccess,
|
|
||||||
InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
|
|
||||||
QueryFailure,
|
QueryFailure,
|
||||||
QueryFailureWithException(String),
|
QueryFailureWithException(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum EvalSession<'a> {
|
||||||
|
EntrySuccess,
|
||||||
|
Error(EvalError),
|
||||||
|
InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
|
||||||
SubsequentQuerySuccess,
|
SubsequentQuerySuccess,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<EvalError> for EvalSession<'a> {
|
||||||
|
fn from(err: EvalError) -> Self {
|
||||||
|
EvalSession::Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<ParserError> for EvalSession<'a> {
|
impl<'a> From<ParserError> for EvalSession<'a> {
|
||||||
fn from(err: ParserError) -> Self {
|
fn from(err: ParserError) -> Self {
|
||||||
EvalSession::ParserError(err)
|
EvalSession::from(EvalError::ParserError(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -243,6 +243,20 @@ impl fmt::Display for IndexingInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for EvalError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&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::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."),
|
||||||
|
&EvalError::ParserError(ref e) => write!(f, "{:?}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for ArithmeticTerm {
|
impl fmt::Display for ArithmeticTerm {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -370,6 +384,12 @@ pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result<TopLevelPacket, Par
|
|||||||
worker.parse_code(buffer)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read() -> String {
|
pub fn read() -> String {
|
||||||
let _ = stdout().flush();
|
let _ = stdout().flush();
|
||||||
|
|
||||||
@@ -419,7 +439,7 @@ fn compile_relation(tl: &TopLevel) -> Result<Code, ParserError>
|
|||||||
fn set_first_index(code: &mut Code)
|
fn set_first_index(code: &mut Code)
|
||||||
{
|
{
|
||||||
let code_len = code.len();
|
let code_len = code.len();
|
||||||
|
|
||||||
for (idx, line) in code.iter_mut().enumerate() {
|
for (idx, line) in code.iter_mut().enumerate() {
|
||||||
match line {
|
match line {
|
||||||
&mut Line::Control(ControlInstruction::JmpByExecute(_, ref mut offset))
|
&mut Line::Control(ControlInstruction::JmpByExecute(_, ref mut offset))
|
||||||
@@ -446,27 +466,22 @@ fn compile_query<'a>(terms: &'a Vec<QueryTerm>, queue: &'a Vec<TopLevel>)
|
|||||||
-> Result<(Code, AllocVarDict<'a>), ParserError>
|
-> Result<(Code, AllocVarDict<'a>), ParserError>
|
||||||
{
|
{
|
||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
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)?;
|
compile_appendix(&mut code, queue)?;
|
||||||
|
|
||||||
Ok((code, cg.take_vars()))
|
Ok((code, cg.take_vars()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevelPacket) -> EvalSession<'b>
|
fn compile_decl<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel, queue: &'b Vec<TopLevel>)
|
||||||
|
-> EvalSession<'b>
|
||||||
{
|
{
|
||||||
match tl {
|
match tl {
|
||||||
&TopLevelPacket::Query(ref terms, ref queue) =>
|
&TopLevel::Declaration(ref decl) => wam.submit_decl(decl),
|
||||||
match compile_query(terms, queue) {
|
_ => {
|
||||||
Ok((code, vars)) => wam.submit_query(code, vars),
|
|
||||||
Err(e) => EvalSession::from(e)
|
|
||||||
},
|
|
||||||
&TopLevelPacket::Decl(TopLevel::Declaration(ref decl), _) =>
|
|
||||||
wam.submit_decl(decl),
|
|
||||||
&TopLevelPacket::Decl(ref tl, ref queue) => {
|
|
||||||
let mut code = match compile_relation(tl) {
|
let mut code = match compile_relation(tl) {
|
||||||
Ok(code) => code,
|
Ok(code) => code,
|
||||||
Err(e) => return EvalSession::ParserError(e)
|
Err(e) => return EvalSession::from(EvalError::ParserError(e))
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = compile_appendix(&mut code, queue) {
|
if let Err(e) = compile_appendix(&mut code, queue) {
|
||||||
@@ -477,15 +492,48 @@ pub fn compile<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevelPacket) -> Eval
|
|||||||
if let Some(name) = tl.name() {
|
if let Some(name) = tl.name() {
|
||||||
wam.add_user_code(name, tl.arity(), code)
|
wam.add_user_code(name, tl.arity(), code)
|
||||||
} else {
|
} else {
|
||||||
EvalSession::NamelessEntry
|
EvalSession::from(EvalError::NamelessEntry)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EvalSession::ImpermissibleEntry(String::from("no code generated."))
|
EvalSession::from(EvalError::ImpermissibleEntry(String::from("no code generated.")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compile<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevelPacket) -> EvalSession<'b>
|
||||||
|
{
|
||||||
|
match tl {
|
||||||
|
&TopLevelPacket::Query(ref terms, ref queue) =>
|
||||||
|
match compile_query(terms, queue) {
|
||||||
|
Ok((code, vars)) => wam.submit_query(code, vars),
|
||||||
|
Err(e) => EvalSession::from(e)
|
||||||
|
},
|
||||||
|
&TopLevelPacket::Decl(ref tl, ref queue) =>
|
||||||
|
compile_decl(wam, tl, queue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile_batch<'a, 'b: 'a>(wam: &'a mut Machine, tls: &'b Vec<TopLevelPacket>)
|
||||||
|
-> EvalSession<'b>
|
||||||
|
{
|
||||||
|
for tl in tls {
|
||||||
|
match tl {
|
||||||
|
&TopLevelPacket::Query(..) =>
|
||||||
|
return EvalSession::from(ParserError::ExpectedRel),
|
||||||
|
&TopLevelPacket::Decl(ref tl, ref queue) => {
|
||||||
|
let result = compile_decl(wam, tl, queue);
|
||||||
|
|
||||||
|
if let &EvalSession::Error(_) = &result {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EvalSession::EntrySuccess
|
||||||
|
}
|
||||||
|
|
||||||
fn error_string(e: &String) -> String {
|
fn error_string(e: &String) -> String {
|
||||||
format!("error: exception thrown: {}", e)
|
format!("error: exception thrown: {}", e)
|
||||||
}
|
}
|
||||||
@@ -506,7 +554,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut result = EvalSession::QueryFailure;
|
let mut result = EvalSession::from(EvalError::QueryFailure);
|
||||||
let mut output = PrinterOutputter::new();
|
let mut output = PrinterOutputter::new();
|
||||||
|
|
||||||
let bindings = wam.heap_view(&heap_locs, output).result();
|
let bindings = wam.heap_view(&heap_locs, output).result();
|
||||||
@@ -535,13 +583,15 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let &EvalSession::QueryFailure = &result {
|
if let &EvalSession::Error(EvalError::QueryFailure) = &result
|
||||||
|
{
|
||||||
write!(stdout, "false.\n\r").unwrap();
|
write!(stdout, "false.\n\r").unwrap();
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let &EvalSession::QueryFailureWithException(ref e) = &result {
|
if let &EvalSession::Error(EvalError::QueryFailureWithException(ref e)) = &result
|
||||||
|
{
|
||||||
write!(stdout, "{}\n\r", error_string(e)).unwrap();
|
write!(stdout, "{}\n\r", error_string(e)).unwrap();
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
return;
|
return;
|
||||||
@@ -553,12 +603,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
|
|||||||
|
|
||||||
write!(stdout(), ".\n").unwrap();
|
write!(stdout(), ".\n").unwrap();
|
||||||
},
|
},
|
||||||
EvalSession::QueryFailure => println!("false."),
|
EvalSession::Error(e) => println!("{}", e),
|
||||||
EvalSession::QueryFailureWithException(e) => println!("{}", error_string(&e)),
|
|
||||||
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),
|
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,10 @@ impl Index<CodePtr> for Machine {
|
|||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let atom_tbl = Rc::new(RefCell::new(HashSet::new()));
|
let atom_tbl = Rc::new(RefCell::new(HashSet::new()));
|
||||||
let (code, code_dir, op_dir) = build_code_dir(atom_tbl.clone());
|
let (code, code_dir, op_dir) = build_code_dir(atom_tbl.clone());
|
||||||
|
|
||||||
|
|
||||||
Machine {
|
Machine {
|
||||||
ms: machine_state::MachineState::new(atom_tbl),
|
ms: machine_state::MachineState::new(atom_tbl),
|
||||||
code,
|
code,
|
||||||
@@ -64,7 +65,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::ImpermissibleEntry(format!("{}/{}", name, arity)),
|
return EvalSession::from(EvalError::ImpermissibleEntry(format!("{}/{}", name, arity))),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ impl Machine {
|
|||||||
|
|
||||||
self.code.append(&mut code);
|
self.code.append(&mut code);
|
||||||
self.code_dir.insert((name, arity), (PredicateKeyType::User, offset));
|
self.code_dir.insert((name, arity), (PredicateKeyType::User, offset));
|
||||||
|
|
||||||
EvalSession::EntrySuccess
|
EvalSession::EntrySuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +210,7 @@ impl Machine {
|
|||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ms.p = CodePtr::TopLevel(cn, p);
|
self.ms.p = CodePtr::TopLevel(cn, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,10 +233,10 @@ impl Machine {
|
|||||||
TermFormatter {},
|
TermFormatter {},
|
||||||
PrinterOutputter::new())
|
PrinterOutputter::new())
|
||||||
.result();
|
.result();
|
||||||
|
|
||||||
EvalSession::QueryFailureWithException(msg)
|
EvalSession::from(EvalError::QueryFailureWithException(msg))
|
||||||
} else {
|
} else {
|
||||||
EvalSession::QueryFailure
|
EvalSession::from(EvalError::QueryFailure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,14 +246,14 @@ impl Machine {
|
|||||||
&Declaration::Op(prec, spec, ref name) => {
|
&Declaration::Op(prec, spec, ref name) => {
|
||||||
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::OpIsInfixAndPostFix,
|
Some(_) => return EvalSession::from(EvalError::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::OpIsInfixAndPostFix,
|
Some(_) => return EvalSession::from(EvalError::OpIsInfixAndPostFix),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -298,7 +299,7 @@ impl Machine {
|
|||||||
self.ms.p = self.ms.or_stack[b].bp;
|
self.ms.p = self.ms.or_stack[b].bp;
|
||||||
|
|
||||||
if let CodePtr::TopLevel(_, 0) = self.ms.p {
|
if let CodePtr::TopLevel(_, 0) = self.ms.p {
|
||||||
return EvalSession::QueryFailure;
|
return EvalSession::from(EvalError::QueryFailure);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.run_query(alloc_l, heap_l);
|
self.run_query(alloc_l, heap_l);
|
||||||
@@ -309,7 +310,7 @@ impl Machine {
|
|||||||
EvalSession::SubsequentQuerySuccess
|
EvalSession::SubsequentQuerySuccess
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EvalSession::QueryFailure
|
EvalSession::from(EvalError::QueryFailure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,10 +319,10 @@ impl Machine {
|
|||||||
{
|
{
|
||||||
for (var, addr) in var_dir {
|
for (var, addr) in var_dir {
|
||||||
output.begin_new_var();
|
output.begin_new_var();
|
||||||
|
|
||||||
output.append(var.as_str());
|
output.append(var.as_str());
|
||||||
output.append(" = ");
|
output.append(" = ");
|
||||||
|
|
||||||
output = self.ms.print_term(addr.clone(), TermFormatter {}, output);
|
output = self.ms.print_term(addr.clone(), TermFormatter {}, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Submodule src/prolog/parser updated: f2e730cbba...64866ff3ef
Reference in New Issue
Block a user