From 9b1595b795121d233cd0cf32537661839e318914 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 17 Jan 2022 01:19:08 -0500 Subject: basic subshell implementation --- src/parse/ast.rs | 31 ++++++++++++++++++++++++++++++- src/runner/mod.rs | 4 ++++ src/shell.pest | 6 ++++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/parse/ast.rs b/src/parse/ast.rs index bac40c8..9d74331 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -141,7 +141,36 @@ impl Exe { } fn build_ast(pair: pest::iterators::Pair) -> Self { - assert!(matches!(pair.as_rule(), Rule::exe)); + assert!(matches!(pair.as_rule(), Rule::subshell | Rule::exe)); + if matches!(pair.as_rule(), Rule::subshell) { + return Self { + exe: Word { + parts: vec![WordPart::SingleQuoted( + std::env::current_exe() + .unwrap() + .to_str() + .unwrap() + .to_string(), + )], + }, + args: vec![ + Word { + parts: vec![WordPart::SingleQuoted("-c".to_string())], + }, + Word { + parts: vec![WordPart::SingleQuoted( + pair.as_str() + .strip_prefix('(') + .unwrap() + .strip_suffix(')') + .unwrap() + .to_string(), + )], + }, + ], + redirects: vec![], + }; + } let mut iter = pair.into_inner(); let exe = match WordOrRedirect::build_ast(iter.next().unwrap()) { WordOrRedirect::Word(word) => word, diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 98894b3..63af51b 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -158,7 +158,11 @@ async fn run_commands( *should = !list.is_empty(); if *should { let val = list.remove(0); + // XXX i really need to just pick one location and + // stick with it instead of trying to keep these + // in sync env.set_var(var, &val); + std::env::set_var(var, &val); } } else { unreachable!(); diff --git a/src/shell.pest b/src/shell.pest index 8a51070..fdfb1b1 100644 --- a/src/shell.pest +++ b/src/shell.pest @@ -3,7 +3,8 @@ escape_char = @{ "\\" ~ ANY } bareword_char = @{ escape_char | - !("|" | ";" | "\"" | "'" | "$" | "{" | WHITESPACE | COMMENT) ~ ANY + !("|" | ";" | "\"" | "'" | "$" | "{" | "(" | ")" | WHITESPACE | COMMENT) + ~ ANY } single_string_char = @{ basic_escape_char | (!"'" ~ ANY) } double_string_char = @{ escape_char | (!("\"" | "$") ~ ANY) } @@ -44,8 +45,9 @@ word = ${ word_part+ } word_or_redirect = ${ redir_prefix? ~ word } exe = ${ word_or_redirect ~ (w ~ word_or_redirect)* } +subshell = ${ "(" ~ w? ~ commands ~ w? ~ ")" } list = ${ word ~ (w ~ word)* } -pipeline = ${ exe ~ (w? ~ "|" ~ w? ~ exe)* } +pipeline = ${ (subshell | exe) ~ (w? ~ "|" ~ w? ~ (subshell | exe))* } control_if = ${ "if" ~ w ~ pipeline } control_while = ${ "while" ~ w ~ pipeline } -- cgit v1.2.3-54-g00ecf