diff --git a/schala-repl/src/repl/command_tree.rs b/schala-repl/src/repl/command_tree.rs index 99aa0b6..ae8fa21 100644 --- a/schala-repl/src/repl/command_tree.rs +++ b/schala-repl/src/repl/command_tree.rs @@ -1,11 +1,11 @@ -use super::Repl; +use super::{Repl, InterpreterDirectiveOutput}; use colored::*; pub type BoxedCommandFunction = Box<(fn(&mut Repl, &[&str]) -> Option)>; /// A CommandTree is either a `Terminal` or a `NonTerminal`. When command parsing reaches the first -/// Terminal, it will use the `ReplAction` found there to find an appropriate function to execute, +/// Terminal, it will use the `DirectiveAction` found there to find an appropriate function to execute, /// and then execute it with any remaining arguments //TODO remove function: BoxedCommandFunction #[derive(Clone)] @@ -15,41 +15,49 @@ pub enum CommandTree { children: Vec, help_msg: Option, function: BoxedCommandFunction, - action: ReplAction, + action: DirectiveAction, }, NonTerminal { name: String, children: Vec, help_msg: Option, - action: ReplAction, + action: DirectiveAction, }, //TODO get rid of Top Top(Vec), } #[derive(Debug, Clone)] -pub enum ReplAction { +pub enum DirectiveAction { Null, Help, QuitProgram } -impl ReplAction { - fn get_function(&self) -> impl Fn(&mut Repl, &[&str]) -> Option { - |_: &mut Repl, _: &[&str]| { None } +impl DirectiveAction { + fn perform(&self, repl: &mut Repl, arguments: &[&str]) -> InterpreterDirectiveOutput { + use DirectiveAction::*; + match self { + Null => None, + Help => Some(repl.print_help_message(arguments)), + QuitProgram => { + repl.save_before_exit(); + ::std::process::exit(0) + } + } } } impl CommandTree { pub fn nonterm_no_further_tab_completions(s: &str, help: Option<&str>) -> CommandTree { - CommandTree::NonTerminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), children: vec![], action: ReplAction::Null } + CommandTree::NonTerminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), children: vec![], action: DirectiveAction::Null } } pub fn terminal(s: &str, help: Option<&str>, children: Vec, function: BoxedCommandFunction) -> CommandTree { - CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), function, children, action: ReplAction::Null } + CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), function, children, action: DirectiveAction::Null } } - pub fn terminal_act(s: &str, help: Option<&str>, children: Vec, action: ReplAction) -> CommandTree { + pub fn terminal_act(s: &str, help: Option<&str>, children: Vec, action: DirectiveAction) -> CommandTree { CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), function: Box::new(|_,_| { None }), children, action} } @@ -58,7 +66,7 @@ impl CommandTree { name: s.to_string(), help_msg: help.map(|x| x.to_string()), children, - action: ReplAction::Null + action: DirectiveAction::Null } } @@ -85,11 +93,11 @@ impl CommandTree { } } - pub fn execute(&self, repl: &mut Repl, arguments: &Vec<&str>) -> Option { + pub fn perform(&self, repl: &mut Repl, arguments: &Vec<&str>) -> InterpreterDirectiveOutput { let mut dir_pointer: &CommandTree = self; let mut idx = 0; - let res: Result<(ReplAction, usize), String> = loop { + let res: Result<(DirectiveAction, usize), String> = loop { match dir_pointer { CommandTree::Top(subcommands) | CommandTree::NonTerminal { children: subcommands, .. } => { let next_command = match arguments.get(idx) { @@ -111,10 +119,7 @@ impl CommandTree { }; match res { - Ok((action, idx)) => { - let f = action.get_function(); - f(repl, &arguments[idx..]) - }, + Ok((action, idx)) => action.perform(repl, &arguments[idx..]), Err(err) => Some(err.red().to_string()) } } diff --git a/schala-repl/src/repl/directives.rs b/schala-repl/src/repl/directives.rs index 191b252..d9101b7 100644 --- a/schala-repl/src/repl/directives.rs +++ b/schala-repl/src/repl/directives.rs @@ -2,26 +2,19 @@ use std::fmt::Write as FmtWrite; use itertools::Itertools; use crate::repl::Repl; -use crate::repl::command_tree::CommandTree; +use crate::repl::command_tree::{CommandTree, DirectiveAction}; use crate::language::{LangMetaRequest, LangMetaResponse, DebugAsk, DebugResponse}; + pub fn directives_from_pass_names(pass_names: &Vec) -> CommandTree { let passes_directives: Vec = pass_names.iter() .map(|pass_name| { CommandTree::nonterm_no_further_tab_completions(pass_name, None) }) .collect(); CommandTree::Top(vec![ - CommandTree::terminal("exit", Some("exit the REPL"), vec![], Box::new(|repl: &mut Repl, _cmds: &[&str]| { - repl.save_before_exit(); - ::std::process::exit(0) - })), - CommandTree::terminal("quit", Some("exit the REPL"), vec![], Box::new(|repl: &mut Repl, _cmds: &[&str]| { - repl.save_before_exit(); - ::std::process::exit(0) - })), - CommandTree::terminal("help", Some("Print this help message"), vec![], Box::new(|repl: &mut Repl, cmds: &[&str]| { - Some(repl.print_help_message(cmds)) - })), + CommandTree::terminal_act("exit", Some("exit the REPL"), vec![], DirectiveAction::QuitProgram), + CommandTree::terminal_act("quit", Some("exit the REPL"), vec![], DirectiveAction::QuitProgram), + CommandTree::terminal_act("help", Some("Print this help message"), vec![], DirectiveAction::Help), CommandTree::nonterm("debug", Some("Configure debug information"), vec![ diff --git a/schala-repl/src/repl/mod.rs b/schala-repl/src/repl/mod.rs index 08c13a0..d1fb4ae 100644 --- a/schala-repl/src/repl/mod.rs +++ b/schala-repl/src/repl/mod.rs @@ -17,6 +17,8 @@ use directives::directives_from_pass_names; const HISTORY_SAVE_FILE: &'static str = ".schala_history"; const OPTIONS_SAVE_FILE: &'static str = ".schala_repl"; +type InterpreterDirectiveOutput = Option; + pub struct Repl { interpreter_directive_sigil: char, line_reader: ::linefeed::interface::Interface<::linefeed::terminal::DefaultTerminal>, @@ -101,33 +103,7 @@ impl Repl { self.options.save_to_file(OPTIONS_SAVE_FILE); } - fn get_function_from_directives<'a>(directives: &'a CommandTree, commands: &Vec<&str>) -> Result<(&'a BoxedCommandFunction, usize), String> { - let mut dir_pointer: &CommandTree = &directives; - let mut idx = 0; - - loop { - match dir_pointer { - CommandTree::Top(subcommands) | CommandTree::NonTerminal { children: subcommands, .. } => { - let next_command = match commands.get(idx) { - Some(cmd) => cmd, - None => break Err(format!("Command requires arguments")) - }; - idx += 1; - match subcommands.iter().find(|sc| sc.get_cmd() == *next_command) { - Some(command_tree) => { - dir_pointer = command_tree; - }, - None => break Err(format!("Command {} not found", next_command)) - }; - }, - CommandTree::Terminal { function, .. } => { - break Ok((function, idx)); - }, - } - } - } - - fn handle_interpreter_directive(&mut self, input: &str) -> Option { + fn handle_interpreter_directive(&mut self, input: &str) -> InterpreterDirectiveOutput { let mut iter = input.chars(); iter.next(); let arguments: Vec<&str> = iter @@ -140,15 +116,7 @@ impl Repl { } let directives = self.get_directives(); - directives.execute(self, &arguments) - - /* - let result: Result<(&BoxedCommandFunction, _), String> = Repl::get_function_from_directives(&directives, &commands); - match result { - Ok((f, idx)) => f(self, &commands[idx..]), - Err(err) => Some(err.red().to_string()) - } - */ + directives.perform(self, &arguments) } fn print_help_message(&mut self, commands_passed_to_help: &[&str] ) -> String {