From 73714e8aa2969c2042a08f6ecae3ba101a759040 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 29 Jan 2018 22:04:51 -0700 Subject: [PATCH] prepare for batch processing. --- README.md | 8 ++-- src/main.rs | 6 +++ src/prolog/ast.rs | 2 + src/prolog/codegen.rs | 20 ++++++--- src/prolog/io.rs | 93 +++++++++++++++++++++++++++++---------- src/prolog/machine/mod.rs | 29 ++++++------ src/prolog/parser | 2 +- 7 files changed, 112 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 4a68be18..a7cc1599 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Extend rusty-wam to include the following, among other features: * Built-in control operators (`,`, `;`, `->`, etc.) (_done_). * Built-in predicates for list processing and top-level declarative control (`setup_call_control/3`, `call_with_inference_limit/3`, - etc.) + etc.) (_in progress_). * Add a rudimentary module system. * Attributed variables using the SICStus Prolog interface and semantics. Adding coroutines like `dif/2`, `freeze/2`, etc. @@ -84,7 +84,7 @@ The following predicates are built-in to rusty-wam. * `(;)/2` * `arg/3` * `atomic/1` -* `call/N` (1 <= N <= 63) +* `call/1..63` * `catch/3` * `display/1` * `duplicate_term/2` @@ -171,7 +171,7 @@ Lastly, rusty-wam supports dynamic operators. Using the built-in 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. -X = -(+(-(5), 3), //(*(2, 4), 8)). ``` \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c9ce711c..2a223d85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,10 @@ mod prolog; use prolog::io::*; use prolog::machine::*; +use std::fs::File; +use std::io::prelude::*; +use std::path::Path; + #[cfg(test)] mod tests; @@ -24,6 +28,8 @@ fn process_buffer(wam: &mut Machine, buffer: &str) fn prolog_repl() { let mut wam = Machine::new(); + load_init_file(&mut wam, "lists.pl"); + loop { print!("prolog> "); diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 1cb783e0..7574e536 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -409,6 +409,8 @@ pub struct Rule { pub clauses: Vec } + + #[derive(Clone, Copy)] pub enum ClauseType<'a> { Arg, diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index 811ddbec..460a2a47 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -16,21 +16,31 @@ pub struct CodeGenerator<'a, TermMarker> { var_count: HashMap<&'a Var, usize> } -pub enum EvalSession<'a> { +pub enum EvalError { OpIsInfixAndPostFix, NamelessEntry, ParserError(ParserError), ImpermissibleEntry(String), - EntrySuccess, - InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>), QueryFailure, - QueryFailureWithException(String), + QueryFailureWithException(String) +} + +pub enum EvalSession<'a> { + EntrySuccess, + Error(EvalError), + InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>), SubsequentQuerySuccess, } +impl<'a> From for EvalSession<'a> { + fn from(err: EvalError) -> Self { + EvalSession::Error(err) + } +} + impl<'a> From for EvalSession<'a> { fn from(err: ParserError) -> Self { - EvalSession::ParserError(err) + EvalSession::from(EvalError::ParserError(err)) } } diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 185eb3f7..694176de 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -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 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -370,6 +384,12 @@ pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result Result, ParserError> +{ + let mut worker = TopLevelWorker::new(wam.atom_tbl(), wam.op_dir()); + worker.parse_batch(buffer) +} + pub fn read() -> String { let _ = stdout().flush(); @@ -419,7 +439,7 @@ fn compile_relation(tl: &TopLevel) -> Result fn set_first_index(code: &mut Code) { let code_len = code.len(); - + for (idx, line) in code.iter_mut().enumerate() { match line { &mut Line::Control(ControlInstruction::JmpByExecute(_, ref mut offset)) @@ -446,27 +466,22 @@ fn compile_query<'a>(terms: &'a Vec, queue: &'a Vec) -> Result<(Code, AllocVarDict<'a>), ParserError> { let mut cg = CodeGenerator::::new(); - let mut code = try!(cg.compile_query(terms)); - + let mut code = try!(cg.compile_query(terms)); + compile_appendix(&mut code, queue)?; Ok((code, cg.take_vars())) } -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) + -> 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(TopLevel::Declaration(ref decl), _) => - wam.submit_decl(decl), - &TopLevelPacket::Decl(ref tl, ref queue) => { + &TopLevel::Declaration(ref decl) => wam.submit_decl(decl), + _ => { let mut code = match compile_relation(tl) { 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) { @@ -477,15 +492,48 @@ pub fn compile<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevelPacket) -> Eval if let Some(name) = tl.name() { wam.add_user_code(name, tl.arity(), code) } else { - EvalSession::NamelessEntry + EvalSession::from(EvalError::NamelessEntry) } } 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) + -> 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 { format!("error: exception thrown: {}", e) } @@ -506,7 +554,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) { } loop { - let mut result = EvalSession::QueryFailure; + let mut result = EvalSession::from(EvalError::QueryFailure); let mut output = PrinterOutputter::new(); 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(); stdout.flush().unwrap(); 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(); stdout.flush().unwrap(); return; @@ -553,12 +603,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) { write!(stdout(), ".\n").unwrap(); }, - EvalSession::QueryFailure => println!("false."), - 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), + EvalSession::Error(e) => println!("{}", e), _ => {} }; } diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index fe05da8e..11ff6cab 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -39,9 +39,10 @@ impl Index for Machine { impl Machine { 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()); - + + Machine { ms: machine_state::MachineState::new(atom_tbl), code, @@ -64,7 +65,7 @@ impl Machine { { match self.code_dir.get(&(name.clone(), arity)) { 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_dir.insert((name, arity), (PredicateKeyType::User, offset)); - + EvalSession::EntrySuccess } @@ -209,7 +210,7 @@ impl Machine { }, _ => {} } - + self.ms.p = CodePtr::TopLevel(cn, p); } @@ -232,10 +233,10 @@ impl Machine { TermFormatter {}, PrinterOutputter::new()) .result(); - - EvalSession::QueryFailureWithException(msg) + + EvalSession::from(EvalError::QueryFailureWithException(msg)) } else { - EvalSession::QueryFailure + EvalSession::from(EvalError::QueryFailure) } } @@ -245,14 +246,14 @@ impl Machine { &Declaration::Op(prec, spec, ref name) => { if is_infix!(spec) { match self.op_dir.get(&(name.clone(), Fixity::Post)) { - Some(_) => return EvalSession::OpIsInfixAndPostFix, + Some(_) => return EvalSession::from(EvalError::OpIsInfixAndPostFix), _ => {} }; } if is_postfix!(spec) { 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; if let CodePtr::TopLevel(_, 0) = self.ms.p { - return EvalSession::QueryFailure; + return EvalSession::from(EvalError::QueryFailure); } self.run_query(alloc_l, heap_l); @@ -309,7 +310,7 @@ impl Machine { EvalSession::SubsequentQuerySuccess } } else { - EvalSession::QueryFailure + EvalSession::from(EvalError::QueryFailure) } } @@ -318,10 +319,10 @@ impl Machine { { for (var, addr) in var_dir { output.begin_new_var(); - + output.append(var.as_str()); output.append(" = "); - + output = self.ms.print_term(addr.clone(), TermFormatter {}, output); } diff --git a/src/prolog/parser b/src/prolog/parser index f2e730cb..64866ff3 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit f2e730cbbabead3c432883c8c2317d76cd426220 +Subproject commit 64866ff3ef1982d996a56e1330c4c2ac3ecd9d41 -- 2.54.0