Various REPL refactoring
This commit is contained in:
parent
d578aa0fc7
commit
d01d280452
@ -5,13 +5,7 @@ pub trait ProgrammingLanguageInterface {
|
|||||||
fn language_name(&self) -> String;
|
fn language_name(&self) -> String;
|
||||||
fn source_file_suffix(&self) -> String;
|
fn source_file_suffix(&self) -> String;
|
||||||
|
|
||||||
fn run_computation(&mut self, _request: ComputationRequest) -> ComputationResponse {
|
fn run_computation(&mut self, _request: ComputationRequest) -> ComputationResponse;
|
||||||
ComputationResponse {
|
|
||||||
main_output: Err(format!("Computation pipeline not implemented")),
|
|
||||||
global_output_stats: GlobalOutputStats::default(),
|
|
||||||
debug_responses: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_meta(&mut self, _request: LangMetaRequest) -> LangMetaResponse {
|
fn request_meta(&mut self, _request: LangMetaRequest) -> LangMetaResponse {
|
||||||
LangMetaResponse::Custom {
|
LangMetaResponse::Custom {
|
||||||
|
@ -48,7 +48,6 @@ fn get_directive_from_commands<'a>(
|
|||||||
|
|
||||||
fn global_help(repl: &mut Repl) -> InterpreterDirectiveOutput {
|
fn global_help(repl: &mut Repl) -> InterpreterDirectiveOutput {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
let sigil = repl.interpreter_directive_sigil;
|
|
||||||
|
|
||||||
writeln!(
|
writeln!(
|
||||||
buf,
|
buf,
|
||||||
@ -63,7 +62,7 @@ fn global_help(repl: &mut Repl) -> InterpreterDirectiveOutput {
|
|||||||
writeln!(
|
writeln!(
|
||||||
buf,
|
buf,
|
||||||
"{}{} - {}",
|
"{}{} - {}",
|
||||||
sigil,
|
repl.sigil,
|
||||||
directive.get_cmd(),
|
directive.get_cmd(),
|
||||||
directive.get_help()
|
directive.get_help()
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use colored::*;
|
||||||
|
|
||||||
use crate::language::{
|
use crate::language::{
|
||||||
ComputationRequest, LangMetaRequest, LangMetaResponse, ProgrammingLanguageInterface,
|
ComputationRequest, LangMetaRequest, LangMetaResponse, ProgrammingLanguageInterface,
|
||||||
@ -22,7 +23,10 @@ const OPTIONS_SAVE_FILE: &'static str = ".schala_repl";
|
|||||||
type InterpreterDirectiveOutput = Option<String>;
|
type InterpreterDirectiveOutput = Option<String>;
|
||||||
|
|
||||||
pub struct Repl {
|
pub struct Repl {
|
||||||
pub interpreter_directive_sigil: char,
|
/// If this is the first character typed by a user into the repl, the following
|
||||||
|
/// will be interpreted as a directive to the REPL rather than a command in the
|
||||||
|
/// running programming language.
|
||||||
|
sigil: char,
|
||||||
line_reader: ::linefeed::interface::Interface<::linefeed::terminal::DefaultTerminal>,
|
line_reader: ::linefeed::interface::Interface<::linefeed::terminal::DefaultTerminal>,
|
||||||
language_states: Vec<Box<dyn ProgrammingLanguageInterface>>,
|
language_states: Vec<Box<dyn ProgrammingLanguageInterface>>,
|
||||||
options: ReplOptions,
|
options: ReplOptions,
|
||||||
@ -38,10 +42,10 @@ impl Repl {
|
|||||||
pub fn new(initial_states: Vec<Box<dyn ProgrammingLanguageInterface>>) -> Repl {
|
pub fn new(initial_states: Vec<Box<dyn ProgrammingLanguageInterface>>) -> Repl {
|
||||||
use linefeed::Interface;
|
use linefeed::Interface;
|
||||||
let line_reader = Interface::new("schala-repl").unwrap();
|
let line_reader = Interface::new("schala-repl").unwrap();
|
||||||
let interpreter_directive_sigil = ':';
|
let sigil = ':';
|
||||||
|
|
||||||
Repl {
|
Repl {
|
||||||
interpreter_directive_sigil,
|
sigil,
|
||||||
line_reader,
|
line_reader,
|
||||||
language_states: initial_states,
|
language_states: initial_states,
|
||||||
options: ReplOptions::new(),
|
options: ReplOptions::new(),
|
||||||
@ -49,10 +53,9 @@ impl Repl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_repl(&mut self) {
|
pub fn run_repl(&mut self) {
|
||||||
println!("Schala MetaInterpreter version {}", crate::VERSION_STRING);
|
println!("Schala meta-interpeter version {}", crate::VERSION_STRING);
|
||||||
println!(
|
println!(
|
||||||
"Type {}help for help with the REPL",
|
"Type {} for help with the REPL", format!("{}help", self.sigil).bright_green().bold()
|
||||||
self.interpreter_directive_sigil
|
|
||||||
);
|
);
|
||||||
self.load_options();
|
self.load_options();
|
||||||
self.handle_repl_loop();
|
self.handle_repl_loop();
|
||||||
@ -68,13 +71,12 @@ impl Repl {
|
|||||||
Ok(options) => {
|
Ok(options) => {
|
||||||
self.options = options;
|
self.options = options;
|
||||||
}
|
}
|
||||||
Err(()) => (),
|
Err(e) => eprintln!("{}",e)
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_repl_loop(&mut self) {
|
fn handle_repl_loop(&mut self) {
|
||||||
use linefeed::ReadResult::*;
|
use linefeed::ReadResult::*;
|
||||||
let sigil = self.interpreter_directive_sigil;
|
|
||||||
|
|
||||||
'main: loop {
|
'main: loop {
|
||||||
macro_rules! match_or_break {
|
macro_rules! match_or_break {
|
||||||
@ -96,7 +98,7 @@ impl Repl {
|
|||||||
self.line_reader.add_history_unique(input.to_string());
|
self.line_reader.add_history_unique(input.to_string());
|
||||||
let mut chars = input.chars().peekable();
|
let mut chars = input.chars().peekable();
|
||||||
let repl_responses = match chars.nth(0) {
|
let repl_responses = match chars.nth(0) {
|
||||||
Some(ch) if ch == sigil => {
|
Some(ch) if ch == self.sigil => {
|
||||||
if chars.peek() == Some(&'{') {
|
if chars.peek() == Some(&'{') {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
buf.push_str(input.get(2..).unwrap());
|
buf.push_str(input.get(2..).unwrap());
|
||||||
@ -113,8 +115,8 @@ impl Repl {
|
|||||||
}
|
}
|
||||||
self.handle_input(&buf)
|
self.handle_input(&buf)
|
||||||
} else {
|
} else {
|
||||||
match self.handle_interpreter_directive(input) {
|
match self.handle_interpreter_directive(input.get(1..).unwrap()) {
|
||||||
Some(directive_output) => println!("<> {}", directive_output),
|
Some(directive_output) => println!("{}", directive_output),
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -131,7 +133,7 @@ impl Repl {
|
|||||||
|
|
||||||
fn update_line_reader(&mut self) {
|
fn update_line_reader(&mut self) {
|
||||||
let tab_complete_handler =
|
let tab_complete_handler =
|
||||||
TabCompleteHandler::new(self.interpreter_directive_sigil, self.get_directives());
|
TabCompleteHandler::new(self.sigil, self.get_directives());
|
||||||
self.line_reader
|
self.line_reader
|
||||||
.set_completer(Arc::new(tab_complete_handler)); //TODO fix this here
|
.set_completer(Arc::new(tab_complete_handler)); //TODO fix this here
|
||||||
self.set_prompt(PromptStyle::Normal);
|
self.set_prompt(PromptStyle::Normal);
|
||||||
@ -139,8 +141,8 @@ impl Repl {
|
|||||||
|
|
||||||
fn set_prompt(&mut self, prompt_style: PromptStyle) {
|
fn set_prompt(&mut self, prompt_style: PromptStyle) {
|
||||||
let prompt_str = match prompt_style {
|
let prompt_str = match prompt_style {
|
||||||
PromptStyle::Normal => ">> ".to_string(),
|
PromptStyle::Normal => ">> ",
|
||||||
PromptStyle::Multiline => ">| ".to_string(),
|
PromptStyle::Multiline => ">| ",
|
||||||
};
|
};
|
||||||
|
|
||||||
self.line_reader.set_prompt(&prompt_str).unwrap();
|
self.line_reader.set_prompt(&prompt_str).unwrap();
|
||||||
@ -154,9 +156,7 @@ impl Repl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_interpreter_directive(&mut self, input: &str) -> InterpreterDirectiveOutput {
|
fn handle_interpreter_directive(&mut self, input: &str) -> InterpreterDirectiveOutput {
|
||||||
let mut iter = input.chars();
|
let arguments: Vec<&str> = input.split_whitespace().collect();
|
||||||
iter.next();
|
|
||||||
let arguments: Vec<&str> = iter.as_str().split_whitespace().collect();
|
|
||||||
|
|
||||||
if arguments.len() < 1 {
|
if arguments.len() < 1 {
|
||||||
return None;
|
return None;
|
||||||
|
@ -2,7 +2,7 @@ use crate::language::DebugAsk;
|
|||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ReplOptions {
|
pub struct ReplOptions {
|
||||||
@ -26,11 +26,11 @@ impl ReplOptions {
|
|||||||
file.write_all(buf.as_bytes())
|
file.write_all(buf.as_bytes())
|
||||||
});
|
});
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
println!("Error saving {} file {}", filename, err);
|
eprintln!("Error saving {} file {}", filename, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_from_file(filename: &str) -> Result<ReplOptions, ()> {
|
pub fn load_from_file(filename: &str) -> Result<ReplOptions, io::Error> {
|
||||||
File::open(filename)
|
File::open(filename)
|
||||||
.and_then(|mut file| {
|
.and_then(|mut file| {
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
@ -41,6 +41,5 @@ impl ReplOptions {
|
|||||||
let output: ReplOptions = crate::serde_json::from_str(&contents)?;
|
let output: ReplOptions = crate::serde_json::from_str(&contents)?;
|
||||||
Ok(output)
|
Ok(output)
|
||||||
})
|
})
|
||||||
.map_err(|_| ())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user