From fd703c36106faf16b54688c848c00693f05310f7 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 17 Mar 2019 17:49:51 -0600 Subject: [PATCH] make toplevel more consistent with answers, depend on readline package without renaming. --- Cargo.lock | 170 --------------------------------- Cargo.toml | 6 +- README.md | 36 ++++--- src/main.rs | 5 +- src/prolog/machine/toplevel.rs | 29 +++--- src/prolog/read.rs | 49 +++++++--- 6 files changed, 80 insertions(+), 215 deletions(-) delete mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 8095debb..00000000 --- a/Cargo.lock +++ /dev/null @@ -1,170 +0,0 @@ -[[package]] -name = "downcast" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.50" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-complex" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-iter" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-rational" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ordered-float" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "prolog_parser" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "readline-rs" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_syscall" -version = "0.1.51" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scryer-prolog" -version = "0.8.6" -dependencies = [ - "downcast 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "prolog_parser 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "readline-rs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum downcast 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6c6fe31318b6ef21166c8e839e680238eb16f875849d597544eead7ec882eed3" -"checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" -"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" -"checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718" -"checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8" -"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" -"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" -"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" -"checksum prolog_parser 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6da85e0cfa5a604edf65f753e629db37bfd04af93a09a1df5576d2197a2f7af3" -"checksum readline-rs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f35410ab92501753b66a269387df7a8162daeaf816f6528ba8b07b34f0d80c99" -"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml index b57a8357..83ba717f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,6 @@ -cargo-features = ["rename-dependency"] - [package] name = "scryer-prolog" -version = "0.8.7" +version = "0.8.8" authors = ["Mark Thom "] repository = "https://github.com/mthom/scryer-prolog" description = "A modern Prolog implementation written mostly in Rust." @@ -13,7 +11,7 @@ downcast = "0.9.1" num = "0.2" ordered-float = "0.5.0" prolog_parser = "0.8.1" -readline_rs = { package = "readline-rs", version = "0.1.2" } +readline_rs_compat = { version = "0.1.3" } [dependencies.termion] version = "1.4.0" \ No newline at end of file diff --git a/README.md b/README.md index 4b1a69e6..8300f561 100644 --- a/README.md +++ b/README.md @@ -218,11 +218,11 @@ To enter a multi-clause predicate, the directive "[user]" is used. For example, ``` -prolog> [user] +?- [user]. (type Enter + Ctrl-D to terminate the stream when finished) p(f(f(X)), h(W), Y) :- g(W), h(W), f(X). p(X, Y, Z) :- h(Y), z(Z). -prolog> [user] +?- [user]. (type Enter + Ctrl-D to terminate the stream when finished) h(x). h(y). h(z). @@ -232,7 +232,7 @@ input stream. The instructive message is always printed. Queries are issued as ``` -prolog> ?- p(X, Y, Z). +?- p(X, Y, Z). ``` Pressing `SPACE` will backtrack through other possible answers, if any exist. @@ -241,10 +241,11 @@ Pressing `.` will abort the search and return to the prompt. Wildcards work as well: ``` -prolog> [user] +?- [user]. +(type Enter + Ctrl-D to terminate the stream when finished) member(X, [X|_]). member(X, [_|Xs]) :- member(X, Xs). -prolog> ?- member(X, [a, b, c]). +?- member(X, [a, b, c]). true . X = a ; X = b ; @@ -253,13 +254,12 @@ false. ``` and so do conjunctive queries: ``` -prolog> [user] +?- [user]. +(type Enter + Ctrl-D to terminate the stream when finished) f(X) :- g(X). -prolog> [user] g(x). g(y). g(z). -prolog> [user] h(call(f, X)). -prolog> ?- h(X), X. +?- h(X), X. true . X = call(f, x) ; X = call(f, y) ; @@ -270,13 +270,18 @@ Note that the values of variables belonging to successful queries are printed out, on one line each. Uninstantiated variables are denoted by a number preceded by an underscore (`X = _0` in an example above). +To quit scryer-prolog, type +``` +?- halt. +``` + ### Dynamic operators Scryper supports dynamic operators. Using the built-in arithmetic operators with the usual precedences, ``` -prolog> ?- write_canonical(-5 + 3 - (2 * 4) // 8). +?- write_canonical(-5 + 3 - (2 * 4) // 8). -(+(-(5), 3), //(*(2, 4), 8)) true. ``` @@ -314,15 +319,16 @@ operators and predicates are hidden in their own modules that have not been exported to the toplevel. To export them, write ``` -prolog> :- use_module(library(lists)). -prolog> :- use_module(library(control)). +?- use_module(library(lists)). +?- use_module(library(control)). ``` The [user] prompt can also be used to define modules inline at the REPL: ``` -prolog> [user] +?- [user]. +(type Enter + Ctrl-D to terminate the stream when finished) :- module(test, [local_member/2]). :- use_module(library(lists)). @@ -332,7 +338,7 @@ local_member(X, Xs) :- member(X, Xs). `use_module` directives can be qualified by adding a list of imports: ``` -prolog> :- use_module(library(lists), [member/2]). +?- use_module(library(lists), [member/2]). ``` A qualified `use_module` can be used to remove imports from the @@ -342,5 +348,5 @@ The `(:)/2` operator resolves calls to predicates that might not be imported to the current working namespace: ``` -prolog> ?- lists:member(X, Xs). +?- lists:member(X, Xs). ``` diff --git a/src/main.rs b/src/main.rs index e1e9a4c1..f0bb3fc3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate downcast; #[macro_use] extern crate prolog_parser; -extern crate readline_rs; +extern crate readline_rs_compat; extern crate termion; mod prolog; @@ -34,7 +34,7 @@ fn prolog_repl() { Ok(Input::Batch) => { set_line_mode(LineMode::Multi); - let src = match read_line("") { + let src = match read_batch("") { Ok(src) => src, Err(e) => { println!("{}", e); @@ -45,7 +45,6 @@ fn prolog_repl() { let result = compile_user_module(&mut wam, src.as_bytes()); print(&mut wam, result); }, - Ok(Input::Quit) => break, Ok(Input::Clear) => { wam.clear(); continue; diff --git a/src/prolog/machine/toplevel.rs b/src/prolog/machine/toplevel.rs index bd569265..c956cd8a 100644 --- a/src/prolog/machine/toplevel.rs +++ b/src/prolog/machine/toplevel.rs @@ -231,8 +231,10 @@ fn setup_qualified_import(mut terms: Vec>) -> Result Result +fn setup_declaration(mut terms: Vec>) -> Result { + let term = *terms.pop().unwrap(); + match term { Term::Clause(_, name, mut terms, _) => if name.as_str() == "op" && terms.len() == 3 { @@ -592,11 +594,12 @@ impl RelationWorker { } } - fn setup_query(&mut self, indices: &mut CompositeIndices, terms: Vec>, blocks_cuts: bool) + fn setup_query(&mut self, indices: &mut CompositeIndices, terms: Vec>, + blocks_cuts: bool) -> Result, ParserError> { let mut query_terms = vec![]; - let mut work_queue = VecDeque::from(terms); + let mut work_queue = VecDeque::from(terms); while let Some(term) = work_queue.pop_front() { let mut term = *term; @@ -651,9 +654,9 @@ impl RelationWorker { blocks_cuts: bool, assume_dyn: bool) -> Result { - let post_head_terms: Vec<_> = terms.drain(1 ..).collect(); - let head = *terms.first().cloned().unwrap(); + let post_head_terms: Vec<_> = terms.drain(1 .. ).collect(); + let tail = *post_head_terms.first().cloned().unwrap(); if assume_dyn { @@ -677,19 +680,23 @@ impl RelationWorker { -> Result { match term { - Term::Clause(r, name, mut terms, fixity) => + Term::Clause(r, name, terms, fixity) => if let Some(hook) = is_compile_time_hook(&name, &terms) { let term = Term::Clause(r, name, terms, fixity); let (hook, clause, queue) = self.setup_hook(hook, indices, term)?; Ok(TopLevel::Declaration(Declaration::Hook(hook, clause, queue))) } else if name.as_str() == "?-" { - Ok(TopLevel::Query(try!(self.setup_query(indices, terms, blocks_cuts)))) - } else if name.as_str() == ":-" && terms.len() > 1 { - Ok(TopLevel::Rule(try!(self.setup_rule(indices, terms, blocks_cuts, true)))) + match setup_declaration(terms.iter().cloned().collect()) { + Ok(decl) => return Ok(TopLevel::Declaration(decl)), + _ => {} + }; + + Ok(TopLevel::Query(self.setup_query(indices, terms, blocks_cuts)?)) + } else if name.as_str() == ":-" && terms.len() == 2 { + Ok(TopLevel::Rule(self.setup_rule(indices, terms, blocks_cuts, true)?)) } else if name.as_str() == ":-" && terms.len() == 1 { - let term = *terms.pop().unwrap(); - Ok(TopLevel::Declaration(try!(setup_declaration(term)))) + Ok(TopLevel::Declaration(setup_declaration(terms)?)) } else { let term = Term::Clause(r, name, terms, fixity); Ok(TopLevel::Fact(try!(self.setup_fact(term, true)))) diff --git a/src/prolog/read.rs b/src/prolog/read.rs index a36c9f13..e8c7c70d 100644 --- a/src/prolog/read.rs +++ b/src/prolog/read.rs @@ -11,7 +11,7 @@ use prolog::machine::machine_state::MachineState; use std::collections::VecDeque; use std::io::Read; -use readline_rs::readline::*; +use readline_rs_compat::readline::*; type SubtermDeque = VecDeque<(usize, usize)>; @@ -27,7 +27,6 @@ impl<'a> TermRef<'a> { } pub enum Input { - Quit, Clear, Batch, TermString(&'static str) @@ -52,7 +51,7 @@ pub fn set_line_mode(mode: LineMode) { fn is_directive(buf: &str) -> bool { match buf { - "[user]" | "quit" | "clear" => true, + "?- [user]." | "?- [clear]." => true, _ => false } } @@ -77,9 +76,6 @@ unsafe extern "C" fn bind_end_key(_: i32, _: i32) -> i32 { unsafe extern "C" fn bind_cr(_: i32, _: i32) -> i32 { if END_OF_LINE { - println!(""); - rl_done = 1; - } else { if let Some(buf) = rl_line_buffer_as_str() { if is_directive(buf) { println!(""); @@ -88,6 +84,9 @@ unsafe extern "C" fn bind_cr(_: i32, _: i32) -> i32 { } } + println!(""); + rl_done = 1; + } else { insert_text_rl("\n"); } @@ -107,20 +106,46 @@ pub fn readline_initialize() { bind_keyseq_rl("\\C-d", bind_end_chord); } -pub fn read_line(prompt: &str) -> Result<&'static str, SessionError> { +pub fn read_batch(prompt: &str) -> Result<&'static str, SessionError> { + unsafe { + use std::ptr::null; + use std::mem; + + // deactivate the startup hook that emits a "?- " to the + // beginning of the readline buffer. + let p: *const i8 = null(); + rl_startup_hook = mem::transmute(p); + } + + match readline_rl(prompt) { + Some(input) => Ok(input), + None => Err(SessionError::UserPrompt) + } +} + +fn read_line(prompt: &str) -> Result<&'static str, SessionError> { match readline_rl(prompt) { Some(input) => Ok(input), None => Err(SessionError::UserPrompt) } } -pub fn toplevel_read_line() -> Result { - let buffer = read_line("prolog> ")?; +unsafe extern "C" fn insert_query_prompt() -> i32 { + insert_text_rl("?- "); + 0 +} +pub fn toplevel_read_line() -> Result +{ + unsafe { + rl_startup_hook = insert_query_prompt; + } + + let buffer = read_line("")?; + Ok(match &*buffer.trim() { - "quit" => Input::Quit, - "clear" => Input::Clear, - "[user]" => { + "?- [clear]." => Input::Clear, + "?- [user]." => { println!("(type Enter + Ctrl-D to terminate the stream when finished)"); Input::Batch }, -- 2.54.0