implemented load-with.... still need docstring and to fix some write errors
This commit is contained in:
parent
ab14ba4b5e
commit
e8cf59b7a7
2 changed files with 156 additions and 16 deletions
|
|
@ -103,9 +103,10 @@ Like the *if form*, if the conditional returns a non-boolean value the *while lo
|
||||||
|
|
||||||
**** Let
|
**** Let
|
||||||
*Let* is one of the most powerful forms Relish offers. The first body in a call to let is a list of lists.
|
*Let* is one of the most powerful forms Relish offers. The first body in a call to let is a list of lists.
|
||||||
Specifically, a list of variable declarations that lookf like this: ~(name value)~.
|
Specifically, a list of variable declarations that look like this: ~(name value)~.
|
||||||
|
|
||||||
Each successive variable definition can build off of the last one, like this: ~((step1 "hello") (step2 (concat step1 " ")) (step3 (concat step2 "world")))~.
|
Each successive variable definition can build off of the last one, like this: ~((step1 "hello") (step2 (concat step1 " ")) (step3 (concat step2 "world")))~.
|
||||||
In said example, the resulting value of step3 is "hello world". After the variable declaration list, the next for is one or more unevaluated trees of code to be evaluated.
|
In said example, the resulting value of step3 is "hello world". After the variable declaration list, the next form is one or more unevaluated trees of code to be evaluated.
|
||||||
Here is an example of a complete let statement using hypothetical data and methods:
|
Here is an example of a complete let statement using hypothetical data and methods:
|
||||||
|
|
||||||
#+BEGIN_SRC lisp
|
#+BEGIN_SRC lisp
|
||||||
|
|
|
||||||
143
src/stl/posix.rs
143
src/stl/posix.rs
|
|
@ -22,6 +22,7 @@ use crate::run;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::fs::File;
|
||||||
use std::process::{Command, Child, Stdio};
|
use std::process::{Command, Child, Stdio};
|
||||||
use nix::unistd;
|
use nix::unistd;
|
||||||
use ctrlc;
|
use ctrlc;
|
||||||
|
|
@ -137,13 +138,14 @@ examples:
|
||||||
(l ping -c ping-count google.com))
|
(l ping -c ping-count google.com))
|
||||||
(l emacs -nw (concat HOME '/.relishrc'))
|
(l emacs -nw (concat HOME '/.relishrc'))
|
||||||
";
|
";
|
||||||
|
|
||||||
|
|
||||||
fn load_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result<Ctr, String> {
|
fn load_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result<Ctr, String> {
|
||||||
if ast.is_empty() {
|
if ast.is_empty() {
|
||||||
Err("need at least one argument".to_string())
|
Err("need at least one argument".to_string())
|
||||||
} else {
|
} else {
|
||||||
let mut args = VecDeque::from(args_from_ast(ast, syms));
|
let mut args = VecDeque::from(args_from_ast(ast, syms));
|
||||||
|
if args.is_empty() {
|
||||||
|
Err("empty command".to_string())
|
||||||
|
} else {
|
||||||
if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) {
|
if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) {
|
||||||
launch_command(
|
launch_command(
|
||||||
filepath,
|
filepath,
|
||||||
|
|
@ -160,6 +162,127 @@ fn load_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Resu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: rework this callback to reduce spaghett
|
||||||
|
const LOAD_WITH_DOCSTRING: &str = "";
|
||||||
|
fn load_with_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result<Ctr, String> {
|
||||||
|
if ast.len() != 2 {
|
||||||
|
Err("exactly two arguments needed".to_string())
|
||||||
|
} else {
|
||||||
|
if let Ctr::Seg(ref fd_redirect_forms) = *ast.car {
|
||||||
|
let mut stdout: Option<Stdio> = None;
|
||||||
|
let mut stdin: Option<Stdio> = None;
|
||||||
|
let mut stderr: Option<Stdio> = None;
|
||||||
|
let mut e: Option<String> = None;
|
||||||
|
if !fd_redirect_forms.circuit(&mut |arg: &Ctr| -> bool {
|
||||||
|
// of the form Seg(Str(fd), Seg(Str(filepath)))
|
||||||
|
if let Ctr::Seg(ref io_redir) = arg {
|
||||||
|
if let Ctr::String(ref fd) = *io_redir.car {
|
||||||
|
if let Ctr::Seg(ref io_file) = *io_redir.cdr {
|
||||||
|
if let Ctr::String(ref filename) = *io_file.car {
|
||||||
|
match fd.as_str() {
|
||||||
|
"stdin" => {
|
||||||
|
if !stdin.is_none() {
|
||||||
|
e = Some(format!("stdin already defined"));
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let input = File::open(filename);
|
||||||
|
if !input.is_ok() {
|
||||||
|
e = Some(format!("input file does not exist"));
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
stdin = Some(Stdio::from(input.ok().unwrap()));
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
"stdout" => {
|
||||||
|
if !stdout.is_none() {
|
||||||
|
e = Some(format!("stdout already defined"));
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let out = File::open(filename).or(File::create(filename));
|
||||||
|
if !out.is_ok() {
|
||||||
|
e = Some(out.unwrap_err().to_string());
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
stdout = Some(Stdio::from(out.ok().unwrap()));
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
"stderr" => {
|
||||||
|
if !stderr.is_none() {
|
||||||
|
e = Some(format!("stderr already defined"));
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let err = File::open(filename).or(File::create(filename));
|
||||||
|
if !err.is_ok() {
|
||||||
|
e = Some(err.unwrap_err().to_string());
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
stderr = Some(Stdio::from(err.ok().unwrap()));
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
e = Some(format!("can only override stdin, stdout, or stderr"));
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e = Some(format!("{} is not a string", *io_file.car));
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e = Some(format!("fd override must have both an fd and a filename"));
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e = Some(format!("{} is not a string", *io_redir.car));
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e = Some(format!("not a list: {}", arg));
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return Err(e.unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
// now deal with the actual command
|
||||||
|
if let Ctr::Seg(ref command_forms) = *ast.cdr {
|
||||||
|
let mut args: VecDeque<String>;
|
||||||
|
if let Ctr::Seg(ref command) = *command_forms.car {
|
||||||
|
args = VecDeque::from(args_from_ast(command, syms));
|
||||||
|
} else {
|
||||||
|
return Err("command not list".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.is_empty() {
|
||||||
|
Err("empty command".to_string())
|
||||||
|
} else {
|
||||||
|
if let Some(filepath) = run::find_on_path(args.pop_front().unwrap()) {
|
||||||
|
launch_command(
|
||||||
|
filepath,
|
||||||
|
&Vec::from(args.make_contiguous()),
|
||||||
|
stdin.or(Some(Stdio::inherit())).unwrap(),
|
||||||
|
stdout.or(Some(Stdio::inherit())).unwrap(),
|
||||||
|
stderr.or(Some(Stdio::inherit())).unwrap(),
|
||||||
|
false,
|
||||||
|
state,
|
||||||
|
)?;
|
||||||
|
Ok(Ctr::Integer(state.last_exit_code.into()))
|
||||||
|
} else {
|
||||||
|
Err("file not found".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("second argument expected to be a list of command elements".to_string())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("first argument expected to be a list of lists".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Q_DOCSTRING: &str = "returns exit code of last process to be run in posix layer";
|
const Q_DOCSTRING: &str = "returns exit code of last process to be run in posix layer";
|
||||||
fn q_callback(_ast: &Seg, _syms: &SymTable, state: &mut ShellState) -> Result<Ctr, String> {
|
fn q_callback(_ast: &Seg, _syms: &SymTable, state: &mut ShellState) -> Result<Ctr, String> {
|
||||||
|
|
@ -215,6 +338,7 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
|
||||||
let load_ss = shell_state.clone();
|
let load_ss = shell_state.clone();
|
||||||
let bg_ss = shell_state.clone();
|
let bg_ss = shell_state.clone();
|
||||||
let q_ss = shell_state.clone();
|
let q_ss = shell_state.clone();
|
||||||
|
let lw_ss = shell_state.clone();
|
||||||
|
|
||||||
syms.insert(
|
syms.insert(
|
||||||
String::from("l"),
|
String::from("l"),
|
||||||
|
|
@ -272,6 +396,21 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
syms.insert(
|
||||||
|
String::from("load-with"),
|
||||||
|
Symbol {
|
||||||
|
name: String::from("load-with"),
|
||||||
|
args: Args::Lazy(2),
|
||||||
|
conditional_branches: true,
|
||||||
|
docs: String::from(LOAD_WITH_DOCSTRING),
|
||||||
|
value: ValueType::Internal(Rc::new(move |ast: &Seg, symtable: &mut SymTable| -> Result<Ctr, String> {
|
||||||
|
load_with_callback(ast, symtable, &mut lw_ss.clone().borrow_mut())
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
if let Err(e) = ctrlc::set_handler(move || println!("POSIX layer caught SIG-something")) {
|
if let Err(e) = ctrlc::set_handler(move || println!("POSIX layer caught SIG-something")) {
|
||||||
eprintln!("WARNING: couldn't set sig handler: {}", e);
|
eprintln!("WARNING: couldn't set sig handler: {}", e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue