Start converting over directives to new format

This commit is contained in:
greg 2019-06-02 00:18:37 -07:00
parent e12ff6f30b
commit fd517351de
3 changed files with 32 additions and 66 deletions

View File

@ -1,11 +1,11 @@
use super::Repl; use super::{Repl, InterpreterDirectiveOutput};
use colored::*; use colored::*;
pub type BoxedCommandFunction = Box<(fn(&mut Repl, &[&str]) -> Option<String>)>; pub type BoxedCommandFunction = Box<(fn(&mut Repl, &[&str]) -> Option<String>)>;
/// A CommandTree is either a `Terminal` or a `NonTerminal`. When command parsing reaches the first /// 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 /// and then execute it with any remaining arguments
//TODO remove function: BoxedCommandFunction //TODO remove function: BoxedCommandFunction
#[derive(Clone)] #[derive(Clone)]
@ -15,41 +15,49 @@ pub enum CommandTree {
children: Vec<CommandTree>, children: Vec<CommandTree>,
help_msg: Option<String>, help_msg: Option<String>,
function: BoxedCommandFunction, function: BoxedCommandFunction,
action: ReplAction, action: DirectiveAction,
}, },
NonTerminal { NonTerminal {
name: String, name: String,
children: Vec<CommandTree>, children: Vec<CommandTree>,
help_msg: Option<String>, help_msg: Option<String>,
action: ReplAction, action: DirectiveAction,
}, },
//TODO get rid of Top //TODO get rid of Top
Top(Vec<CommandTree>), Top(Vec<CommandTree>),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ReplAction { pub enum DirectiveAction {
Null, Null,
Help, Help,
QuitProgram QuitProgram
} }
impl ReplAction { impl DirectiveAction {
fn get_function(&self) -> impl Fn(&mut Repl, &[&str]) -> Option<String> { fn perform(&self, repl: &mut Repl, arguments: &[&str]) -> InterpreterDirectiveOutput {
|_: &mut Repl, _: &[&str]| { None } use DirectiveAction::*;
match self {
Null => None,
Help => Some(repl.print_help_message(arguments)),
QuitProgram => {
repl.save_before_exit();
::std::process::exit(0)
}
}
} }
} }
impl CommandTree { impl CommandTree {
pub fn nonterm_no_further_tab_completions(s: &str, help: Option<&str>) -> 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<CommandTree>, function: BoxedCommandFunction) -> CommandTree { pub fn terminal(s: &str, help: Option<&str>, children: Vec<CommandTree>, 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<CommandTree>, action: ReplAction) -> CommandTree { pub fn terminal_act(s: &str, help: Option<&str>, children: Vec<CommandTree>, action: DirectiveAction) -> CommandTree {
CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), function: Box::new(|_,_| { None }), children, action} 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(), name: s.to_string(),
help_msg: help.map(|x| x.to_string()), help_msg: help.map(|x| x.to_string()),
children, children,
action: ReplAction::Null action: DirectiveAction::Null
} }
} }
@ -85,11 +93,11 @@ impl CommandTree {
} }
} }
pub fn execute(&self, repl: &mut Repl, arguments: &Vec<&str>) -> Option<String> { pub fn perform(&self, repl: &mut Repl, arguments: &Vec<&str>) -> InterpreterDirectiveOutput {
let mut dir_pointer: &CommandTree = self; let mut dir_pointer: &CommandTree = self;
let mut idx = 0; let mut idx = 0;
let res: Result<(ReplAction, usize), String> = loop { let res: Result<(DirectiveAction, usize), String> = loop {
match dir_pointer { match dir_pointer {
CommandTree::Top(subcommands) | CommandTree::NonTerminal { children: subcommands, .. } => { CommandTree::Top(subcommands) | CommandTree::NonTerminal { children: subcommands, .. } => {
let next_command = match arguments.get(idx) { let next_command = match arguments.get(idx) {
@ -111,10 +119,7 @@ impl CommandTree {
}; };
match res { match res {
Ok((action, idx)) => { Ok((action, idx)) => action.perform(repl, &arguments[idx..]),
let f = action.get_function();
f(repl, &arguments[idx..])
},
Err(err) => Some(err.red().to_string()) Err(err) => Some(err.red().to_string())
} }
} }

View File

@ -2,26 +2,19 @@ use std::fmt::Write as FmtWrite;
use itertools::Itertools; use itertools::Itertools;
use crate::repl::Repl; use crate::repl::Repl;
use crate::repl::command_tree::CommandTree; use crate::repl::command_tree::{CommandTree, DirectiveAction};
use crate::language::{LangMetaRequest, LangMetaResponse, DebugAsk, DebugResponse}; use crate::language::{LangMetaRequest, LangMetaResponse, DebugAsk, DebugResponse};
pub fn directives_from_pass_names(pass_names: &Vec<String>) -> CommandTree { pub fn directives_from_pass_names(pass_names: &Vec<String>) -> CommandTree {
let passes_directives: Vec<CommandTree> = pass_names.iter() let passes_directives: Vec<CommandTree> = pass_names.iter()
.map(|pass_name| { CommandTree::nonterm_no_further_tab_completions(pass_name, None) }) .map(|pass_name| { CommandTree::nonterm_no_further_tab_completions(pass_name, None) })
.collect(); .collect();
CommandTree::Top(vec![ CommandTree::Top(vec![
CommandTree::terminal("exit", Some("exit the REPL"), vec![], Box::new(|repl: &mut Repl, _cmds: &[&str]| { CommandTree::terminal_act("exit", Some("exit the REPL"), vec![], DirectiveAction::QuitProgram),
repl.save_before_exit(); CommandTree::terminal_act("quit", Some("exit the REPL"), vec![], DirectiveAction::QuitProgram),
::std::process::exit(0) CommandTree::terminal_act("help", Some("Print this help message"), vec![], DirectiveAction::Help),
})),
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::nonterm("debug", CommandTree::nonterm("debug",
Some("Configure debug information"), Some("Configure debug information"),
vec![ vec![

View File

@ -17,6 +17,8 @@ use directives::directives_from_pass_names;
const HISTORY_SAVE_FILE: &'static str = ".schala_history"; const HISTORY_SAVE_FILE: &'static str = ".schala_history";
const OPTIONS_SAVE_FILE: &'static str = ".schala_repl"; const OPTIONS_SAVE_FILE: &'static str = ".schala_repl";
type InterpreterDirectiveOutput = Option<String>;
pub struct Repl { pub struct Repl {
interpreter_directive_sigil: char, interpreter_directive_sigil: char,
line_reader: ::linefeed::interface::Interface<::linefeed::terminal::DefaultTerminal>, line_reader: ::linefeed::interface::Interface<::linefeed::terminal::DefaultTerminal>,
@ -101,33 +103,7 @@ impl Repl {
self.options.save_to_file(OPTIONS_SAVE_FILE); 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> { fn handle_interpreter_directive(&mut self, input: &str) -> InterpreterDirectiveOutput {
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<String> {
let mut iter = input.chars(); let mut iter = input.chars();
iter.next(); iter.next();
let arguments: Vec<&str> = iter let arguments: Vec<&str> = iter
@ -140,15 +116,7 @@ impl Repl {
} }
let directives = self.get_directives(); let directives = self.get_directives();
directives.execute(self, &arguments) directives.perform(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())
}
*/
} }
fn print_help_message(&mut self, commands_passed_to_help: &[&str] ) -> String { fn print_help_message(&mut self, commands_passed_to_help: &[&str] ) -> String {