prepare for batch processing.

This commit is contained in:
Mark Thom
2018-01-29 22:04:51 -07:00
parent bb49f35027
commit 73714e8aa2
7 changed files with 112 additions and 48 deletions

View File

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

View File

@@ -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> ");

View File

@@ -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,

View File

@@ -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))
} }
} }

View File

@@ -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),
_ => {} _ => {}
}; };
} }

View File

@@ -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);
} }