]> Repositorios git - scryer-prolog.git/commitdiff
use the readline library at toplevel
authorMark Thom <[email protected]>
Sun, 17 Mar 2019 01:12:06 +0000 (19:12 -0600)
committerMark Thom <[email protected]>
Sun, 17 Mar 2019 01:12:06 +0000 (19:12 -0600)
Cargo.lock
Cargo.toml
README.md
src/main.rs
src/prolog/machine/term_expansion.rs
src/prolog/machine/toplevel.rs
src/prolog/read.rs
src/tests.rs

index 6e7aa3a5b8d980d6d1e2f01defc900809bab3ed2..a24efcdd7ebad5763efa670122493c38bd1f9439 100644 (file)
@@ -96,6 +96,11 @@ dependencies = [
  "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "readline-sys"
+version = "0.1.0"
+source = "git+https://github.com/mthom/readline-sys#e529b03ae3c723fc45b06784b1c67aa0b4c322ae"
+
 [[package]]
 name = "redox_syscall"
 version = "0.1.51"
@@ -111,12 +116,13 @@ dependencies = [
 
 [[package]]
 name = "scryer-prolog"
-version = "0.8.3"
+version = "0.8.4"
 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-sys 0.1.0 (git+https://github.com/mthom/readline-sys)",
  "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -156,6 +162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "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-sys 0.1.0 (git+https://github.com/mthom/readline-sys)" = "<none>"
 "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"
index 98d36db4c4a7b7796d8dbecb34ac80c97f6f25f7..558ebefb524b99d61c37bf564a93a43f5db57b56 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "scryer-prolog"
-version = "0.8.3"
+version = "0.8.4"
 authors = ["Mark Thom <[email protected]>"]
 repository = "https://github.com/mthom/scryer-prolog"
 description = "A modern Prolog implementation written mostly in Rust."
@@ -11,6 +11,10 @@ downcast = "0.9.1"
 num = "0.2"
 ordered-float = "0.5.0"
 prolog_parser = "0.8.1"
+readline-sys = "0.1.0"
+
+[patch.crates-io]
+readline-sys = { git = 'https://github.com/mthom/readline-sys' }
 
 [dependencies.termion]
 version = "1.4.0"
\ No newline at end of file
index 4e8627fdd1c1bf951d1cd1b7fdc1615c56972249..007b7edf8513d15ce3ba9f7c4ce067e75017e609 100644 (file)
--- a/README.md
+++ b/README.md
@@ -101,8 +101,11 @@ $> cargo install scryer-prolog
 ```
 
 cargo will download and install the libraries Scryer Prolog uses
-automatically. You can find the `scryer-prolog` executable in
-`~/.cargo/bin`.
+automatically, save for the C library readline. It will search the
+system library paths for readline without taking further steps to
+install it if it is not found.
+
+You can find the `scryer-prolog` executable in `~/.cargo/bin`.
 
 Note on compatibility: Scryer Prolog should work on Linux, Mac OS X, and
 FreeBSD. Windows support hinges on the Termion library working in
index bfbda33f79d258c5162d2b5dfaf4a8efd5ae0097..d04dbc69e3caf9801bac6a4ceef0915d116e37d1 100644 (file)
@@ -1,5 +1,7 @@
 #[macro_use] extern crate downcast;
 #[macro_use] extern crate prolog_parser;
+
+extern crate readline_sys;
 extern crate termion;
 
 mod prolog;
@@ -11,22 +13,18 @@ use prolog::machine::toplevel::string_to_toplevel;
 use prolog::read::*;
 use prolog::write::*;
 
-use std::io::{Write, stdin, stdout};
-
 #[cfg(test)]
 mod tests;
 
 fn prolog_repl() {
     let mut wam = Machine::new();
-    
+
     loop {
-        print!("prolog> ");
-        stdout().flush().unwrap();
-        
+        set_line_mode(LineMode::Single);
+
         match toplevel_read_line() {
             Ok(Input::TermString(buffer)) => {
-                let stdin  = stdin();
-                let result = match string_to_toplevel(stdin.lock(), buffer, &mut wam) {
+                let result = match string_to_toplevel(buffer, &mut wam) {
                     Ok(packet) => compile_term(&mut wam, packet),
                     Err(e) => EvalSession::from(e)
                 };
@@ -34,9 +32,17 @@ fn prolog_repl() {
                 print(&mut wam, result)
             },
             Ok(Input::Batch) => {
-                let stdin  = stdin();
-                let result = compile_user_module(&mut wam, stdin.lock());
+                set_line_mode(LineMode::Multi);
+
+                let src = match read_line("") {
+                    Ok(src) => src,
+                    Err(e) => {
+                        println!("{}", e);
+                        continue;
+                    }
+                };
                 
+                let result = compile_user_module(&mut wam, src.as_bytes());
                 print(&mut wam, result);
             },
             Ok(Input::Quit) => break,
@@ -52,5 +58,6 @@ fn prolog_repl() {
 }
 
 fn main() {
+    readline_initialize();
     prolog_repl();
 }
index a7b8b8c87c538b80a5d1d65b4f98334cd8399a4e..d94569fb8d6479c40c526458b8cadb2622c354e3 100644 (file)
@@ -149,11 +149,6 @@ impl<'a, R: Read> TermStream<'a, R> {
         self.parser.set_atom_tbl(atom_tbl);
     }
 
-    #[inline]
-    pub fn add_to_top(&mut self, buf: &str) {
-        self.parser.add_to_top(buf);
-    }
-
     #[inline]
     pub fn eof(&mut self) -> Result<bool, ParserError> {
         Ok(self.stack.is_empty() && self.parser.eof()?)
index 1be84c37709ecac6adfe55ad38be02f2005bae83..c3656eba2b3f82755c7ed05fc8f73c419ccb9be9 100644 (file)
@@ -761,15 +761,12 @@ fn term_to_toplevel<'a, R>(term_stream: &mut TermStream<'a, R>, code_dir: &mut C
 }
 
 pub
-fn string_to_toplevel<R: Read>(src: R, buffer: String, wam: &mut Machine)
-                               -> Result<TopLevelPacket, SessionError>
+fn string_to_toplevel(buffer: String, wam: &mut Machine) -> Result<TopLevelPacket, SessionError>
 {
-    let mut term_stream = TermStream::new(src, wam.indices.atom_tbl(),
+    let mut term_stream = TermStream::new(buffer.as_bytes(), wam.indices.atom_tbl(),
                                           wam.machine_flags(), &mut wam.indices,
                                           &mut wam.policies, &mut wam.code_repo);
 
-    term_stream.add_to_top(buffer.as_str());
-
     let term = term_stream.read_term(&OpDir::new())?;
     let mut code_dir = CodeDir::new();
 
index 0c94bc5fcf13ef896977bee19d558c62af5a1e10..309e0f7d50aae0be18b7e6348eba1ebdc5a97863 100644 (file)
@@ -4,11 +4,14 @@ use prolog_parser::tabled_rc::TabledData;
 
 use prolog::forms::*;
 use prolog::iterators::*;
+use prolog::machine::machine_errors::*;
 use prolog::machine::machine_indices::*;
 use prolog::machine::machine_state::MachineState;
 
 use std::collections::VecDeque;
-use std::io::{Read, stdin};
+use std::io::Read;
+
+use readline_sys::readline::*;
 
 type SubtermDeque = VecDeque<(usize, usize)>;
 
@@ -30,21 +33,99 @@ pub enum Input {
     TermString(String)
 }
 
-pub fn toplevel_read_line() -> Result<Input, ParserError> {
-    let mut buffer = String::new();
+#[derive(Clone, Copy)]
+pub enum LineMode {
+    Single,
+    Multi
+}
+
+static mut LINE_MODE: LineMode = LineMode::Single;
+static mut END_OF_LINE: bool = false;
+
+pub fn set_line_mode(mode: LineMode) {
+    unsafe {
+        LINE_MODE = mode;
+        END_OF_LINE = false;
+        rl_done = 0;
+    }
+}
+
+fn is_directive(buf: &String) -> bool {
+    match buf.as_str() {
+        "[user]" | "quit" | "clear" => true,
+        _ => false
+    }
+}
+
+unsafe extern "C" fn bind_end_chord(_: i32, _: i32) -> i32 {
+    if let LineMode::Multi = LINE_MODE {
+        rl_done = 1;
+    }
+
+    0
+}
+
+unsafe extern "C" fn bind_end_key(_: i32, _: i32) -> i32 {
+    insert_text_rl(".");
+
+    if let LineMode::Single = LINE_MODE {
+        END_OF_LINE = true;
+    }
+
+    0
+}
+
+unsafe extern "C" fn bind_cr(_: i32, _: i32) -> i32 {    
+    if END_OF_LINE {
+        println!("");
+        rl_done = 1;
+    } else {
+        if let Some(ref buf) = rl_line_buffer_as_string() {
+            if is_directive(buf) {
+                println!("");
+                rl_done = 1;
+                return 0;
+            }
+        }
+        
+        insert_text_rl("\n");
+    }
+
+    0
+}
+
+pub fn readline_initialize() {
+    let rc = initialize_rl(); // initialize editline.
 
-    let stdin = stdin();
-    stdin.read_line(&mut buffer).unwrap();
+    if rc != 0 {
+        panic!("initialize_rl() failed with return code {}", rc);
+    }
+
+    bind_key_rl('.' as i32, bind_end_key);
+    bind_key_rl('\n' as i32, bind_cr);
+    bind_key_rl('\r' as i32, bind_cr);
+    bind_keyseq_rl("\\C-d", bind_end_chord);
+}
+
+pub fn read_line(prompt: &str) -> Result<String, SessionError> {
+    match readline_rl(prompt) {
+        Some(input) => Ok(input.to_string()),
+        None => Err(SessionError::UserPrompt)
+    }
+}
 
-    match &*buffer.trim() {
-        "quit"   => Ok(Input::Quit),
-        "clear"  => Ok(Input::Clear),
+pub fn toplevel_read_line() -> Result<Input, SessionError> {
+    let buffer = read_line("prolog> ")?;
+
+    Ok(match &*buffer.trim() {
+        "quit"   => Input::Quit,
+        "clear"  => Input::Clear,
         "[user]" => {
             println!("(type Enter + Ctrl-D to terminate the stream when finished)");
-            Ok(Input::Batch)
+            Input::Batch
         },
-        _ => Ok(Input::TermString(buffer))
-    }
+        _ => Input::TermString(buffer)
+    })
 }
 
 impl MachineState {
index dd27affb1620ec82fe146e53aba334e702afd6c3..71e19a80c5007d0d2670627646ab6debaa9872ce 100644 (file)
@@ -6,7 +6,6 @@ use prolog::machine::machine_indices::*;
 use prolog::machine::toplevel::*;
 
 use std::collections::HashSet;
-use std::io::empty;
 use std::mem::swap;
 use std::ops::{Range, RangeFrom};
 
@@ -148,7 +147,7 @@ pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>
 {
     wam.reset();
 
-    match string_to_toplevel(empty(), String::from(buffer), wam) {
+    match string_to_toplevel(String::from(buffer), wam) {
         Ok(term) =>
             match compile_term(wam, term) {
                 EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
@@ -165,7 +164,7 @@ pub fn submit_query_without_results(wam: &mut Machine, buffer: &str) -> bool
 {
     wam.reset();
 
-    match string_to_toplevel(empty(), String::from(buffer), wam) {
+    match string_to_toplevel(String::from(buffer), wam) {
         Ok(term) =>
             match compile_term(wam, term) {
                 EvalSession::InitialQuerySuccess(..)
@@ -183,7 +182,7 @@ pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
 {
     wam.reset();
 
-    match string_to_toplevel(empty(), String::from(buffer), wam) {
+    match string_to_toplevel(String::from(buffer), wam) {
         Ok(term) =>
             match compile_term(wam, term) {
                 EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>