[package]
name = "scryer-prolog"
-version = "0.8.93"
+version = "0.8.94"
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"
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"
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();
NumberToCodes,
OpDeclaration,
REPL(REPLCodePtr),
+ ReadQueryTerm,
ReadTerm,
RedoAttrVarBindings,
RemoveCallPolicyCheck,
&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"),
("$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),
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)),
_ => {}
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;
&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();
extern crate ordered_float;
extern crate prolog_parser;
extern crate rug;
+extern crate rustyline;
#[macro_use]
mod macros;
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))
}
}
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)
}
}
'$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], []) :-