Skip to content

Commit

Permalink
subshells
Browse files Browse the repository at this point in the history
  • Loading branch information
harryscholes committed Oct 25, 2024
1 parent ffc272e commit e3accb1
Show file tree
Hide file tree
Showing 7 changed files with 371 additions and 8 deletions.
2 changes: 2 additions & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ pub enum Ast {
And { left: Box<Ast>, right: Box<Ast> },
Or { left: Box<Ast>, right: Box<Ast> },
Sequence { left: Box<Ast>, right: Box<Ast> },
Subshell { inner: Box<Ast> },
Empty,
}
2 changes: 1 addition & 1 deletion src/bin/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {

io::stdin().lock().read_line(&mut line).unwrap();

if let Err(e) = Pipeline::run(&line) {
if let Err(e) = Pipeline::run(line.trim()) {
eprintln!("Error: {}", e);
}

Expand Down
22 changes: 22 additions & 0 deletions src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ fn exec_impl(ast: &Ast, stdin: Option<Stdio>, stdout: Option<Stdio>) -> io::Resu
Ast::And { left, right } => exec_and(left, right, stdout),
Ast::Or { left, right } => exec_or(left, right, stdout),
Ast::Sequence { left, right } => exec_sequence(left, right, stdout),
Ast::Subshell { inner } => exec_impl(inner, stdin, stdout),
Ast::Empty => Ok(Command::new("true").spawn()?),
}
}

Expand Down Expand Up @@ -254,6 +256,26 @@ mod tests {
assert_eq!(std::str::from_utf8(&output.stdout).unwrap(), "bar\n");
}

#[test]
fn test_exec_impl_subshells() {
let ast = Ast::Subshell {
inner: Box::new(Ast::Subshell {
inner: Box::new(Ast::Subshell {
inner: Box::new(Ast::Subshell {
inner: Box::new(Ast::Command {
command: input!("echo"),
args: vec![input!("foo")],
}),
}),
}),
}),
};
let stdout = Stdio::piped();
let child = exec_impl(&ast, None, Some(stdout)).unwrap();
let output = child.wait_with_output().unwrap();
assert_eq!(std::str::from_utf8(&output.stdout).unwrap(), "foo\n");
}

#[test]
fn test_exec_impl_with_pipe() {
let ast = Ast::Pipe {
Expand Down
5 changes: 4 additions & 1 deletion src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ pub enum Token {
And,
Or,
End,
OpenParenthesis,
CloseParenthesis,
// TODO:
// - Subshell
// - Variable
}

Expand All @@ -28,6 +29,8 @@ impl AsRef<OsStr> for Token {
Token::Or => "||".as_ref(),
Token::Background => "&".as_ref(),
Token::End => ";".as_ref(),
Token::OpenParenthesis => "(".as_ref(),
Token::CloseParenthesis => ")".as_ref(),
}
}
}
10 changes: 10 additions & 0 deletions src/lex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ impl Lexer {
tokens.push(input!(std::mem::take(&mut token)));
}
tokens.push(Token::RedirectIn);
} else if c == '(' && !in_single_quotes && !in_double_quotes {
if !token.is_empty() {
tokens.push(input!(std::mem::take(&mut token)));
}
tokens.push(Token::OpenParenthesis);
} else if c == ')' && !in_single_quotes && !in_double_quotes {
if !token.is_empty() {
tokens.push(input!(std::mem::take(&mut token)));
}
tokens.push(Token::CloseParenthesis);
} else {
token.push(c);
}
Expand Down
Loading

0 comments on commit e3accb1

Please sign in to comment.