use crate::args::Args;
use crate::exec::Exec;
use crate::expr::Expr;
use crate::store::Store;
use err_tools::*;
pub enum Statement {
Expr(Expr),
Assign(&'static str, Vec<String>, Args),
For {
vars: Vec<String>,
args: Args,
block: Vec<Statement>,
},
If {
expr: Expr,
block: Vec<Statement>,
else_: Option<Vec<Statement>>,
},
Disown(Exec),
Builtin(&'static str, Args),
}
impl Statement {
pub fn run(&self, s: &mut Store) -> anyhow::Result<bool> {
match self {
Statement::Expr(e) => {
e.run(s)
}
Statement::Assign("let", names, args) => {
let ag = args.run_vec(s, 0)?;
if ag.len() < names.len() {
return e_str("Not enough results for var names");
}
for (n, k) in names.iter().enumerate() {
s.let_set(k.to_string(), ag[n].clone())
}
Ok(true)
}
Statement::Assign("set", names, args) => {
let ag = args.run_vec(s, 0)?;
if ag.len() < names.len() {
return e_str("Not enough results for var names");
}
for (n, k) in names.iter().enumerate() {
s.set(k.to_string(), ag[n].clone())
}
Ok(true)
}
Statement::Assign("push", names, args) => {
let ag = args.run_vec(s, 0)?;
if ag.len() < names.len() {
return e_str("Not enough results for var names");
}
for (n, k) in names.iter().enumerate() {
s.push_set(k.to_string(), ag[n].clone())?;
}
Ok(true)
}
Statement::Assign("export", names, args) => {
let ag = args.run_vec(s, 0)?;
if ag.len() < names.len() {
return e_str("Not enough results for var names");
}
for (n, k) in names.into_iter().enumerate() {
std::env::set_var(k.to_string(), ag[n].to_string());
}
Ok(true)
}
Statement::Assign(a, _, _) => {
println!("Assigner doesn't exist : '{}'", a);
Ok(true)
}
Statement::For { vars, args, block } => {
let mut push_v = Vec::new();
let sc = s.clone();
args.run_push(s, 2, |d| {
push_v.push(d);
if push_v.len() >= vars.len() {
let mut ch = sc.child();
let mut vals = Vec::new();
std::mem::swap(&mut push_v, &mut vals);
let (mut k_it, mut v_it) = (vars.iter(), vals.into_iter());
while let (Some(k), Some(v)) = (k_it.next(), v_it.next()) {
ch.set(k.to_string(), v)
}
run_block(&block, &mut ch)?;
}
Ok(())
})?;
Ok(true)
}
Statement::If { expr, block, else_ } => match expr.run(s)? {
true => run_block(&block, &mut s.child()),
false => match &else_ {
Some(ee) => run_block(&ee, &mut s.child()),
None => Ok(true),
},
},
Statement::Disown(e) => {
let id = e.disown()?;
println!("PID = {}", id);
Ok(true)
}
Statement::Builtin("cd", args) => {
let mut run_res = match args.run_s_vec(s, 1)?.get(0) {
Some(v) => v.to_string(),
None => {
let hm = std::env::var("HOME")?;
std::env::set_current_dir(hm)?;
std::env::set_var("PWD", std::env::current_dir()?);
return Ok(true);
}
};
if let Some('~') = run_res.chars().next() {
let hm = std::env::var("HOME")?;
run_res = run_res.replace('~', &hm);
}
let s2 = glob::glob(&run_res)?
.next()
.e_str("Could not glob arg for cd")??;
std::env::set_current_dir(s2)?;
std::env::set_var("PWD", std::env::current_dir()?);
Ok(true)
}
Statement::Builtin("load", args) => {
let ag = args.run_s_vec(s, 1)?;
for a in ag {
println!("Loading {}", a);
s.source_path(a)?;
}
Ok(true)
}
Statement::Builtin("proglist", args) => {
let ag = args.run_s_vec(s, 1)?;
for a in ag {
let matches = crate::tab_complete::prog_matches(&a);
for m in matches {
println!("--{}", m);
}
}
Ok(true)
}
Statement::Builtin("scope_depth", _) => {
println!("Scope depth = {}", s.scope_depth());
Ok(true)
}
Statement::Builtin("var", args) => {
let dvec = args.run_s_vec(s, 1)?;
s.for_each(|k, v, d| {
for a in &dvec {
if !k.contains(a) {
return;
}
}
println!("{}:{} = {}", d, k, v);
});
Ok(true)
}
Statement::Builtin(b, _) => {
println!("Builtin doesn't exist : '{}'", b);
Ok(true)
}
}
}
}
pub fn run_block(block: &[Statement], store: &mut Store) -> anyhow::Result<bool> {
for st in block {
match st.run(store) {
Ok(_) => {}
Err(e) => {
return Err(e);
}
}
}
Ok(true)
}