summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2022-01-17 18:22:54 -0500
committerJesse Luehrs <doy@tozt.net>2022-01-17 18:22:54 -0500
commited9b8b345316bb8807ebbf501f19fa4684e5deba (patch)
tree50d2f9bdaeffc8e041d01bf6fff44c310ce4f94b /src
parentb95a6415d5c85fcbbc5dfc5983838530fdcff190 (diff)
downloadnbsh-ed9b8b345316bb8807ebbf501f19fa4684e5deba.tar.gz
nbsh-ed9b8b345316bb8807ebbf501f19fa4684e5deba.zip
implement command substitution
Diffstat (limited to 'src')
-rw-r--r--src/parse/ast.rs24
-rw-r--r--src/shell.pest5
2 files changed, 27 insertions, 2 deletions
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<Word>),
+ 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+ }