summaryrefslogtreecommitdiff
path: root/commands/src/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'commands/src/parser.rs')
-rw-r--r--commands/src/parser.rs102
1 files changed, 102 insertions, 0 deletions
diff --git a/commands/src/parser.rs b/commands/src/parser.rs
new file mode 100644
index 0000000..023d602
--- /dev/null
+++ b/commands/src/parser.rs
@@ -0,0 +1,102 @@
+use alloc::collections::BTreeMap;
+use alloc::string::{String, ToString};
+use alloc::vec::Vec;
+
+#[derive(Debug)]
+pub struct Command {
+ pub command: String,
+ pub args: BTreeMap<String, CommandArgument>,
+ pub names: Vec<String>
+}
+
+#[derive(Debug)]
+pub enum CommandArgument {
+ Anonymous,
+ Value(String)
+}
+
+#[derive(Debug)]
+pub enum CommandError {
+ ExecutablePathNotFound,
+ MismatchedQuotes
+}
+
+impl Command {
+ pub fn from_str(input: &str) -> Result<Self, CommandError> {
+ let mut in_double_quotes = false;
+ let mut in_single_quotes = false;
+ let mut escaping = false;
+
+ let input = input.trim();
+ let input_split = input.split(|char| match char {
+ '"' if !in_single_quotes && !escaping => {
+ in_double_quotes = !in_double_quotes;
+ false
+ }
+ '\'' if !in_double_quotes && !escaping => {
+ in_single_quotes = !in_single_quotes;
+ false
+ }
+ '\\' if !escaping => {
+ escaping = true;
+ false
+ },
+ ' ' => !in_double_quotes && !in_single_quotes,
+ _ => {
+ escaping = false;
+ false
+ },
+ });
+
+ let mut parsed = input_split.map(|split| {
+ match split.chars().next().unwrap() {
+ '\'' | '"' => {
+ let end = split.len() - 1;
+ split[1..end].replace("\\n", "\n").replace("\\t", "\t").replace("\\r", "\r").replace('\\', "")
+ }
+ _ => split.replace("\\n", "\n").replace("\\t", "\t").replace("\\r", "\r").replace('\\', "")
+ }
+ });
+ let command = parsed.next().ok_or(CommandError::ExecutablePathNotFound)?;
+ let args: Vec<String> = parsed.collect();
+
+ if in_double_quotes || in_single_quotes {
+ return Err(CommandError::MismatchedQuotes);
+ }
+
+ let mut command_args: BTreeMap<String, CommandArgument> = BTreeMap::new();
+ let mut names: Vec<String> = Vec::new();
+
+ for arg in args.iter() {
+ if arg.starts_with("--") {
+ if arg.contains("=") {
+ let parts: Vec<&str> = arg.split("=").collect();
+ let mut value: &str = parts[1];
+
+ if value.starts_with('"') || value.starts_with("'") {
+ let len = value.len() - 1;
+ value = &value[1..len];
+ }
+
+ command_args.insert(parts[0][2..].parse().unwrap(), CommandArgument::Value(String::from(value)));
+ } else {
+ command_args.insert(arg[2..].parse().unwrap(), CommandArgument::Anonymous);
+ }
+ } else if arg.starts_with("-") {
+ let chars: String = arg[1..].parse().unwrap();
+
+ for i in chars.chars() {
+ command_args.insert(i.to_string(), CommandArgument::Anonymous);
+ }
+ } else {
+ names.push(arg.parse().unwrap());
+ }
+ }
+
+ Ok(Command {
+ command,
+ args: command_args,
+ names
+ })
+ }
+} \ No newline at end of file