use the readline library at toplevel
This commit is contained in:
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "scryer-prolog"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||
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"
|
||||
@@ -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
|
||||
|
||||
27
src/main.rs
27
src/main.rs
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()?)
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
let stdin = stdin();
|
||||
stdin.read_line(&mut buffer).unwrap();
|
||||
static mut LINE_MODE: LineMode = LineMode::Single;
|
||||
static mut END_OF_LINE: bool = false;
|
||||
|
||||
match &*buffer.trim() {
|
||||
"quit" => Ok(Input::Quit),
|
||||
"clear" => Ok(Input::Clear),
|
||||
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.
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
Reference in New Issue
Block a user