Browse Source

feat: use shlex to parse line

main
fdai7451 2 years ago
parent
commit
7908e28279
  1. 7
      Cargo.lock
  2. 1
      Cargo.toml
  3. 4
      src/builtins/cd.rs
  4. 2
      src/builtins/exit.rs
  5. 2
      src/builtins/mod.rs
  6. 1
      src/error.rs
  7. 4
      src/execute.rs
  8. 3
      src/main.rs
  9. 40
      src/parse.rs

7
Cargo.lock

@ -174,6 +174,7 @@ name = "pmuw-project"
version = "0.1.0"
dependencies = [
"rustyline",
"shlex",
]
[[package]]
@ -267,6 +268,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "shlex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]]
name = "smallvec"
version = "1.10.0"

1
Cargo.toml

@ -5,3 +5,4 @@ edition = "2021"
[dependencies]
rustyline = "10.1.0"
shlex = "1.1"

4
src/builtins/cd.rs

@ -2,7 +2,7 @@ use std::env::set_current_dir;
use crate::error::ShellError;
pub fn run(args: &[&str]) -> Result<(), ShellError> {
set_current_dir(args[0]);
pub fn run(args: Vec<String>) -> Result<(), ShellError> {
set_current_dir(args.get(0).unwrap());
Ok(())
}

2
src/builtins/exit.rs

@ -2,4 +2,4 @@ use crate::error::ShellError;
pub fn run() -> Result<(), ShellError> {
Err(ShellError::Exit)
}
}

2
src/builtins/mod.rs

@ -8,7 +8,7 @@ pub fn is_builtin(keyword: &str) -> bool {
BUILTINS.contains(&keyword)
}
pub fn execute_builtin(keyword: &str, args: &[&str]) -> Result<(), ShellError> {
pub fn execute_builtin(keyword: &str, args: Vec<String>) -> Result<(), ShellError> {
match keyword {
"exit" => exit::run()?,
"cd" => cd::run(args)?,

1
src/error.rs

@ -5,4 +5,5 @@ pub enum ShellError {
Exit,
NotFound(Command),
ExecuteFailure(String),
MalformedArgs(String),
}

4
src/execute.rs

@ -9,10 +9,10 @@ pub fn interpret(line: &str) -> Result<(), ShellError> {
if line.is_empty() {
return Err(ShellError::EmptyLine);
}
let (keyword, args) = parse_line(line);
let (keyword, args) = parse_line(line)?;
if is_builtin(keyword) {
execute_builtin(keyword, &args)?;
execute_builtin(keyword, args)?;
} else {
let mut command = Command::new(keyword);
command.args(args);

3
src/main.rs

@ -34,6 +34,9 @@ fn main() -> Result<()> {
Err(ShellError::ExecuteFailure(msg)) => {
eprintln!("{}", msg)
}
Err(ShellError::MalformedArgs(args)) => {
eprintln!("Malformed arguments: {}", args)
}
},
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => {
break;

40
src/parse.rs

@ -1,37 +1,11 @@
pub fn parse_line(line: &str) -> (&str, Vec<&str>) {
let tokens = tokenize(line);
use crate::error::ShellError;
let keyword = tokens[0];
let mut args: Vec<&str> = Vec::new();
pub fn parse_line(line: &str) -> Result<(&str, Vec<String>), ShellError> {
let (keyword, unparsed_args) = line.split_once(' ').unwrap_or((line, ""));
if tokens.len() > 1 {
args = tokens[1..].to_vec();
}
(keyword, args)
}
fn tokenize(line: &str) -> Vec<&str> {
line.trim().split(' ').collect::<Vec<&str>>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tokenize() {
assert_eq!(
tokenize("keyword arg1 arg2 arg3"),
vec!["keyword", "arg1", "arg2", "arg3"]
);
}
#[test]
fn test_parse_line() {
assert_eq!(
parse_line("keyword arg1 arg2 arg3"),
("keyword", vec!["arg1", "arg2", "arg3"])
);
if let Some(args) = shlex::split(unparsed_args) {
Ok((keyword, args))
} else {
Err(ShellError::MalformedArgs(unparsed_args.to_string()))
}
}
Loading…
Cancel
Save