"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"
[[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)",
]
"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"
[package]
name = "scryer-prolog"
-version = "0.8.3"
+version = "0.8.4"
repository = "https://github.com/mthom/scryer-prolog"
description = "A modern Prolog implementation written mostly in Rust."
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
```
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
#[macro_use] extern crate downcast;
#[macro_use] extern crate prolog_parser;
+
+extern crate readline_sys;
extern crate termion;
mod prolog;
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)
};
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,
}
fn main() {
+ readline_initialize();
prolog_repl();
}
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()?)
}
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();
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)>;
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 {
use prolog::machine::toplevel::*;
use std::collections::HashSet;
-use std::io::empty;
use std::mem::swap;
use std::ops::{Range, RangeFrom};
{
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) =>
{
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(..)
{
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) =>