From 9c0f88ec91dcdc6873d5c28baa66a833d47771cc Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Wed, 5 Apr 2023 21:18:40 -0700 Subject: [PATCH] WIP early start on pipe command --- Readme.org | 2 +- src/stl/posix.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/Readme.org b/Readme.org index 8ed53c3..d843061 100644 --- a/Readme.org +++ b/Readme.org @@ -452,7 +452,7 @@ Representation of code trees, traversals, and type annotations all live here. *** lib: file:src/lib.rs This defines a library that can be included to provide an interpreter interface within any Rust project. -The components defined here can certainly be used to support language development for other LISP (or non LISP) langauges. +The components defined here can certainly be used to support language development for other LISP (or non LISP) langauges.` Your project can use or not use any number of these components. *** sym: file:src/sym.rs diff --git a/src/stl/posix.rs b/src/stl/posix.rs index ddc8531..470fd6f 100644 --- a/src/stl/posix.rs +++ b/src/stl/posix.rs @@ -165,6 +165,57 @@ fn load_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Resu } } +// TODO: maybe flesh out this docstring a bit +const PIPE_DOCSTRING: &str = "Calls a sequence of shell commands. +Each one has their output redirected to the input of the next one. + +Example: +(pipe + (ls -la) + (grep '*.rs') + (tr -d '.rs'))"; +fn pipe_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result { + if ast.is_empty() { + return Err("need at least one argument".to_string()) + } + + let mut input = Stdio::inherit(); + if !ast.circuit(&mut |arg: &Ctr| -> bool { + if let Ctr::Seg(command_form) = arg { + let args = VecDeque::from(args_from_ast(ast, syms)); + if args.is_empty() { + return false + } + + if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) { + let tmp = Stdio::piped(); + // TODO Youll just have to break open launch_command here + // youll need seperate calls for .stdin and .stdout anyways + // and also the move semantics are not working + launch_command( + filepath, + &Vec::from(args.make_contiguous()), + input, + Stdio::inherit(), + tmp, + false, + state, + ).unwrap(); + input = tmp; + true + } else { + eprintln!("file not found"); + false + } + } else { + false + } + }) { + Err("all arguments must be full shell commands".to_string()) + } else { + Ok(Ctr::None) + } +} const LOAD_TO_STRING_DOCSTRING: &str = "Calls a binary off disk with given arguments. Arguments may be of any type except lambda. If a symbol is not defined it will be passed as a string. @@ -208,7 +259,25 @@ fn load_to_string_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellStat } // TODO: rework this callback to reduce spaghett -const LOAD_WITH_DOCSTRING: &str = ""; +const LOAD_WITH_DOCSTRING: &str = "Takes two arguments. +1. a list of up to three redirects + - A redirect looks like a variable declaration in a let form + Ex: ('stdout' '/dev/null') + - The first value is one of 'stdout', 'stdin', or 'stderr' + - The second value is a filename. + The file must exist for stdin redirects. + For other redirects the file will be created if not existing. + + Example: (('stdin' '/path/to/myinput.txt') + ('stdout' '/dev/null')) + +2. a shell command + - exactly as would be passed to load + Example: (ping -c 4 google.com) + +Example invocation: +(load-with (('stdout' '/dev/null')) + (ping -c 4 google.com))"; fn load_with_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result { if ast.len() != 2 { Err("exactly two arguments needed".to_string())