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::*;
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
/// 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<CommandTree>,
help_msg: Option<String>,
function: BoxedCommandFunction,
action: ReplAction,
action: DirectiveAction,
},
NonTerminal {
name: String,
children: Vec<CommandTree>,
help_msg: Option<String>,
action: ReplAction,
action: DirectiveAction,
},
//TODO get rid of Top
Top(Vec<CommandTree>),
}
#[derive(Debug, Clone)]
pub enum ReplAction {
pub enum DirectiveAction {
Null,
Help,
QuitProgram
}
impl ReplAction {
fn get_function(&self) -> impl Fn(&mut Repl, &[&str]) -> Option<String> {
|_: &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<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}
}
@ -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<String> {
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())
}
}

View File

@ -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<String>) -> CommandTree {
let passes_directives: Vec<CommandTree> = 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![

View File

@ -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<String>;
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<String> {
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 {