|
|
|
@ -17,16 +17,14 @@ mod directives; |
|
|
|
|
use directives::directives_from_pass_names; |
|
|
|
|
mod help; |
|
|
|
|
mod response; |
|
|
|
|
use response::ReplResponse; |
|
|
|
|
use std::{collections::HashSet, sync::Arc}; |
|
|
|
|
|
|
|
|
|
use colored::*; |
|
|
|
|
use std::collections::HashSet; |
|
|
|
|
use std::sync::Arc; |
|
|
|
|
|
|
|
|
|
pub use language::{ |
|
|
|
|
ComputationRequest, ComputationResponse, DebugAsk, DebugResponse, GlobalOutputStats, |
|
|
|
|
LangMetaRequest, LangMetaResponse, ProgrammingLanguageInterface, |
|
|
|
|
ComputationRequest, ComputationResponse, DebugAsk, DebugResponse, GlobalOutputStats, LangMetaRequest, |
|
|
|
|
LangMetaResponse, ProgrammingLanguageInterface, |
|
|
|
|
}; |
|
|
|
|
use response::ReplResponse; |
|
|
|
|
|
|
|
|
|
include!(concat!(env!("OUT_DIR"), "/static.rs")); |
|
|
|
|
const VERSION_STRING: &str = "0.1.0"; |
|
|
|
@ -58,20 +56,12 @@ impl<L: ProgrammingLanguageInterface> Repl<L> { |
|
|
|
|
let line_reader = Interface::new("schala-repl").unwrap(); |
|
|
|
|
let sigil = ':'; |
|
|
|
|
|
|
|
|
|
Repl { |
|
|
|
|
sigil, |
|
|
|
|
line_reader, |
|
|
|
|
language_state: initial_state, |
|
|
|
|
options: ReplOptions::new(), |
|
|
|
|
} |
|
|
|
|
Repl { sigil, line_reader, language_state: initial_state, options: ReplOptions::new() } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn run_repl(&mut self, config: L::Config) { |
|
|
|
|
println!("Schala meta-interpeter version {}", VERSION_STRING); |
|
|
|
|
println!( |
|
|
|
|
"Type {} for help with the REPL", |
|
|
|
|
format!("{}help", self.sigil).bright_green().bold() |
|
|
|
|
); |
|
|
|
|
println!("Type {} for help with the REPL", format!("{}help", self.sigil).bright_green().bold()); |
|
|
|
|
self.load_options(); |
|
|
|
|
self.handle_repl_loop(config); |
|
|
|
|
self.save_before_exit(); |
|
|
|
@ -79,9 +69,7 @@ impl<L: ProgrammingLanguageInterface> Repl<L> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn load_options(&mut self) { |
|
|
|
|
self.line_reader |
|
|
|
|
.load_history(HISTORY_SAVE_FILE) |
|
|
|
|
.unwrap_or(()); |
|
|
|
|
self.line_reader.load_history(HISTORY_SAVE_FILE).unwrap_or(()); |
|
|
|
|
match ReplOptions::load_from_file(OPTIONS_SAVE_FILE) { |
|
|
|
|
Ok(options) => { |
|
|
|
|
self.options = options; |
|
|
|
@ -113,7 +101,7 @@ impl<L: ProgrammingLanguageInterface> Repl<L> { |
|
|
|
|
self.line_reader.add_history_unique(input.to_string()); |
|
|
|
|
let mut chars = input.chars().peekable(); |
|
|
|
|
let repl_responses = match chars.next() { |
|
|
|
|
Some(ch) if ch == self.sigil => { |
|
|
|
|
Some(ch) if ch == self.sigil => |
|
|
|
|
if chars.peek() == Some(&'{') { |
|
|
|
|
let mut buf = String::new(); |
|
|
|
|
buf.push_str(input.get(2..).unwrap()); |
|
|
|
@ -130,12 +118,11 @@ impl<L: ProgrammingLanguageInterface> Repl<L> { |
|
|
|
|
} |
|
|
|
|
self.handle_input(&buf, &config) |
|
|
|
|
} else { |
|
|
|
|
if let Some(output) = self.handle_interpreter_directive(input.get(1..).unwrap()) { |
|
|
|
|
println!("{}", output); |
|
|
|
|
if let Some(output) = self.handle_interpreter_directive(input.get(1..).unwrap()) { |
|
|
|
|
println!("{}", output); |
|
|
|
|
} |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
_ => self.handle_input(input, &config), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -147,8 +134,7 @@ impl<L: ProgrammingLanguageInterface> Repl<L> { |
|
|
|
|
|
|
|
|
|
fn update_line_reader(&mut self) { |
|
|
|
|
let tab_complete_handler = TabCompleteHandler::new(self.sigil, self.get_directives()); |
|
|
|
|
self.line_reader |
|
|
|
|
.set_completer(Arc::new(tab_complete_handler)); //TODO fix this here
|
|
|
|
|
self.line_reader.set_completer(Arc::new(tab_complete_handler)); //TODO fix this here
|
|
|
|
|
self.set_prompt(PromptStyle::Normal); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -162,9 +148,7 @@ impl<L: ProgrammingLanguageInterface> Repl<L> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn save_before_exit(&self) { |
|
|
|
|
self.line_reader |
|
|
|
|
.save_history(HISTORY_SAVE_FILE) |
|
|
|
|
.unwrap_or(()); |
|
|
|
|
self.line_reader.save_history(HISTORY_SAVE_FILE).unwrap_or(()); |
|
|
|
|
self.options.save_to_file(OPTIONS_SAVE_FILE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -185,20 +169,13 @@ impl<L: ProgrammingLanguageInterface> Repl<L> { |
|
|
|
|
debug_requests.insert(ask.clone()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let request = ComputationRequest { |
|
|
|
|
source: input, |
|
|
|
|
config: config.clone(), |
|
|
|
|
debug_requests, |
|
|
|
|
}; |
|
|
|
|
let request = ComputationRequest { source: input, config: config.clone(), debug_requests }; |
|
|
|
|
let response = self.language_state.run_computation(request); |
|
|
|
|
response::handle_computation_response(response, &self.options) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn get_directives(&mut self) -> CommandTree { |
|
|
|
|
let pass_names = match self |
|
|
|
|
.language_state |
|
|
|
|
.request_meta(LangMetaRequest::StageNames) |
|
|
|
|
{ |
|
|
|
|
let pass_names = match self.language_state.request_meta(LangMetaRequest::StageNames) { |
|
|
|
|
LangMetaResponse::StageNames(names) => names, |
|
|
|
|
_ => vec![], |
|
|
|
|
}; |
|
|
|
@ -212,15 +189,14 @@ struct TabCompleteHandler { |
|
|
|
|
top_level_commands: CommandTree, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
use linefeed::complete::{Completer, Completion}; |
|
|
|
|
use linefeed::terminal::Terminal; |
|
|
|
|
use linefeed::{ |
|
|
|
|
complete::{Completer, Completion}, |
|
|
|
|
terminal::Terminal, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
impl TabCompleteHandler { |
|
|
|
|
fn new(sigil: char, top_level_commands: CommandTree) -> TabCompleteHandler { |
|
|
|
|
TabCompleteHandler { |
|
|
|
|
top_level_commands, |
|
|
|
|
sigil, |
|
|
|
|
} |
|
|
|
|
TabCompleteHandler { top_level_commands, sigil } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -247,11 +223,7 @@ impl<T: Terminal> Completer<T> for TabCompleteHandler { |
|
|
|
|
None => { |
|
|
|
|
let top = matches!(command_tree, Some(CommandTree::Top(_))); |
|
|
|
|
let word = if top { word.get(1..).unwrap() } else { word }; |
|
|
|
|
for cmd in command_tree |
|
|
|
|
.map(|x| x.get_subcommands()) |
|
|
|
|
.unwrap_or_default() |
|
|
|
|
.into_iter() |
|
|
|
|
{ |
|
|
|
|
for cmd in command_tree.map(|x| x.get_subcommands()).unwrap_or_default().into_iter() { |
|
|
|
|
if cmd.starts_with(word) { |
|
|
|
|
completions.push(Completion { |
|
|
|
|
completion: format!("{}{}", if top { ":" } else { "" }, cmd), |
|
|
|
@ -265,12 +237,9 @@ impl<T: Terminal> Completer<T> for TabCompleteHandler { |
|
|
|
|
Some(s) => { |
|
|
|
|
let new_ptr: Option<&CommandTree> = command_tree.and_then(|cm| match cm { |
|
|
|
|
CommandTree::Top(children) => children.iter().find(|c| c.get_cmd() == s), |
|
|
|
|
CommandTree::NonTerminal { children, .. } => { |
|
|
|
|
children.iter().find(|c| c.get_cmd() == s) |
|
|
|
|
} |
|
|
|
|
CommandTree::Terminal { children, .. } => { |
|
|
|
|
children.iter().find(|c| c.get_cmd() == s) |
|
|
|
|
} |
|
|
|
|
CommandTree::NonTerminal { children, .. } => |
|
|
|
|
children.iter().find(|c| c.get_cmd() == s), |
|
|
|
|
CommandTree::Terminal { children, .. } => children.iter().find(|c| c.get_cmd() == s), |
|
|
|
|
}); |
|
|
|
|
command_tree = new_ptr; |
|
|
|
|
} |
|
|
|
|