Skip to content

Commit

Permalink
Shell reader macroa.
Browse files Browse the repository at this point in the history
  • Loading branch information
sstanfield committed Oct 17, 2024
1 parent fc2a340 commit 1b68c5c
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 12 deletions.
71 changes: 71 additions & 0 deletions compiler/src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,72 @@ impl<'vm> Reader<'vm> {
}
}

fn read_shell_list(
&mut self,
buffer: &mut String,
in_back_quote: bool,
) -> Result<Value, ReadError> {
let mut closed = false;
let mut list = Vec::new();
list.push(Value::Symbol(self.vm().intern_static("sh")));
let line = self.line() as u32;
let column = self.column() as u32;
let mut open_parens: u32 = 0;
buffer.clear();

while let Some(ch) = self.chars().next() {
let ch = ch?;
match &*ch {
")" if open_parens == 0 => {
closed = true;
if !buffer.is_empty() {
list.push(self.vm().alloc_string(buffer.clone()));
buffer.clear();
}
break;
}
")" => open_parens -= 1,
"(" => open_parens += 1,
":" => {
if !buffer.is_empty() {
list.push(self.vm().alloc_string(buffer.clone()));
}
if let Some(Value::Symbol(i)) =
self.read_inner(buffer, in_back_quote, ReadReturn::List)?
{
list.push(Value::Keyword(i));
buffer.clear();
} else {
return Err(ReadError {
reason: "Invalid keyword".to_string(),
});
}
}
"~" => {
if !buffer.is_empty() {
list.push(self.vm().alloc_string(buffer.clone()));
}
if let Some(exp) = self.read_inner(buffer, in_back_quote, ReadReturn::List)? {
list.push(exp);
buffer.clear();
}
}
_ => buffer.push_str(&ch),
}
}
if !closed {
Err(ReadError {
reason: "Unclosed list".to_string(),
})
} else if list.is_empty() {
Err(ReadError {
reason: "Empty shell command".to_string(),
})
} else {
Ok(self.alloc_list(list, line, column))
}
}

fn read_list(&mut self, buffer: &mut String, in_back_quote: bool) -> Result<Value, ReadError> {
let mut cont = true;
let mut dot = false;
Expand Down Expand Up @@ -1201,6 +1267,11 @@ impl<'vm> Reader<'vm> {
return Ok(Some(v));
}
}
"$" if self.peek_is("(")? => {
self.chars().next();
let exp = self.read_shell_list(buffer, in_back_quote)?;
return Ok(Some(exp));
}
"(" => {
let exp = self.read_list(buffer, in_back_quote)?;
return Ok(Some(exp));
Expand Down
86 changes: 86 additions & 0 deletions shell/src/command_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ impl Arg {
}
}

impl TryFrom<&mut Arg> for FileDesc {
type Error = ();

fn try_from(arg: &mut Arg) -> Result<Self, Self::Error> {
if let Arg::Str(targ) = arg {
let fd = targ.to_string_lossy();
if fd.ends_with('-') {
match FileDesc::from_str(&fd[0..fd.len() - 1]) {
Ok(fd) => Ok(fd),
Err(_) => Err(()),
}
} else {
match FileDesc::from_str(&fd) {
Ok(fd) => Ok(fd),
Err(_) => Err(()),
}
}
} else {
Err(())
}
}
}

impl Display for Arg {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down Expand Up @@ -368,6 +391,46 @@ impl Redirects {
}
}
}

fn fds_to_internal(&mut self, fd_set: &HashSet<FileDesc>) {
for r in self.redir_stack.iter_mut() {
match r {
RedirType::In(ifd, RedirArg::Fd(fd_arg)) => {
if let Ok(fd) = fd_arg.try_into() {
if fd_set.contains(&fd) {
*r = RedirType::In(*ifd, RedirArg::InternalFd(fd));
}
}
}
RedirType::In(_, _) => {}
RedirType::InDirect(_, _) => {}
RedirType::Out(ofd, RedirArg::Fd(fd_arg)) => {
if let Ok(fd) = fd_arg.try_into() {
if fd_set.contains(&fd) {
*r = RedirType::Out(*ofd, RedirArg::InternalFd(fd));
}
}
}
RedirType::Out(_, _) => {}
RedirType::OutTrunc(ofd, RedirArg::Fd(fd_arg)) => {
if let Ok(fd) = fd_arg.try_into() {
if fd_set.contains(&fd) {
*r = RedirType::OutTrunc(*ofd, RedirArg::InternalFd(fd));
}
}
}
RedirType::OutTrunc(_, _) => {}
RedirType::InOut(iofd, RedirArg::Fd(fd_arg)) => {
if let Ok(fd) = fd_arg.try_into() {
if fd_set.contains(&fd) {
*r = RedirType::InOut(*iofd, RedirArg::InternalFd(fd));
}
}
}
RedirType::InOut(_, _) => {}
}
}
}
}

impl Default for Redirects {
Expand Down Expand Up @@ -511,6 +574,12 @@ impl CommandWithArgs {
}
}

pub fn fds_to_internal(&mut self, fd_set: &HashSet<FileDesc>) {
if let Some(stdios) = &mut self.stdios {
stdios.fds_to_internal(fd_set);
}
}

/// Return a set of all the 'internal' file descriptors (for pipes etc).
pub fn get_internal_fds(&self) -> HashSet<FileDesc> {
let mut res = HashSet::new();
Expand Down Expand Up @@ -736,6 +805,23 @@ impl Run {
}
}

pub fn fds_to_internal(&mut self, fd_set: &HashSet<FileDesc>) {
match self {
Run::Command(current) => current.fds_to_internal(fd_set),
Run::BackgroundCommand(current) => current.fds_to_internal(fd_set),
Run::Pipe(ref mut seq)
| Run::Sequence(ref mut seq)
| Run::And(ref mut seq)
| Run::Or(ref mut seq) => {
for run in seq {
run.fds_to_internal(fd_set);
}
}
Run::Subshell(ref mut current) => current.fds_to_internal(fd_set),
Run::Empty => {}
}
}

/// Return a set of all the 'internal' file descriptors (for pipes etc).
pub fn get_internal_fds(&self) -> HashSet<FileDesc> {
let mut res = HashSet::new();
Expand Down
22 changes: 10 additions & 12 deletions slosh_lib/src/shell_builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use compile_state::state::SloshVm;
use shell::platform::{FromFileDesc, Platform, Sys};
use slvm::io::HeapIo;
use slvm::{VMError, VMResult, Value};
use std::collections::HashSet;
use std::env::VarError;
use std::fs::File;
use std::io::{BufRead, ErrorKind};
Expand All @@ -13,7 +14,7 @@ fn sh(vm: &mut SloshVm, registers: &[Value]) -> VMResult<Value> {
let mut result = Vec::new();
let mut new_regs = Vec::with_capacity(registers.len());
new_regs.extend_from_slice(registers);
let mut fds_close = Vec::new();
let mut fds_close = HashSet::new();
for r in new_regs.iter_mut() {
if let Value::Keyword(i) = r {
let key = vm.get_interned(*i);
Expand All @@ -22,7 +23,7 @@ fn sh(vm: &mut SloshVm, registers: &[Value]) -> VMResult<Value> {
Ok((inp, outp)) => {
let mut key = key.to_string();
key.push_str(&format!("&{inp}"));
fds_close.push(inp);
fds_close.insert(inp);
*r = vm.alloc_string(key);
let file = HeapIo::from_file(unsafe { File::from_file_desc(outp) });
result.push(vm.alloc_io(file));
Expand All @@ -35,7 +36,7 @@ fn sh(vm: &mut SloshVm, registers: &[Value]) -> VMResult<Value> {
Ok((inp, outp)) => {
let mut key = key.to_string();
key.push_str(&format!("&{outp}"));
fds_close.push(outp);
fds_close.insert(outp);
*r = vm.alloc_string(key);
let file = HeapIo::from_file(unsafe { File::from_file_desc(inp) });
file.to_buf_reader().map_err(|e| {
Expand Down Expand Up @@ -66,21 +67,18 @@ fn sh(vm: &mut SloshVm, registers: &[Value]) -> VMResult<Value> {
let jobs = &mut jobs_ref.borrow_mut();
run_res = shell::parse::parse_line(jobs, &command)
});
let run = run_res
let mut run = run_res
.map_err(|e| VMError::new_compile(format!("sh: {e}")))?
.into_run();
let background = !result.is_empty(); //stdinp.is_some() || stdoutp.is_some();
if !fds_close.is_empty() {
run.fds_to_internal(&fds_close);
}
let background = false; // !result.is_empty();
SHELL_ENV.with(|jobs_ref| {
let jobs = &mut jobs_ref.borrow_mut();
fork_res = shell::run::run_job(&run, jobs, background);
});
// Close the file descriptors for the subshell end of the pipes.
for fd in fds_close {
if let Err(e) = Sys::close_fd(fd) {
eprintln!("error closing subshell pipe: {e}");
}
}
let fork_res = fork_res.map_err(|e| VMError::new_compile(format!("sh: {e}")))?;
let fork_res = fork_res.map_err(|e| VMError::new_compile(format!("sh 2: {e}")))?;
if result.is_empty() {
Ok(fork_res.into())
} else {
Expand Down

0 comments on commit 1b68c5c

Please sign in to comment.