]> Repositorios git - scryer-prolog.git/commitdiff
migrate to rustyline, add history support
authorMark Thom <[email protected]>
Thu, 26 Sep 2019 17:25:05 +0000 (11:25 -0600)
committerMark Thom <[email protected]>
Thu, 26 Sep 2019 17:25:05 +0000 (11:25 -0600)
Cargo.toml
src/main.rs
src/prolog/clause_types.rs
src/prolog/machine/mod.rs
src/prolog/machine/system_calls.rs
src/prolog/mod.rs
src/prolog/read.rs
src/prolog/toplevel.pl

index ec8c2b85fec40849166aa58980ea5959404e431c..93ab38523fb1c26455a0521c0ff3b190de0f14ff 100644 (file)
@@ -1,14 +1,11 @@
 [package]
 name = "scryer-prolog"
-version = "0.8.93"
+version = "0.8.94"
 authors = ["Mark Thom <[email protected]>"]
 repository = "https://github.com/mthom/scryer-prolog"
 description = "A modern Prolog implementation written mostly in Rust."
 license = "BSD-3-Clause"
 
-[features]
-default = ["readline_rs_compat"]
-
 [dependencies]
 cfg-if = "0.1.7"
 dirs = "2.0.2"
@@ -16,9 +13,9 @@ downcast = "0.10.0"
 indexmap = "1.0.2"
 ordered-float = "0.5.0"
 prolog_parser = "0.8.29"
-readline_rs_compat = { version = "0.1.9", optional = true }
 ref_thread_local = "0.0.0"
 rug = "1.4.0"
+rustyline = "5.0.3"
 
 [dependencies.termion]
 version = "1.4.0"
index 948c0abcba623ab7a82eda196449e24f1dc41148..61ed623b15d22d1875d772a8f1b96b3ed2157e1d 100644 (file)
@@ -25,8 +25,8 @@ use prolog::read::*;
 mod tests;
 
 fn main() {
-    #[cfg(feature = "readline_rs_compat")]
-    readline::readline_initialize();
+//    #[cfg(feature = "readline_rs_compat")]
+//    readline::readline_initialize();
 
     let mut wam = Machine::new(readline::input_stream());
     wam.run_toplevel();
index 07d3d589d1464d5569cff348f30af54870a8a67c..3d0d1aef48ac9b103c2b3b1937d1d1f38c3c8899 100644 (file)
@@ -201,6 +201,7 @@ pub enum SystemClauseType {
     NumberToCodes,
     OpDeclaration,
     REPL(REPLCodePtr),
+    ReadQueryTerm,
     ReadTerm,
     RedoAttrVarBindings,
     RemoveCallPolicyCheck,
@@ -322,6 +323,7 @@ impl SystemClauseType {
             &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
             &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
             &SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
+            &SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
             &SystemClauseType::ReadTerm => clause_name!("$read_term"),
             &SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
             &SystemClauseType::RetractClause => clause_name!("$retract_clause"),
@@ -416,6 +418,7 @@ impl SystemClauseType {
             ("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
             ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
             ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
+            ("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
             ("$read_term", 2) => Some(SystemClauseType::ReadTerm),
             ("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
             ("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
index b9e90cc761297d667a5639742454fa7dfb0cbaa7..73159f38d792abfc77f9e6821198bea0865d2726 100644 (file)
@@ -354,14 +354,9 @@ impl Machine {
     fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
         match code_ptr {
             REPLCodePtr::CompileBatch => {
-                #[cfg(feature = "readline_rs_compat")]
-                readline::set_line_mode(readline::LineMode::Multi);
-
                 let src = readline::input_stream();
-
-                #[cfg(feature = "readline_rs_compat")]
-                readline::set_line_mode(readline::LineMode::Single);
-
+                readline::set_prompt(false);
+                
                 match compile_user_module(self, src) {
                     EvalSession::Error(e) => self.throw_session_error(e, (clause_name!("repl"), 0)),
                     _ => {}
index 81a634dfc2b918ed428cab95dd378fa563ac3a3b..0ed454f68f3448dad76920fbaa3f4723883bfb21 100644 (file)
@@ -251,6 +251,63 @@ impl MachineState {
         Ok(())
     }
 
+    fn read_term(&mut self,
+                 current_input_stream: &mut PrologStream,
+                 indices: &mut IndexStore)
+                 -> CallResult
+    {
+        match self.read(
+            current_input_stream,
+            indices.atom_tbl.clone(),
+            &indices.op_dir,
+        ) {
+            Ok(term_write_result) => {
+                let a1 = self[temp_v!(1)].clone();
+                self.unify(Addr::HeapCell(term_write_result.heap_loc), a1);
+
+                if self.fail {
+                    return Ok(());
+                }
+
+                let mut list_of_var_eqs = vec![];
+
+                for (var, binding) in term_write_result.var_dict.into_iter().rev() {
+                    let var_atom = clause_name!(var.to_string(), indices.atom_tbl);
+                    let var_atom = Constant::Atom(var_atom, None);
+
+                    let h = self.heap.h;
+                    let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
+
+                    self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec));
+                    self.heap.push(HeapCellValue::Addr(Addr::Con(var_atom)));
+                    self.heap.push(HeapCellValue::Addr(binding));
+
+                    list_of_var_eqs.push(Addr::Str(h));
+                }
+
+                let a2 = self[temp_v!(2)].clone();
+                let list_offset =
+                    Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter()));
+
+                Ok(self.unify(list_offset, a2))
+            }
+            Err(err) => {
+                if let ParserError::UnexpectedEOF = err {
+                    std::process::exit(0);
+                }
+
+                // reset the input stream after an input failure.
+                *current_input_stream = readline::input_stream();
+
+                let h = self.heap.h;
+                let syntax_error = MachineError::syntax_error(h, err);
+                let stub = MachineError::functor_stub(clause_name!("read_term"), 2);
+
+                Err(self.error_form(syntax_error, stub))
+            }
+        }
+    }
+    
     #[inline]
     fn install_new_block(&mut self, r: RegType) -> usize {
         self.block = self.b;
@@ -1674,69 +1731,27 @@ impl MachineState {
             &SystemClauseType::InstallNewBlock => {
                 self.install_new_block(temp_v!(1));
             }
-            &SystemClauseType::ReadTerm => {
-                match self.read(
-                    current_input_stream,
-                    indices.atom_tbl.clone(),
-                    &indices.op_dir,
-                ) {
-                    Ok(term_write_result) => {
-                        let a1 = self[temp_v!(1)].clone();
-                        self.unify(Addr::HeapCell(term_write_result.heap_loc), a1);
-
-                        if self.fail {
-                            return Ok(());
-                        }
-
-                        let mut list_of_var_eqs = vec![];
-
-                        for (var, binding) in term_write_result.var_dict.into_iter().rev() {
-                            let var_atom = clause_name!(var.to_string(), indices.atom_tbl);
-                            let var_atom = Constant::Atom(var_atom, None);
-
-                            let h = self.heap.h;
-                            let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
-
-                            self.heap
-                                .push(HeapCellValue::NamedStr(2, clause_name!("="), spec));
-                            self.heap.push(HeapCellValue::Addr(Addr::Con(var_atom)));
-                            self.heap.push(HeapCellValue::Addr(binding));
-
-                            list_of_var_eqs.push(Addr::Str(h));
-                        }
-
-                        let a2 = self[temp_v!(2)].clone();
-                        let list_offset =
-                            Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter()));
+            &SystemClauseType::ReadQueryTerm => {
+                readline::set_prompt(true);
+                let result = self.read_term(current_input_stream, indices);
+                readline::set_prompt(false);
 
-                        self.unify(list_offset, a2);
-                    }
-                    Err(err) => {
-                        if let ParserError::UnexpectedEOF = err {
-                            std::process::exit(0);
-                        }
-
-                        // reset the input stream after an input failure.
-                        *current_input_stream = readline::input_stream();
-
-                        let h = self.heap.h;
-                        let syntax_error = MachineError::syntax_error(h, err);
-                        let stub = MachineError::functor_stub(clause_name!("read_term"), 2);
-
-                        return Err(self.error_form(syntax_error, stub));
-                    }
-                }
+                let _ = result?;
             }
+            &SystemClauseType::ReadTerm => {
+                readline::set_prompt(false);
+                self.read_term(current_input_stream, indices)?;
+            },
             &SystemClauseType::ResetBlock => {
                 let addr = self.deref(self[temp_v!(1)].clone());
                 self.reset_block(addr);
             }
-            &SystemClauseType::SetBall => self.set_ball(),
-            &SystemClauseType::SkipMaxList => {
+            &SystemClauseType::SetBall =>
+                self.set_ball(),
+            &SystemClauseType::SkipMaxList =>
                 if let Err(err) = self.skip_max_list() {
                     return Err(err);
-                }
-            }
+                },            
             &SystemClauseType::StoreGlobalVar => {
                 let key = self[temp_v!(1)].clone();
 
index c98c3f27b0650868f88115b4d72dad8f501aa0cd..3ec028e493d29e6ce661dbe411de4ba0fd074d6a 100644 (file)
@@ -2,6 +2,7 @@ extern crate dirs;
 extern crate ordered_float;
 extern crate prolog_parser;
 extern crate rug;
+extern crate rustyline;   
 
 #[macro_use]
 mod macros;
index ddebca49abdc5f3c8e161340e83a409c34834d5a..a56e957a2db8a0985dc6daf6fec4077648a4b517 100644 (file)
@@ -25,35 +25,60 @@ impl<'a> TermRef<'a> {
 
 pub type PrologStream = ParsingStream<Box<Read>>;
 
-#[cfg(feature = "readline_rs_compat")]
 pub mod readline {
     use prolog_parser::ast::*;
-    use readline_rs_compat::readline::*;
-    use std::io::{Error, Read};
+    use prolog::rustyline::error::ReadlineError;
+    use prolog::rustyline::{Cmd, Editor, KeyPress};
+    use std::io::Read;
 
-    #[derive(Clone, Copy)]
-    pub enum LineMode {
-        Single,
-        Multi,
+    static mut PROMPT: bool = false;
+
+    pub fn set_prompt(value: bool) {
+        unsafe {
+            PROMPT = value;
+        }
     }
 
+    #[inline]
+    fn get_prompt() -> &'static str {
+        unsafe {
+            if PROMPT { "?- " } else { "" }
+        }
+    }
+    
     pub struct ReadlineStream {
+        rl: Editor<()>,
         pending_input: String,
     }
 
     impl ReadlineStream {
-        #[inline]
-        fn new(pending_input: String) -> Self {
-            ReadlineStream { pending_input }
+        fn input_stream(pending_input: String) -> Self {
+            let mut rl = Editor::<()>::new();
+
+            rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));
+
+            ReadlineStream { rl, pending_input }
         }
 
-        fn call_readline(&mut self, prompt: &str, buf: &mut [u8]) -> std::io::Result<usize> {
-            match readline_rl(prompt) {
-                Some(text) => {
+        fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+            match self.rl.readline(get_prompt()) {
+                Ok(text) => {
                     self.pending_input += &text;
+
+                    unsafe {
+                        if PROMPT {
+                            self.rl.history_mut().add(&self.pending_input);
+                            PROMPT = false;
+                        }
+                    }
+
+                    self.pending_input += "\n";                    
                     Ok(self.write_to_buf(buf))
                 }
-                None => Err(Error::last_os_error()),
+                Err(ReadlineError::Eof) =>
+                    Ok(self.write_to_buf(buf)),                
+                Err(e) =>
+                    Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, e))
             }
         }
 
@@ -84,84 +109,16 @@ pub mod readline {
     impl Read for ReadlineStream {
         fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
             if self.pending_input.is_empty() {
-                self.call_readline("", buf)
+                self.call_readline(buf)
             } else {
                 Ok(self.write_to_buf(buf))
             }
         }
     }
 
-    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;
-        }
-    }
-
-    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_cr(_: i32, _: i32) -> i32 {
-        if let LineMode::Single = LINE_MODE {
-            insert_text_rl("\n");
-            println!("");
-            rl_done = 1;
-        } else {
-            insert_text_rl("\n");
-        }
-
-        0
-    }
-
-    pub fn readline_initialize() {
-        let rc = initialize_rl(); // initialize editline.
-
-        if rc != 0 {
-            panic!("initialize_rl() failed with return code {}", rc);
-        }
-
-        bind_key_rl('\t' as i32, rl_insert); // just insert tabs when typed.
-        bind_key_rl('\n' as i32, bind_cr);
-        bind_key_rl('\r' as i32, bind_cr);
-        bind_keyseq_rl("\\C-d", bind_end_chord);
-    }
-
-    #[inline]
-    pub fn input_stream() -> ::PrologStream {
-        let reader: Box<Read> = Box::new(ReadlineStream::new(String::from("")));
-        parsing_stream(reader)
-    }
-}
-
-#[cfg(not(feature = "readline_rs_compat"))]
-pub mod readline {
-    use prolog_parser::ast::*;
-    use std::io::{stdin, BufReader, Read, Stdin};
-
-    struct StdinWrapper {
-        buf: BufReader<Stdin>,
-    }
-
-    impl Read for StdinWrapper {
-        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
-            self.buf.read(buf)
-        }
-    }
-
     #[inline]
     pub fn input_stream() -> ::PrologStream {
-        let reader: Box<Read> = Box::new(StdinWrapper {
-            buf: BufReader::new(stdin()),
-        });
+        let reader: Box<Read> = Box::new(ReadlineStream::input_stream(String::from("")));
         parsing_stream(reader)
     }
 }
index 532291f9aa10b9cd0f885e3366699ce4cc1ab2c9..b49375205beede8b85a1262ca733ea03ede73994 100644 (file)
@@ -4,8 +4,7 @@
 '$repl' :- '$repl'.
 
 '$read_and_match' :-
-    write_term('?- ', [quoted(false)]),
-    read_term(Term, [variable_names(VarList)]),
+    '$read_query_term'(Term, VarList),
     '$instruction_match'(Term, VarList).
 
 '$instruction_match'([user], []) :-