Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::collections::HashMap;
- use std::iter::Peekable;
- use std::slice::Iter;
- use std::str::Chars;
- pub struct CommandLine<'a> {
- commands: HashMap<&'a str, Command<'a>>,
- }
- impl<'a> CommandLine<'a> {
- pub fn new_appending(commands: HashMap<&'a str, Command<'a>>) -> Self {
- Self { commands }
- }
- pub fn new() -> Self {
- Self {
- commands: HashMap::new(),
- }
- }
- pub fn register(&mut self, command: Command<'a>) {
- self.commands.insert(command.name, command);
- }
- pub fn deregister(&mut self, command: Command<'a>) {
- self.commands.remove(command.name);
- }
- pub fn lookup(&self, name: &str) -> Option<&Command<'a>> {
- self.commands.get(name)
- }
- pub fn run(&self, input: &str) -> Result<(), CommandParseError> {
- let parsed_syntax_res = parsing::parse(self, input);
- if parsed_syntax_res.is_err() {
- return Err(parsed_syntax_res.err().unwrap());
- }
- let parsed_syntax = parsed_syntax_res.ok().unwrap();
- parsed_syntax.branch.execute(parsed_syntax.parameters);
- Ok(())
- }
- }
- pub enum ParameterVal {
- Raw(String),
- Number(i32),
- Multi(Vec<Parameter>),
- }
- pub struct Parameter {
- pub val: ParameterVal,
- }
- #[derive(PartialEq, Clone)]
- pub enum ParameterKind {
- Raw,
- Number,
- List(Box<ParameterKind>),
- None,
- }
- impl std::fmt::Display for ParameterKind {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- let name = match self {
- ParameterKind::Raw => "raw",
- ParameterKind::Number => "number",
- ParameterKind::List(_) => "list",
- _ => "unknown",
- };
- f.write_str(name)
- }
- }
- pub enum CommandParseError {
- InvalidInput,
- UnknownCommand,
- InvalidBranch,
- MissingParameter(ParameterKind),
- InvalidParameter(String),
- }
- pub struct Command<'a> {
- pub name: &'a str,
- pub branches: Vec<Branch<'a>>,
- default_branch: Option<Branch<'a>>,
- }
- impl<'a> Command<'a> {
- pub fn new(name: &'a str) -> Self {
- Command {
- name,
- branches: Vec::new(),
- default_branch: Option::None,
- }
- }
- pub fn new_branched(name: &'a str, branches: Vec<Branch<'a>>) -> Result<Self, String> {
- let mut default_branch = Option::None;
- let mut branches = Vec::from(branches);
- if branches.len() == 1 {
- default_branch = Option::Some(branches.swap_remove(0));
- } else {
- let mut idx = 0;
- while idx < branches.len() {
- unsafe {
- if !branches.get_unchecked(idx).aliases.is_empty() {
- idx += 1;
- continue;
- }
- }
- idx += 1;
- if default_branch.is_some() {
- return Result::Err("default branch already set".to_owned());
- } else {
- default_branch = Option::Some(branches.swap_remove(idx));
- break;
- }
- }
- }
- Result::Ok(Self {
- name,
- branches,
- default_branch,
- })
- }
- pub fn new_single(name: &'a str, default_branch: Branch<'a>) -> Self {
- Self {
- name,
- branches: Vec::new(),
- default_branch: Option::Some(default_branch),
- }
- }
- pub fn add_branch(&mut self, branch: Branch<'a>) -> Result<(), String> {
- if branch.aliases.is_empty() {
- if self.default_branch.is_some() {
- return Result::Err("default branch already set".to_owned());
- } else {
- self.default_branch = Option::Some(branch);
- }
- } else {
- self.branches.push(branch);
- }
- Result::Ok(())
- }
- }
- pub struct Branch<'a> {
- aliases: Vec<&'a str>,
- param_types: Vec<ParameterKind>,
- task: Box<dyn FnMut(&mut Iter<Parameter>)>,
- }
- impl<'a> Branch<'a> {
- pub fn new<F: FnMut(&mut Iter<Parameter>) + 'static>(
- aliases: Vec<&'a str>,
- param_format: &'a str,
- task: F,
- ) -> Self {
- Self {
- aliases,
- param_types: parsing::parse_param_types(param_format),
- task: Box::new(task),
- }
- }
- pub fn default<F: FnMut(&mut Iter<Parameter>) + 'static>(param_format: &'a str, task: F) -> Self {
- Self::new(Vec::new(), param_format, task)
- }
- fn execute(&mut self, params: Vec<Parameter>) {
- (self.task)(&mut params.iter())
- }
- }
- pub trait ParamValueShortcut {
- fn as_str(&self) -> &String;
- fn as_i32(&self) -> &i32;
- fn as_multi(&self) -> &Vec<Parameter>;
- }
- impl ParamValueShortcut for Parameter {
- fn as_str(&self) -> &String {
- match &self.val {
- ParameterVal::Raw(v) => v,
- _ => panic!(),
- }
- }
- fn as_i32(&self) -> &i32 {
- match &self.val {
- ParameterVal::Number(v) => v,
- _ => panic!(),
- }
- }
- fn as_multi(&self) -> &Vec<Parameter> {
- match &self.val {
- ParameterVal::Multi(v) => v,
- _ => panic!(),
- }
- }
- }
- pub trait ParamAccessor {
- fn poll(&mut self) -> &Parameter;
- fn poll_str(&mut self) -> &String;
- fn poll_i32(&mut self) -> &i32;
- fn poll_multi(&mut self) -> &Vec<Parameter>;
- fn poll_multi_as<B, F: FnMut(&Parameter) -> B>(&mut self, map_func: F) -> Vec<B>;
- }
- impl<'a> ParamAccessor for Iter<'a, Parameter> {
- fn poll(&mut self) -> &Parameter {
- self.next().unwrap()
- }
- fn poll_str(&mut self) -> &String {
- self.poll().as_str()
- }
- fn poll_i32(&mut self) -> &i32 {
- self.poll().as_i32()
- }
- fn poll_multi(&mut self) -> &Vec<Parameter> {
- self.poll().as_multi()
- }
- fn poll_multi_as<B, F>(&mut self, map_func: F) -> Vec<B>
- where
- F: FnMut(&Parameter) -> B,
- {
- self.poll_multi().iter().map(map_func).collect()
- }
- }
- mod parsing {
- use super::*;
- pub struct SyntaxTree<'a> {
- pub command: &'a Command<'a>,
- pub branch: &'a mut Branch<'a>,
- pub parameters: Vec<Parameter>,
- }
- pub fn parse<'a>(
- command_line: &'a CommandLine<'a>,
- input: &'a str,
- ) -> Result<SyntaxTree<'a>, CommandParseError> {
- let mut parts = parse_input_parts(input).into_iter();
- let command_name_res = parts.next();
- if command_name_res.is_none() {
- return Err(CommandParseError::InvalidInput);
- }
- let command_name = command_name_res.unwrap();
- let command_res = command_line.lookup(command_name.as_str());
- if command_res.is_none() {
- return Err(CommandParseError::UnknownCommand);
- }
- let command = command_res.unwrap();
- let mut peekable_parts = parts.peekable();
- let possible_branch_name_res = peekable_parts.peek().cloned();
- if possible_branch_name_res.is_none() {
- return Err(CommandParseError::InvalidInput);
- }
- let possible_branch_name = possible_branch_name_res.unwrap().clone();
- let selected_branch = command.default_branch.as_ref().or_else(|| {
- for branch in &command.branches {
- if branch.aliases.contains(&possible_branch_name.as_str()) {
- peekable_parts.next(); // take non-default branch name from the input parts
- return Some(branch);
- }
- }
- return None;
- });
- if selected_branch.is_none() {
- return Err(CommandParseError::InvalidBranch);
- }
- let selected_branch = selected_branch.unwrap();
- let mut parameters: Vec<Parameter> = Vec::new();
- for param_type in selected_branch.param_types.iter() {
- let raw_param_res = peekable_parts.next();
- if raw_param_res.is_none() {
- return Err(CommandParseError::MissingParameter(param_type.clone()));
- }
- let raw_param = raw_param_res.unwrap();
- let result = parse_param(raw_param.clone(), ¶m_type);
- if result.is_none() {
- return Err(CommandParseError::InvalidParameter(raw_param.to_owned()));
- }
- parameters.push(result.unwrap());
- }
- return Ok(SyntaxTree {
- command,
- branch: selected_branch,
- parameters,
- });
- }
- pub fn parse_param_types(format: &str) -> Vec<ParameterKind> {
- let mut result = Vec::new();
- let mut chars_peek = format.chars().peekable();
- let iter = format.chars();
- let mut prev_param_was_list = false;
- for c in iter {
- chars_peek.next();
- if prev_param_was_list {
- prev_param_was_list = false;
- continue;
- }
- let kind = match c {
- 's' => ParameterKind::Raw,
- 'n' => ParameterKind::Number,
- _ => ParameterKind::None,
- };
- let check_param_res = check_list_param_or(&mut chars_peek, kind);
- if check_param_res.0 {
- prev_param_was_list = true;
- }
- let kind = check_param_res.1;
- if kind != ParameterKind::None {
- result.push(kind);
- }
- }
- return result;
- }
- pub fn check_list_param_or(
- chars: &mut Peekable<Chars>,
- original_type: ParameterKind,
- ) -> (bool, ParameterKind) {
- let mut c = chars.clone();
- let next_char_res = c.peek();
- if next_char_res.is_some() {
- let next_char = *next_char_res.unwrap();
- if next_char == '{' || next_char == '[' {
- chars.next().unwrap();
- return (true, ParameterKind::List(Box::new(original_type)));
- }
- }
- return (false, original_type);
- }
- fn parse_input_parts(input: &str) -> Vec<String> {
- let mut parts = Vec::new();
- let mut curr_part = String::new();
- let mut in_compound_param = false;
- let mut last_char = std::char::MAX;
- for (i, c) in input.chars().enumerate() {
- match c {
- '[' | '{' => {
- if last_char == '\\' {
- curr_part.pop();
- curr_part.push(c);
- continue;
- }
- curr_part.push(c);
- in_compound_param = true;
- }
- ']' | '}' => {
- if last_char == '\\' {
- curr_part.pop();
- curr_part.push(c);
- continue;
- }
- if in_compound_param {
- curr_part.push(c);
- parts.push(curr_part.to_owned());
- curr_part.clear();
- in_compound_param = false;
- }
- }
- '"' => {
- if last_char == '\\' {
- curr_part.pop();
- curr_part.push(c);
- continue;
- }
- in_compound_param = !in_compound_param;
- if !in_compound_param {
- parts.push(curr_part.to_owned());
- curr_part.clear();
- }
- }
- ' ' => {
- if in_compound_param || last_char == '\\' {
- curr_part.push(c);
- } else {
- if last_char != '"' {
- parts.push(curr_part.to_owned());
- curr_part.clear();
- }
- }
- }
- _ => {
- curr_part.push(c);
- }
- }
- if i + 1 == input.len() {
- parts.push(curr_part.to_owned());
- break;
- }
- last_char = c;
- }
- parts
- }
- fn parse_param(raw_param: String, param_type: &ParameterKind) -> Option<Parameter> {
- match param_type {
- ParameterKind::Raw => {
- return Some(Parameter {
- val: ParameterVal::Raw(raw_param),
- });
- }
- ParameterKind::Number => {
- let num_parse_res = raw_param.parse::<i32>();
- if num_parse_res.is_err() {
- return None;
- }
- return Some(Parameter {
- val: ParameterVal::Number(num_parse_res.unwrap()),
- });
- }
- ParameterKind::List(t) => {
- const ELEMENT_DELIMITER: char = ',';
- let mut chars = raw_param.chars();
- let open_char = chars.next().unwrap();
- if open_char != '{' && open_char != '[' {
- return None;
- }
- let close_char = chars.next_back().unwrap();
- if close_char != '}' && close_char != ']' {
- return None;
- }
- let raw_param = chars.as_str();
- let raw_elements: Vec<&str> = raw_param.split(ELEMENT_DELIMITER).collect();
- let mut elements: Vec<Parameter> = Vec::new();
- for e in raw_elements {
- let e = e.trim();
- let res = parse_param(e.to_string(), t);
- if res.is_none() {
- return None;
- }
- elements.push(res.unwrap());
- }
- return Some(Parameter {
- val: ParameterVal::Multi(elements),
- });
- }
- _ => {}
- };
- return None;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement