Merge branch 'cargo-clippy' into 'main'
Readme and clippy cleanups See merge request whom/relish!6
This commit is contained in:
commit
b9414ae4d2
13 changed files with 159 additions and 197 deletions
|
|
@ -25,8 +25,7 @@ The purpose of Relish is to create a highly portable, easy to integrate language
|
||||||
* Contact
|
* Contact
|
||||||
[[https://matrix.to/#/#relish:matrix.sunnypup.io][Matrix chat: #relish:matrix.sunnypup.io]]
|
[[https://matrix.to/#/#relish:matrix.sunnypup.io][Matrix chat: #relish:matrix.sunnypup.io]]
|
||||||
|
|
||||||
If you like Relish and want to support me in working on it consider donating:
|
If you like Relish and want to support me in working on it consider donating: [[https://ko-fi.com/avaaffine][Ava's Ko-Fi]].
|
||||||
https://ko-fi.com/avaaffine
|
|
||||||
|
|
||||||
* Documentation
|
* Documentation
|
||||||
** Writing in Relish
|
** Writing in Relish
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ Readers should be able to run the Relish repl to follow along with this guide an
|
||||||
* Syntax
|
* Syntax
|
||||||
** Data types
|
** Data types
|
||||||
Relish leverages the following data types:
|
Relish leverages the following data types:
|
||||||
- Strings: delimited by ~'~, ~"~, or ~`~
|
- Strings: delimited by one of the following: ~' " `~
|
||||||
- Integers: up to 128 bit signed integers
|
- Integers: up to 128 bit signed integers
|
||||||
- Floats: all floats are stored as 64 bit floats
|
- Floats: all floats are stored as 64 bit floats
|
||||||
- Booleans: ~true~ or ~false~
|
- Booleans: ~true~ or ~false~
|
||||||
- Symbols: an un-delimited chunk of text containing alphanumerics, ~-~, ~_~, or ~?~
|
- Symbols: an un-delimited chunk of text containing alphanumerics or one of the following: ~- _ ?~
|
||||||
|
|
||||||
Symbols and Functions can contain data of any type. there is no immediate restriction on what can be set/passed to what..... However, internally Relish is typed, and many builtin functions will get picky about what types are passed to them.
|
Symbols and Functions can contain data of any type. there is no immediate restriction on what can be set/passed to what..... However, internally Relish is typed, and many builtin functions will get picky about what types are passed to them.
|
||||||
** S-Expressions
|
** S-Expressions
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,10 @@ impl fmt::Display for Traceback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::Into<String> for Traceback {
|
|
||||||
fn into(self) -> String {
|
impl std::convert::From<Traceback> for String {
|
||||||
format!("{}", self)
|
fn from(arg: Traceback) -> Self {
|
||||||
|
format!("{}", arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ pub fn eval(ast: &Seg, syms: &mut SymTable) -> Result<Box<Ctr>, Traceback> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Ctr::Lambda(ref l) => return Ok(call_lambda(l, arg_cdr, syms)?.clone()),
|
Ctr::Lambda(ref l) => return Ok(call_lambda(l, arg_cdr, syms)?),
|
||||||
|
|
||||||
Ctr::Symbol(ref tok) => {
|
Ctr::Symbol(ref tok) => {
|
||||||
let outer_scope_seg_holder: Seg;
|
let outer_scope_seg_holder: Seg;
|
||||||
|
|
|
||||||
|
|
@ -43,14 +43,12 @@ pub fn lex(document: &String) -> Result<Box<Seg>, Traceback> {
|
||||||
let document_normal = document.clone() + " ";
|
let document_normal = document.clone() + " ";
|
||||||
let tree = process(&document_normal);
|
let tree = process(&document_normal);
|
||||||
|
|
||||||
// TODO: Make multiple forms of Ok()
|
match tree {
|
||||||
// To represent the multiple passable outcomes
|
|
||||||
return match tree {
|
|
||||||
Err(e) => Err(start_trace(
|
Err(e) => Err(start_trace(
|
||||||
("<lex>", format!("Problem lexing document: {:?}", e))
|
("<lex>", format!("Problem lexing document: {:?}", e))
|
||||||
.into())),
|
.into())),
|
||||||
Ok(t) => Ok(t),
|
Ok(t) => Ok(t),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The logic used in lex
|
/* The logic used in lex
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ use std::env::{var, current_dir};
|
||||||
|
|
||||||
fn get_paths() -> Vec<String> {
|
fn get_paths() -> Vec<String> {
|
||||||
Vec::from_iter(var("PATH")
|
Vec::from_iter(var("PATH")
|
||||||
.unwrap_or("".to_string().into())
|
.unwrap_or("".to_string())
|
||||||
.split(':')
|
.split(':')
|
||||||
.map(String::from))
|
.map(String::from))
|
||||||
}
|
}
|
||||||
|
|
@ -69,7 +69,7 @@ pub fn run_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
if let Ctr::String(ref filename) = *ast.car {
|
if let Ctr::String(ref filename) = *ast.car {
|
||||||
if filename.ends_with(".rls") {
|
if filename.ends_with(".rls") {
|
||||||
if let Some(filepath) = find_on_path(filename.to_string()) {
|
if let Some(filepath) = find_on_path(filename.to_string()) {
|
||||||
return run(filepath, syms)
|
run(filepath, syms)
|
||||||
.and(Ok(Ctr::None))
|
.and(Ok(Ctr::None))
|
||||||
} else {
|
} else {
|
||||||
let canonical_path_res = fs::canonicalize(filename);
|
let canonical_path_res = fs::canonicalize(filename);
|
||||||
|
|
@ -90,7 +90,7 @@ pub fn run_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
).and(Ok(Ctr::None))
|
).and(Ok(Ctr::None))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(start_trace(
|
Err(start_trace(
|
||||||
("<call script>", "binary called, unimplemented!")
|
("<call script>", "binary called, unimplemented!")
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ Example: (pop (1 2 3)) -> (1 (2 3)).
|
||||||
The head can then be accessed by car and the rest can be accessed by cdr.";
|
The head can then be accessed by car and the rest can be accessed by cdr.";
|
||||||
fn pop_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
fn pop_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
if let Ctr::Seg(ref s) = *ast.car {
|
if let Ctr::Seg(ref s) = *ast.car {
|
||||||
if s.len() < 1 {
|
if s.is_empty() {
|
||||||
return Err(start_trace(("pop", "input is empty").into()));
|
return Err(start_trace(("pop", "input is empty").into()));
|
||||||
}
|
}
|
||||||
let mut ret = Seg::new();
|
let mut ret = Seg::new();
|
||||||
|
|
@ -134,7 +134,7 @@ Example: (dq (1 2 3)) -> (3 (1 2)).
|
||||||
The last element can then be accessed by car and the rest can be accessed by cdr.";
|
The last element can then be accessed by car and the rest can be accessed by cdr.";
|
||||||
fn dequeue_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
fn dequeue_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
if let Ctr::Seg(ref s) = *ast.car {
|
if let Ctr::Seg(ref s) = *ast.car {
|
||||||
if s.len() < 1 {
|
if s.is_empty() {
|
||||||
return Err(start_trace(("dequeue", "expected an input").into()));
|
return Err(start_trace(("dequeue", "expected an input").into()));
|
||||||
}
|
}
|
||||||
let mut rest = Seg::new();
|
let mut rest = Seg::new();
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
name.clone(),
|
name.clone(),
|
||||||
Symbol::from_ast(
|
Symbol::from_ast(
|
||||||
name, &"variable used in let form".to_string(),
|
name, &"variable used in let form".to_string(),
|
||||||
&Seg::from_mono(Box::new(*var_val_res.unwrap().clone())),
|
&Seg::from_mono(Box::new(*var_val_res.unwrap())),
|
||||||
None),
|
None),
|
||||||
);
|
);
|
||||||
locals.push(name.clone());
|
locals.push(name.clone());
|
||||||
|
|
@ -214,7 +214,7 @@ fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
if !eval_forms.circuit(&mut |eval_form: &Ctr| -> bool {
|
if !eval_forms.circuit(&mut |eval_form: &Ctr| -> bool {
|
||||||
let res: Result<Box<Ctr>, Traceback>;
|
let res: Result<Box<Ctr>, Traceback>;
|
||||||
if let Ctr::Seg(ref eval_tree) = eval_form {
|
if let Ctr::Seg(ref eval_tree) = eval_form {
|
||||||
res = eval(&eval_tree, &mut localsyms);
|
res = eval(eval_tree, &mut localsyms);
|
||||||
} else {
|
} else {
|
||||||
let eval_tree = Seg::from_mono(Box::new(eval_form.clone()));
|
let eval_tree = Seg::from_mono(Box::new(eval_form.clone()));
|
||||||
let intermediate = eval(&eval_tree, &mut localsyms);
|
let intermediate = eval(&eval_tree, &mut localsyms);
|
||||||
|
|
@ -234,7 +234,7 @@ fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = res.unwrap().clone();
|
result = res.unwrap();
|
||||||
true
|
true
|
||||||
}) {
|
}) {
|
||||||
assert!(err_trace.depth() > 0);
|
assert!(err_trace.depth() > 0);
|
||||||
|
|
@ -314,7 +314,7 @@ fn while_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(*(result.unwrap()).clone())
|
Ok(*(result.unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
const CIRCUIT_DOCSTRING: &str = "traverses a list of N un-evaluated forms.
|
const CIRCUIT_DOCSTRING: &str = "traverses a list of N un-evaluated forms.
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ fn eval_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
Err(e) => Err(e.with_trace(
|
Err(e) => Err(e.with_trace(
|
||||||
("eval", "evaluation failure")
|
("eval", "evaluation failure")
|
||||||
.into())),
|
.into())),
|
||||||
Ok(s) => Ok(*s.clone()),
|
Ok(s) => Ok(*s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ fn eval_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
Err(e) => Err(e.with_trace(
|
Err(e) => Err(e.with_trace(
|
||||||
("eval", "evaluation failure")
|
("eval", "evaluation failure")
|
||||||
.into())),
|
.into())),
|
||||||
Ok(s) => Ok(*s.clone()),
|
Ok(s) => Ok(*s),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
|
@ -101,7 +101,7 @@ fn help_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
return Err(start_trace(("help", "expected one input").into()));
|
return Err(start_trace(("help", "expected one input").into()));
|
||||||
}
|
}
|
||||||
if let Ctr::Symbol(ref symbol) = *ast.car {
|
if let Ctr::Symbol(ref symbol) = *ast.car {
|
||||||
if let Some(ref sym) = syms.get(symbol) {
|
if let Some(sym) = syms.get(symbol) {
|
||||||
let args_str: String;
|
let args_str: String;
|
||||||
if let ValueType::VarForm(_) = sym.value {
|
if let ValueType::VarForm(_) = sym.value {
|
||||||
args_str = "(its a variable)".to_string();
|
args_str = "(its a variable)".to_string();
|
||||||
|
|
@ -132,17 +132,11 @@ returns true or false according to whether or not the symbol is found in the sym
|
||||||
fn isset_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
fn isset_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
if ast.len() != 1 {
|
if ast.len() != 1 {
|
||||||
Err(start_trace(("set?", "expcted one input").into()))
|
Err(start_trace(("set?", "expcted one input").into()))
|
||||||
} else {
|
} else if let Ctr::Symbol(ref symbol) = *ast.car {
|
||||||
if let Ctr::Symbol(ref symbol) = *ast.car {
|
Ok(Ctr::Bool(syms.get(symbol).is_some()))
|
||||||
if let Some(_) = syms.get(symbol) {
|
|
||||||
Ok(Ctr::Bool(true))
|
|
||||||
} else {
|
|
||||||
Ok(Ctr::Bool(false))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Err(start_trace(("set?", "expected argument to be a input").into()))
|
Err(start_trace(("set?", "expected argument to be a input").into()))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ENV_DOCSTRING: &str = "takes no arguments
|
const ENV_DOCSTRING: &str = "takes no arguments
|
||||||
|
|
@ -166,12 +160,11 @@ fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
let mut variables = vec![];
|
let mut variables = vec![];
|
||||||
for (name, val) in syms.iter() {
|
for (name, val) in syms.iter() {
|
||||||
if let ValueType::VarForm(l) = &val.value {
|
if let ValueType::VarForm(l) = &val.value {
|
||||||
let token: String;
|
let token: String = match l.to_type() {
|
||||||
match l.to_type() {
|
Type::Lambda => format!("{}: <lambda>", name),
|
||||||
Type::Lambda => token = format!("{}: <lambda>", name),
|
Type::Seg => format!("{}: <form>", name),
|
||||||
Type::Seg => token = format!("{}: <form>", name),
|
_ => format!("{}: {}", name, val.value),
|
||||||
_ => token = format!("{}: {}", name, val.value.to_string()),
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if token.len() > v_col_len && token.len() < xdim as usize {
|
if token.len() > v_col_len && token.len() < xdim as usize {
|
||||||
v_col_len = token.len();
|
v_col_len = token.len();
|
||||||
|
|
@ -203,7 +196,7 @@ fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
print!("{:v_col_len$}", var);
|
print!("{:v_col_len$}", var);
|
||||||
col_iter += 1;
|
col_iter += 1;
|
||||||
if col_iter % n_v_cols == 0 {
|
if col_iter % n_v_cols == 0 {
|
||||||
print!("\n");
|
println!();
|
||||||
} else {
|
} else {
|
||||||
print!(" ");
|
print!(" ");
|
||||||
}
|
}
|
||||||
|
|
@ -214,7 +207,7 @@ fn env_callback(_ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
print!("{:f_col_len$}", func);
|
print!("{:f_col_len$}", func);
|
||||||
col_iter += 1;
|
col_iter += 1;
|
||||||
if col_iter % n_f_cols == 0 {
|
if col_iter % n_f_cols == 0 {
|
||||||
print!("\n");
|
println!();
|
||||||
} else {
|
} else {
|
||||||
print!(" ");
|
print!(" ");
|
||||||
}
|
}
|
||||||
|
|
@ -250,8 +243,7 @@ fn lambda_callback(
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Err(start_trace(("lambda", "lambda inputs should all be symbols").into()))
|
Err(start_trace(("lambda", "lambda inputs should all be symbols").into()))
|
||||||
} else {
|
} else if let Ctr::Seg(ref eval_head) = *ast.cdr {
|
||||||
if let Ctr::Seg(ref eval_head) = *ast.cdr {
|
|
||||||
if let Ctr::Seg(_) = *eval_head.car {
|
if let Ctr::Seg(_) = *eval_head.car {
|
||||||
Ok(Ctr::Lambda(UserFn{
|
Ok(Ctr::Lambda(UserFn{
|
||||||
ast: Box::new(eval_head.clone()),
|
ast: Box::new(eval_head.clone()),
|
||||||
|
|
@ -263,7 +255,6 @@ fn lambda_callback(
|
||||||
} else {
|
} else {
|
||||||
Err(start_trace(("lambda", "not enough args").into()))
|
Err(start_trace(("lambda", "not enough args").into()))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Err(start_trace(("lambda", "expected list of lambda inputs").into()))
|
Err(start_trace(("lambda", "expected list of lambda inputs").into()))
|
||||||
}
|
}
|
||||||
|
|
@ -296,8 +287,7 @@ fn setdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("set-doc", "expected two inputs")
|
("set-doc", "expected two inputs")
|
||||||
.into()))
|
.into()))
|
||||||
} else {
|
} else if let Ctr::Symbol(ref symbol) = *ast.car {
|
||||||
if let Ctr::Symbol(ref symbol) = *ast.car {
|
|
||||||
if let Some(mut sym) = syms.remove(symbol) {
|
if let Some(mut sym) = syms.remove(symbol) {
|
||||||
if let Ctr::Seg(ref doc_node) = *ast.cdr {
|
if let Ctr::Seg(ref doc_node) = *ast.cdr {
|
||||||
if let Ctr::String(ref doc) = *doc_node.car {
|
if let Ctr::String(ref doc) = *doc_node.car {
|
||||||
|
|
@ -320,13 +310,11 @@ fn setdoc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
("set-doc", format!("{symbol} is undefined"))
|
("set-doc", format!("{symbol} is undefined"))
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("set-doc", "first input must be a symbol")
|
("set-doc", "first input must be a symbol")
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const STORE_DOCSTRING: &str = "allows user to define functions and variables.
|
const STORE_DOCSTRING: &str = "allows user to define functions and variables.
|
||||||
|
|
@ -377,11 +365,9 @@ fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr,
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(Ctr::None)
|
return Ok(Ctr::None)
|
||||||
} else {
|
} else if ast.len() < 3 || ast.len() > 4 {
|
||||||
if ast.len() < 3 || ast.len() > 4 {
|
|
||||||
return Err(start_trace(("def", "expected 3 or 4 inputs").into()))
|
return Err(start_trace(("def", "expected 3 or 4 inputs").into()))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut iter: &Seg;
|
let mut iter: &Seg;
|
||||||
if let Ctr::Seg(ref s) = *ast.cdr {
|
if let Ctr::Seg(ref s) = *ast.cdr {
|
||||||
|
|
@ -394,7 +380,7 @@ fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr,
|
||||||
Ctr::String(ref s) => docs = s.clone(),
|
Ctr::String(ref s) => docs = s.clone(),
|
||||||
Ctr::Symbol(ref s) => match syms.call_symbol(s, &Seg::new(), true) {
|
Ctr::Symbol(ref s) => match syms.call_symbol(s, &Seg::new(), true) {
|
||||||
Ok(d) => if let Ctr::String(doc) = *d {
|
Ok(d) => if let Ctr::String(doc) = *d {
|
||||||
docs = doc.clone();
|
docs = doc;
|
||||||
} else {
|
} else {
|
||||||
return Err(start_trace(("def", "expected docs input to evaluate to a string").into()))
|
return Err(start_trace(("def", "expected docs input to evaluate to a string").into()))
|
||||||
},
|
},
|
||||||
|
|
@ -432,7 +418,6 @@ fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr,
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_var {
|
if is_var {
|
||||||
let var_val: Ctr;
|
|
||||||
let var_eval_result = eval(var_val_form, syms);
|
let var_eval_result = eval(var_val_form, syms);
|
||||||
if let Err(e) = var_eval_result {
|
if let Err(e) = var_eval_result {
|
||||||
return Err(e.with_trace(
|
return Err(e.with_trace(
|
||||||
|
|
@ -440,11 +425,11 @@ fn store_callback(ast: &Seg, syms: &mut SymTable, env_cfg: bool) -> Result<Ctr,
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
let var_eval_final = *var_eval_result?;
|
let var_eval_final = *var_eval_result?;
|
||||||
match var_eval_final {
|
let var_val: Ctr = match var_eval_final {
|
||||||
Ctr::Seg(ref s) if expand => var_val = *s.car.clone(),
|
Ctr::Seg(ref s) if expand => *s.car.clone(),
|
||||||
Ctr::Seg(ref s) if !expand => var_val = Ctr::Seg(s.clone()),
|
Ctr::Seg(ref s) if !expand => Ctr::Seg(s.clone()),
|
||||||
_ => var_val = var_eval_final,
|
_ => var_eval_final,
|
||||||
}
|
};
|
||||||
|
|
||||||
let outer_seg = Seg::from_mono(Box::new(var_val.clone()));
|
let outer_seg = Seg::from_mono(Box::new(var_val.clone()));
|
||||||
syms.insert(
|
syms.insert(
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,7 @@ use crate::error::{Traceback, start_trace};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn isnumeric(arg: &Ctr) -> bool {
|
fn isnumeric(arg: &Ctr) -> bool {
|
||||||
match arg {
|
matches!(arg, Ctr::Integer(_) | Ctr::Float(_))
|
||||||
Ctr::Integer(_) => true,
|
|
||||||
Ctr::Float(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ADD_DOCSTRING: &str =
|
const ADD_DOCSTRING: &str =
|
||||||
|
|
@ -175,7 +171,7 @@ fn floatcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
if let Ctr::Integer(i) = *ast.car {
|
if let Ctr::Integer(i) = *ast.car {
|
||||||
Ok(Ctr::Float(i as f64))
|
Ok(Ctr::Float(i as f64))
|
||||||
} else if let Ctr::String(ref s) = *ast.car {
|
} else if let Ctr::String(ref s) = *ast.car {
|
||||||
let flt = str::parse::<f64>(&s);
|
let flt = str::parse::<f64>(s);
|
||||||
if flt.is_err() {
|
if flt.is_err() {
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("float", flt.err().unwrap().to_string())
|
("float", flt.err().unwrap().to_string())
|
||||||
|
|
@ -452,7 +448,7 @@ fn inc_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
|
|
||||||
let sym_ret = syms
|
let sym_ret = syms
|
||||||
.remove(&var_name);
|
.remove(&var_name);
|
||||||
if let None = sym_ret {
|
if sym_ret.is_none() {
|
||||||
return Err(start_trace(
|
return Err(start_trace(
|
||||||
("inc", format!("input ({var_name}) is not defined"))
|
("inc", format!("input ({var_name}) is not defined"))
|
||||||
.into()))
|
.into()))
|
||||||
|
|
@ -499,7 +495,7 @@ fn dec_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
|
|
||||||
let sym_ret = syms
|
let sym_ret = syms
|
||||||
.remove(&var_name);
|
.remove(&var_name);
|
||||||
if let None = sym_ret {
|
if sym_ret.is_none() {
|
||||||
return Err(start_trace(
|
return Err(start_trace(
|
||||||
("dec", format!("input ({var_name}) is not defined"))
|
("dec", format!("input ({var_name}) is not defined"))
|
||||||
.into()))
|
.into()))
|
||||||
|
|
|
||||||
|
|
@ -37,10 +37,7 @@ use {
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
cell::{
|
cell::RefCell,
|
||||||
RefCell, RefMut,
|
|
||||||
BorrowMutError,
|
|
||||||
},
|
|
||||||
io::Result as IOResult,
|
io::Result as IOResult,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
fs::{
|
fs::{
|
||||||
|
|
@ -109,9 +106,9 @@ pub fn unign_sigs() {
|
||||||
|
|
||||||
// TODO: trigger this on SIGCHLD instead of traditional shell once per input
|
// TODO: trigger this on SIGCHLD instead of traditional shell once per input
|
||||||
pub fn check_jobs(state: &mut ShellState) {
|
pub fn check_jobs(state: &mut ShellState) {
|
||||||
let mut idx = 0 as usize;
|
let mut idx = 0usize;
|
||||||
while idx < state.children.len() {
|
while idx < state.children.len() {
|
||||||
if let Ok(_) = state.children[idx].try_wait() {
|
if state.children[idx].try_wait().is_ok() {
|
||||||
state.children.remove(idx);
|
state.children.remove(idx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -134,7 +131,7 @@ pub fn args_from_ast(ast: &Seg, syms: &mut SymTable) -> Vec<String> {
|
||||||
match *res_ctr {
|
match *res_ctr {
|
||||||
Ctr::Lambda(_) => false,
|
Ctr::Lambda(_) => false,
|
||||||
Ctr::Seg(_) => false,
|
Ctr::Seg(_) => false,
|
||||||
Ctr::String(s) => args.push(s.clone()) == (),
|
Ctr::String(s) => args.push(s) == (),
|
||||||
_ => args.push(res_ctr.to_string()) == (),
|
_ => args.push(res_ctr.to_string()) == (),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -178,15 +175,13 @@ fn launch_command(
|
||||||
newchld = Command::new(path)
|
newchld = Command::new(path)
|
||||||
.pre_exec(move || -> IOResult<()> {
|
.pre_exec(move || -> IOResult<()> {
|
||||||
let pid = unistd::getpid();
|
let pid = unistd::getpid();
|
||||||
if let Err(_) = unistd::setpgid(pid, pid) {
|
if unistd::setpgid(pid, pid).is_err() {
|
||||||
// crying would be nice... if you had eyes
|
// crying would be nice... if you had eyes
|
||||||
}
|
}
|
||||||
|
|
||||||
if !background {
|
if !background &&unistd::tcsetpgrp(0, pid).is_err() {
|
||||||
if let Err(_) = unistd::tcsetpgrp(0, pid) {
|
|
||||||
// you wish to scream, but fork() has taken from you your throat
|
// you wish to scream, but fork() has taken from you your throat
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unign_sigs();
|
unign_sigs();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -255,8 +250,7 @@ fn make_foreground(pid: u32, state: &mut ShellState) -> Result<(), String>{
|
||||||
|
|
||||||
state.last_exit_code = exit
|
state.last_exit_code = exit
|
||||||
.code()
|
.code()
|
||||||
.or(Some(-1))
|
.unwrap_or(-1);
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -298,8 +292,7 @@ fn load_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Resu
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("load", "empty command")
|
("load", "empty command")
|
||||||
.into()))
|
.into()))
|
||||||
} else {
|
} 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()) {
|
|
||||||
if let Err(e) = launch_command(
|
if let Err(e) = launch_command(
|
||||||
filepath,
|
filepath,
|
||||||
&Vec::from(args.make_contiguous()),
|
&Vec::from(args.make_contiguous()),
|
||||||
|
|
@ -321,7 +314,6 @@ fn load_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Resu
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PIPE_DOCSTRING: &str = "Calls a sequence of shell commands.
|
const PIPE_DOCSTRING: &str = "Calls a sequence of shell commands.
|
||||||
|
|
@ -385,8 +377,7 @@ fn pipe_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Resu
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("pipe", err)
|
("pipe", err)
|
||||||
.into()))
|
.into()))
|
||||||
} else {
|
} else if lastpid > 0 {
|
||||||
if lastpid > 0 {
|
|
||||||
if let Some(pos) = state.children
|
if let Some(pos) = state.children
|
||||||
.iter()
|
.iter()
|
||||||
.position(|x| x.id() == lastpid)
|
.position(|x| x.id() == lastpid)
|
||||||
|
|
@ -396,7 +387,7 @@ fn pipe_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Resu
|
||||||
.expect("failed to wait on last child");
|
.expect("failed to wait on last child");
|
||||||
state.last_exit_code = exit.status
|
state.last_exit_code = exit.status
|
||||||
.code()
|
.code()
|
||||||
.or_else(|| {Some(-1)})
|
.or(Some(-1))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
println!("{}", String::from_utf8_lossy(&exit.stdout));
|
println!("{}", String::from_utf8_lossy(&exit.stdout));
|
||||||
|
|
@ -411,7 +402,6 @@ fn pipe_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Resu
|
||||||
("pipe", "impossible error state".to_string())
|
("pipe", "impossible error state".to_string())
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const LOAD_TO_STRING_DOCSTRING: &str = "Calls a binary off disk with given arguments.
|
const LOAD_TO_STRING_DOCSTRING: &str = "Calls a binary off disk with given arguments.
|
||||||
|
|
@ -437,8 +427,7 @@ fn load_to_string_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellStat
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("load-to-string", "command is empty")
|
("load-to-string", "command is empty")
|
||||||
.into()))
|
.into()))
|
||||||
} else {
|
} 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()) {
|
|
||||||
let res = Command::new(filepath).args(args).output();
|
let res = Command::new(filepath).args(args).output();
|
||||||
if let Ok(output) = res {
|
if let Ok(output) = res {
|
||||||
if let Some(code) = output.status.code() {
|
if let Some(code) = output.status.code() {
|
||||||
|
|
@ -448,7 +437,7 @@ fn load_to_string_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellStat
|
||||||
Ok(Ctr::String(string.trim_end().to_string()))
|
Ok(Ctr::String(string.trim_end().to_string()))
|
||||||
} else {
|
} else {
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("load-to-string", format!("couldn't marshall utf-8 command output into a string"))
|
("load-to-string", "couldn't marshall utf-8 command output into a string")
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -462,7 +451,6 @@ fn load_to_string_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellStat
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: rework this callback to reduce spaghett
|
// TODO: rework this callback to reduce spaghett
|
||||||
|
|
@ -514,7 +502,7 @@ fn load_with_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) ->
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
stdin = Some(Stdio::from(input.ok().unwrap()));
|
stdin = Some(Stdio::from(input.ok().unwrap()));
|
||||||
return true
|
true
|
||||||
},
|
},
|
||||||
"stdout" => {
|
"stdout" => {
|
||||||
if !stdout.is_none() {
|
if !stdout.is_none() {
|
||||||
|
|
@ -531,7 +519,7 @@ fn load_with_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) ->
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
stdout = Some(Stdio::from(out.ok().unwrap()));
|
stdout = Some(Stdio::from(out.ok().unwrap()));
|
||||||
return true
|
true
|
||||||
},
|
},
|
||||||
"stderr" => {
|
"stderr" => {
|
||||||
if !stderr.is_none() {
|
if !stderr.is_none() {
|
||||||
|
|
@ -548,7 +536,7 @@ fn load_with_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) ->
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
stderr = Some(Stdio::from(err.ok().unwrap()));
|
stderr = Some(Stdio::from(err.ok().unwrap()));
|
||||||
return true
|
true
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
e = Some(format!("can only override stdin, stdout, or stderr"));
|
e = Some(format!("can only override stdin, stdout, or stderr"));
|
||||||
|
|
@ -668,8 +656,7 @@ fn bg_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("bg", "empty command")
|
("bg", "empty command")
|
||||||
.into()))
|
.into()))
|
||||||
} else {
|
} 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()) {
|
|
||||||
if let Err(e) = launch_command(
|
if let Err(e) = launch_command(
|
||||||
filepath,
|
filepath,
|
||||||
&Vec::from(args.make_contiguous()),
|
&Vec::from(args.make_contiguous()),
|
||||||
|
|
@ -691,7 +678,6 @@ fn bg_callback(ast: &Seg, syms: &mut SymTable, state: &mut ShellState) -> Result
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FG_DOCSTRING: &str = "takes one argument (an integer).
|
const FG_DOCSTRING: &str = "takes one argument (an integer).
|
||||||
|
|
@ -727,7 +713,7 @@ const CD_DOCSTRING: &str =
|
||||||
fn cd_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
fn cd_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
if let Ctr::String(ref dir) = *ast.car {
|
if let Ctr::String(ref dir) = *ast.car {
|
||||||
let dirp = Path::new(dir);
|
let dirp = Path::new(dir);
|
||||||
if let Err(s) = set_current_dir(&dirp) {
|
if let Err(s) = set_current_dir(dirp) {
|
||||||
Err(start_trace(
|
Err(start_trace(
|
||||||
("cd", s.to_string())
|
("cd", s.to_string())
|
||||||
.into()))
|
.into()))
|
||||||
|
|
@ -746,7 +732,7 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
|
||||||
let pgid_res = unistd::getpgid(Some(pid));
|
let pgid_res = unistd::getpgid(Some(pid));
|
||||||
let sid_res = unistd::getsid(Some(pid));
|
let sid_res = unistd::getsid(Some(pid));
|
||||||
|
|
||||||
if !pgid_res.is_ok() || !sid_res.is_ok() {
|
if pgid_res.is_err() || sid_res.is_err() {
|
||||||
panic!("couldn't get pgid")
|
panic!("couldn't get pgid")
|
||||||
}
|
}
|
||||||
let pgid = pgid_res.ok().unwrap();
|
let pgid = pgid_res.ok().unwrap();
|
||||||
|
|
@ -760,14 +746,14 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
|
||||||
state.parent_sid = sid;
|
state.parent_sid = sid;
|
||||||
if let Ok(attr) = tcgetattr(0) {
|
if let Ok(attr) = tcgetattr(0) {
|
||||||
state.attr = Some(attr.clone());
|
state.attr = Some(attr.clone());
|
||||||
shattr = attr.clone();
|
shattr = attr;
|
||||||
} else {
|
} else {
|
||||||
panic!("couldn't get term attrs");
|
panic!("couldn't get term attrs");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let term_pgrp_res = unistd::tcgetpgrp(0);
|
let term_pgrp_res = unistd::tcgetpgrp(0);
|
||||||
if !term_pgrp_res.is_ok() {
|
if term_pgrp_res.is_err() {
|
||||||
panic!("couldn't get terminal's pgrp: {:?}", term_pgrp_res)
|
panic!("couldn't get terminal's pgrp: {:?}", term_pgrp_res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -898,16 +884,13 @@ pub fn load_posix_shell(syms: &mut SymTable, shell_state: Rc<RefCell<ShellState>
|
||||||
symtable,
|
symtable,
|
||||||
&mut lts_ss
|
&mut lts_ss
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
.or(Ok::<RefMut<'_, ShellState>, BorrowMutError>(
|
.unwrap_or(RefCell::from(ShellState{
|
||||||
RefCell::from(ShellState{
|
|
||||||
parent_pid: pid,
|
parent_pid: pid,
|
||||||
parent_sid: pgid,
|
parent_sid: pgid,
|
||||||
children: vec![],
|
children: vec![],
|
||||||
last_exit_code: 0,
|
last_exit_code: 0,
|
||||||
attr: Some(shattr.clone()),
|
attr: Some(shattr.clone()),
|
||||||
}).borrow_mut()))
|
}).borrow_mut()))
|
||||||
.unwrap()
|
|
||||||
)
|
|
||||||
})),
|
})),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ fn concat_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
match arg {
|
match arg {
|
||||||
// should be a thing here
|
// should be a thing here
|
||||||
Ctr::Symbol(_) => return false,
|
Ctr::Symbol(_) => return false,
|
||||||
Ctr::String(s) => string.push_str(&s),
|
Ctr::String(s) => string.push_str(s),
|
||||||
Ctr::Integer(i) => string.push_str(&i.to_string()),
|
Ctr::Integer(i) => string.push_str(&i.to_string()),
|
||||||
Ctr::Float(f) => string.push_str(&f.to_string()),
|
Ctr::Float(f) => string.push_str(&f.to_string()),
|
||||||
Ctr::Bool(b) => string.push_str(&b.to_string()),
|
Ctr::Bool(b) => string.push_str(&b.to_string()),
|
||||||
|
|
@ -56,7 +56,7 @@ fn concat_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
("concat", "highly suspicious that an input was an unevaluated symbol")
|
("concat", "highly suspicious that an input was an unevaluated symbol")
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
return Ok(Ctr::String(string));
|
Ok(Ctr::String(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
const STRLEN_DOCSTRING: &str = "Takes a single arg of any type.
|
const STRLEN_DOCSTRING: &str = "Takes a single arg of any type.
|
||||||
|
|
@ -147,7 +147,7 @@ fn split_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ctr::String(ref s) = &*second_arg_obj {
|
if let Ctr::String(ref s) = second_arg_obj {
|
||||||
delim_str = s.clone();
|
delim_str = s.clone();
|
||||||
} else {
|
} else {
|
||||||
return Err(start_trace(
|
return Err(start_trace(
|
||||||
|
|
@ -174,7 +174,7 @@ fn input_callback(ast: &Seg, _syms: &mut SymTable) -> Result<Ctr, Traceback> {
|
||||||
io::stdin().read_line(&mut input).expect("couldnt read user input");
|
io::stdin().read_line(&mut input).expect("couldnt read user input");
|
||||||
Ok(Ctr::String(input.trim().to_string()))
|
Ok(Ctr::String(input.trim().to_string()))
|
||||||
} else {
|
} else {
|
||||||
return Err(start_trace(
|
Err(start_trace(
|
||||||
("input", "expected a string input to prompt user with")
|
("input", "expected a string input to prompt user with")
|
||||||
.into()))
|
.into()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,13 +143,13 @@ impl SymTable {
|
||||||
if let ValueType::VarForm(ref val) = symbol.value {
|
if let ValueType::VarForm(ref val) = symbol.value {
|
||||||
match **val {
|
match **val {
|
||||||
Ctr::Lambda(ref l) if call_func => {
|
Ctr::Lambda(ref l) if call_func => {
|
||||||
return call_lambda(
|
call_lambda(
|
||||||
l,
|
l,
|
||||||
&Box::new(Ctr::Seg(args.clone())),
|
&Box::new(Ctr::Seg(args.clone())),
|
||||||
self
|
self
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
_ => return Ok(val.clone()),
|
_ => Ok(val.clone()),
|
||||||
}
|
}
|
||||||
} else if call_func {
|
} else if call_func {
|
||||||
symbol.call(args, self)
|
symbol.call(args, self)
|
||||||
|
|
@ -343,7 +343,7 @@ impl Symbol {
|
||||||
errcon = eval_res.err().unwrap();
|
errcon = eval_res.err().unwrap();
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
outer_scope_seg_storage.append(eval_res.unwrap().clone());
|
outer_scope_seg_storage.append(eval_res.unwrap());
|
||||||
} else if let Ctr::Symbol(ref s) = arg {
|
} else if let Ctr::Symbol(ref s) = arg {
|
||||||
let eval_res = syms.call_symbol(
|
let eval_res = syms.call_symbol(
|
||||||
s,
|
s,
|
||||||
|
|
@ -354,7 +354,7 @@ impl Symbol {
|
||||||
errcon = eval_res.err().unwrap();
|
errcon = eval_res.err().unwrap();
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
outer_scope_seg_storage.append(eval_res.unwrap().clone());
|
outer_scope_seg_storage.append(eval_res.unwrap());
|
||||||
} else {
|
} else {
|
||||||
outer_scope_seg_storage.append(Box::new(arg.clone()));
|
outer_scope_seg_storage.append(Box::new(arg.clone()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue