diff --git a/src/control.rs b/src/control.rs index 3fb17b7..01cbbba 100644 --- a/src/control.rs +++ b/src/control.rs @@ -2,6 +2,7 @@ use crate::command::Command; use crate::exit_code::ExitCode; use crate::interface::get_user_input; use crate::parser::parse; +use crate::variables::Variables; fn exit(code: &ExitCode) { let code = i32::from(code.get()); @@ -11,12 +12,13 @@ fn exit(code: &ExitCode) { pub fn run() { let mut current_exit_code = ExitCode::new(0); + let mut variables = Variables::new(); loop { let user_input = get_user_input(); if user_input.is_some() { - let mut command_sequence = parse(user_input.unwrap()); + let mut command_sequence = parse(user_input.unwrap(), &variables); if !command_sequence.is_empty() { current_exit_code = command_sequence.spawn(); diff --git a/src/parser.rs b/src/parser.rs index 8ede708..9d2d299 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,22 @@ use crate::command::command_builder::CommandBuilder; use crate::command::command_sequence::CommandSequence; +use crate::variables::Variables; + +fn parse_variable(characters: &mut Vec, variables: &Variables) -> String { + if characters.is_empty() { + String::new() + } else { + let mut current_char = characters.pop().unwrap(); + let mut var_name = String::new(); + + while !characters.is_empty() && !current_char.is_whitespace() { + var_name.push(current_char); + current_char = characters.pop().unwrap(); + } + + variables.get(var_name.as_str()) + } +} fn parse_quote(characters: &mut Vec) -> String { let mut quoted = String::new(); @@ -16,41 +33,49 @@ fn parse_quote(characters: &mut Vec) -> String { quoted } -fn parse_backslash(characters: &mut Vec) -> Option { +fn parse_backslash(characters: &mut Vec) -> String { let escaped_char = match characters.is_empty() { - false => Some(characters.pop().unwrap()), - true => None, + false => String::from(characters.pop().unwrap()), + true => String::new(), }; escaped_char } -fn parse_main(characters: &mut Vec, current_arg: &mut String) -> Vec { +fn parse_main( + characters: &mut Vec, + current_arg: &mut String, + variables: &Variables, +) -> Vec { if characters.is_empty() { - vec![] + let mut last_arg = vec![]; + + if !current_arg.is_empty() { + last_arg.push(current_arg.clone()); + } + + last_arg } else { let current_char = characters.pop().unwrap(); if current_char.is_whitespace() { if !current_arg.is_empty() { let mut argv: Vec = vec![current_arg.clone()]; - argv.append(&mut parse_main(characters, &mut String::new())); + argv.append(&mut parse_main(characters, &mut String::new(), variables)); argv } else { - parse_main(characters, current_arg) + parse_main(characters, current_arg, variables) } } else if current_char == '\\' { - let escaped_char = parse_backslash(characters); - - if escaped_char.is_some() { - current_arg.push(escaped_char.unwrap()); - } - - parse_main(characters, current_arg) + current_arg.push_str(parse_backslash(characters).as_str()); + parse_main(characters, current_arg, variables) + } else if current_char == '$' { + current_arg.push_str(parse_variable(characters, variables).as_str()); + parse_main(characters, current_arg, variables) } else if current_char == '\'' { current_arg.push_str(parse_quote(characters).as_str()); - parse_main(characters, current_arg) + parse_main(characters, current_arg, variables) } else if current_char == ';' { let mut argv: Vec = vec![]; @@ -61,17 +86,17 @@ fn parse_main(characters: &mut Vec, current_arg: &mut String) -> Vec CommandSequence { +pub fn parse(line: String, variables: &Variables) -> CommandSequence { let mut characters: Vec = line.chars().rev().collect(); let mut command_sequence = CommandSequence::new(); while !characters.is_empty() { - let argv = parse_main(&mut characters, &mut String::new()); + let argv = parse_main(&mut characters, &mut String::new(), variables); if !argv.is_empty() { let command = CommandBuilder::new(argv).build(); diff --git a/src/variables.rs b/src/variables.rs index 88277b1..61b4be9 100644 --- a/src/variables.rs +++ b/src/variables.rs @@ -1,12 +1,18 @@ use std::collections::HashMap; use std::env; -struct Variables { +pub struct Variables { variables: HashMap, } impl Variables { - fn get(&self, key: &str) -> String { + pub fn new() -> Self { + Self { + variables: HashMap::new(), + } + } + + pub fn get(&self, key: &str) -> String { let var_from_map = self.variables.get(key); let value: String; @@ -24,7 +30,7 @@ impl Variables { value } - fn unset(&mut self, key: &str) { + pub fn unset(&mut self, key: &str) { let old_value = self.variables.remove(key); if old_value.is_none() { @@ -32,12 +38,12 @@ impl Variables { } } - fn set(&mut self, key: &str, value: &str) { + pub fn set(&mut self, key: &str, value: &str) { self.variables .insert(String::from(key), String::from(value)); } - fn export(&mut self, key: &str) { + pub fn export(&mut self, key: &str) { let var_to_export = self.variables.get(key); if var_to_export.is_some() {