From ed9b8b345316bb8807ebbf501f19fa4684e5deba Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 17 Jan 2022 18:22:54 -0500 Subject: implement command substitution --- src/parse/ast.rs | 24 +++++++++++++++++++++++- src/shell.pest | 5 ++++- 2 files changed, 27 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/parse/ast.rs b/src/parse/ast.rs index b7716df..294afe5 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -279,7 +279,8 @@ impl Word { is_glob = true; } } - WordPart::Var(_) + WordPart::Substitution(_) + | WordPart::Var(_) | WordPart::DoubleQuoted(_) | WordPart::SingleQuoted(_) => { let part = part.eval(env).await; @@ -321,6 +322,7 @@ impl Word { #[derive(Debug, Clone, PartialEq, Eq)] enum WordPart { Alternation(Vec), + Substitution(String), Var(String), Bareword(String), DoubleQuoted(String), @@ -337,6 +339,11 @@ impl WordPart { Rule::word_part | Rule::alternation_word_part )); pair.into_inner().map(|pair| match pair.as_rule() { + Rule::substitution => { + let commands = pair.into_inner().next().unwrap(); + assert!(matches!(commands.as_rule(), Rule::commands)); + Self::Substitution(commands.as_str().to_string()) + } Rule::var => { let s = pair.as_str(); let inner = s.strip_prefix('$').unwrap(); @@ -368,6 +375,21 @@ impl WordPart { async fn eval(self, env: &Env) -> String { match self { Self::Alternation(_) => unreachable!(), + Self::Substitution(commands) => { + let mut cmd = async_std::process::Command::new( + std::env::current_exe().unwrap(), + ); + cmd.args(&["-c", &commands]); + cmd.stdin(async_std::process::Stdio::inherit()); + cmd.stderr(async_std::process::Stdio::inherit()); + let mut out = + String::from_utf8(cmd.output().await.unwrap().stdout) + .unwrap(); + if out.ends_with('\n') { + out.truncate(out.len() - 1); + } + out + } Self::Var(name) => { env.var(&name).unwrap_or_else(|| "".to_string()) } diff --git a/src/shell.pest b/src/shell.pest index bb06caa..94f78d2 100644 --- a/src/shell.pest +++ b/src/shell.pest @@ -33,12 +33,15 @@ alternation_word_part = ${ alternation_word = ${ alternation_word_part* } alternation = ${ "{" ~ alternation_word ~ ("," ~ alternation_word)* ~ "}" } +substitution = ${ "$(" ~ w? ~ commands ~ w? ~ ")"} + word_part = ${ alternation | + substitution | var | bareword | "'" ~ single_string ~ "'" | - "\"" ~ (var | double_string)+ ~ "\"" + "\"" ~ (substitution | var | double_string)+ ~ "\"" } word = ${ word_part+ } -- cgit v1.2.3-54-g00ecf