use std::fs::File; use std::process::{Command}; use crate::parser::ast::{AndExpression, BreakExpression, CommandValue, Expression, FileSourceExpression, FileTargetExpression, ForExpression, IfExpression, LetExpression, OrExpression, RedirectTargetExpression, Value, WhileExpression}; use crate::parser::vars::{AnyFunction, Context, Variable}; use anyhow::{Result, bail, Context as AnyhowContext}; trait ExecExpression { fn exec(&mut self, ctx: &mut Context) -> Result>; } trait GetValue { fn get(&mut self, ctx: &mut Context) -> Result; } impl GetValue for CommandValue { fn get(self: &mut CommandValue, ctx: &mut Context) -> Result { match self { CommandValue::Value(val) => val.get(ctx), CommandValue::Var(_, _) => bail!("Broken executor") } } } impl GetValue for Value { fn get(self: &mut Value, ctx: &mut Context) -> Result { match self { Value::Literal(str) => { Ok(Variable::String(str.clone())) }, Value::Variable(str) => Ok(ctx.get_var(str).unwrap_or(&mut Variable::String(String::from(""))).clone()), Value::ArrayVariable(str) => Ok(ctx.get_var(str).unwrap_or(&mut Variable::Array(Vec::new())).clone()), Value::Expressions(expressions) => { let mut out = String::new(); ctx.add_scope(); for expr in expressions { let res = expr.exec(ctx)?; match res { None => {}, Some(mut cmd) => { out += &*String::from_utf8_lossy(&cmd.output().with_context(|| "Failed to read output of command")?.stdout); } } } ctx.pop_scope(); Ok(Variable::String(out)) }, Value::Values(vec) | Value::ArrayDefinition(vec) => { let mut out = Vec::new(); for val in vec { out.push(val.get(ctx)?); } Ok(Variable::Array(out)) } Value::ValueFunction(call) => { let args = get_variables(ctx, &mut call.args)?; let func = ctx.get_func(call.name.as_str()).with_context(|| format!("Function {} not found", call.name))?; match func { AnyFunction::Native(func) => { (func.func)(ctx, args) } AnyFunction::UserDefined(_) => todo!("User defined functions are not yet supported") } } } } } fn get_variables(ctx: &mut Context, args: &mut Vec) -> Result> { let mut out = Vec::new(); for arg in args { out.push(arg.get(ctx)?); } Ok(out) } impl ExecExpression for Expression { fn exec(self: &mut Expression, ctx: &mut Context) -> Result> { match self { Expression::LetExpression(expr) => expr.exec(ctx), Expression::Command(expr) => expr.exec(ctx), Expression::JobCommand(_) => todo!("Jobs"), Expression::Function(_) => todo!("Function definition"), Expression::IfExpression(expr) => expr.exec(ctx), Expression::WhileExpression(expr) => expr.exec(ctx), Expression::ForExpression(expr) => expr.exec(ctx), Expression::RedirectTargetExpression(expr) => expr.exec(ctx), Expression::FileTargetExpression(expr) => expr.exec(ctx), Expression::FileSourceExpression(expr) => expr.exec(ctx), Expression::Expressions(expr) => expr.exec(ctx), Expression::OrExpression(expr) => expr.exec(ctx), Expression::AndExpression(expr) => expr.exec(ctx), Expression::BreakExpression(expr) => expr.exec(ctx) } } } impl ExecExpression for Command { fn exec(&mut self, ctx: &mut Context) -> Result> { let overrides = ctx.get_overrides()?; if let Some(stdout) = overrides.stdout { self.stdout(stdout); } if let Some(stderr) = overrides.stderr { self.stderr(stderr); } if let Some(stdin) = overrides.stdin { self.stdin(stdin); } let name = self.get_program().to_str().unwrap_or("unknown").to_string(); let out = self.spawn() .with_context(|| "Failed to spawn process ".to_string() + &name)? .wait() .with_context(|| "Failed to wait for process")?; ctx.set_var(String::from("?"), Variable::I32(out.code().unwrap_or(-1))); Ok(None) } } impl ExecExpression for Option { fn exec(&mut self, ctx: &mut Context) -> Result> { match self { None => Ok(None), Some(cmd) => cmd.exec(ctx) } } } impl ExecExpression for BreakExpression { fn exec(self: &mut BreakExpression, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { ctx.break_num -= 1; return Ok(None) } let val = self.num.get(ctx)?.to_string(); let num: u16 = if !val.is_empty() { val.parse()? } else { 1 }; ctx.break_num = if num == 0 { 1 } else { num }; Ok(None) } } impl ExecExpression for WhileExpression { fn exec(self: &mut WhileExpression, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { ctx.break_num -= 1; return Ok(None) } let mut condition = match self.condition.exec(ctx)? { None => bail!("Invalid while expression"), Some(cmd) => cmd }; ctx.add_scope(); let mut res; loop { let condition_res = condition.exec(ctx)?; let code = ctx.get_last_exit_code().unwrap_or(1); if code == 0 { res = self.contents.exec(ctx)? } else { res = condition_res; break; } if ctx.break_num > 0 { ctx.break_num -= 1; break; } } ctx.pop_scope(); Ok(res) } } impl ExecExpression for ForExpression { fn exec<'a>(&mut self, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { ctx.break_num -= 1; return Ok(None) } let arg_value = self.arg_value.get(ctx)?; let arg_key = match &self.arg_key { None => None, Some(key) => { let mut lkey: Value = key.clone(); let res = lkey.get(ctx)?; Some(res) } }; let mut res: Option = None; let list = self.list.get(ctx)?; fn process(i: usize, val: Variable, ctx: &mut Context, arg_key: &Option, arg_value: &Variable) -> Result<()> { ctx.add_scope(); if let Some(key) = &arg_key { ctx.set_var(key.to_string(), Variable::U64(i as u64)); } ctx.set_var(arg_value.to_string(), val); Ok(()) } match list { Variable::Array(arr) => { if arr.is_empty() { self.else_contents.exec(ctx)?; } else { for (i, val) in arr.iter().enumerate() { process(i, val.clone(), ctx, &arg_key, &arg_value)?; res.exec(ctx)?; res = self.contents.exec(ctx)?; ctx.pop_scope(); if ctx.break_num > 0 { ctx.break_num -= 1; break; } } } }, Variable::String(str) => { if str.is_empty() { self.else_contents.exec(ctx)?; } else { for (i, char) in str.chars().enumerate() { process(i, Variable::String(char.to_string()), ctx, &arg_key, &arg_value)?; res.exec(ctx)?; res = self.contents.exec(ctx)?; ctx.pop_scope(); if ctx.break_num > 0 { ctx.break_num -= 1; break; } } } }, _ => bail!("Invalid for expression") }; Ok(res) } } impl ExecExpression for IfExpression { fn exec(self: &mut IfExpression, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { return Ok(None) } let mut condition = match self.condition.exec(ctx)? { None => bail!("Invalid IF expression"), Some(cmd) => cmd }; ctx.add_scope(); condition.exec(ctx)?; let code = ctx.get_last_exit_code().unwrap_or(1); let res= if code == 0 { self.contents.exec(ctx)? } else { self.else_contents.exec(ctx)? }; ctx.pop_scope(); Ok(res) } } impl ExecExpression for LetExpression { fn exec(self: &mut LetExpression, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { return Ok(None) } let key = self.key.get(ctx)?; let val = self.value.get(ctx)?; ctx.set_var(key.to_string(), val); Ok(None) } } impl ExecExpression for Vec { fn exec(self: &mut Vec, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { return Ok(None) } if self.is_empty() { bail!("Command with 0 length"); } let first = self.get_mut(0).unwrap(); let command_name = first.get(ctx)?.to_string(); let mut cmd = Command::new(command_name); for value in &mut self[1..] { cmd.arg(value.get(ctx)?.to_string()); } Ok(Some(cmd)) } } impl ExecExpression for RedirectTargetExpression { fn exec(self: &mut RedirectTargetExpression, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { return Ok(None) } let (reader, writer) = os_pipe::pipe()?; let mut src = self.source.exec(ctx)?.unwrap(); let mut target = self.target.exec(ctx)?.unwrap(); target.stdin(reader); ctx.add_scope(); ctx.scopes.last_mut().unwrap().stdout_override = Some(writer); src.exec(ctx)?; ctx.pop_scope(); Ok(Some(target)) } } impl ExecExpression for FileTargetExpression { fn exec(self: &mut FileTargetExpression, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { return Ok(None) } let src = &mut self.source; let target = self.target.get(ctx)?; let src = match src { Some(expr) => expr.exec(ctx)?, None => { todo!("Redirect without target file"); } }; let command = match src { Some(mut cmd) => { let file = File::create(target.to_string())?; cmd.stdout(file); cmd }, None => { bail!("Invalid command provided for file target"); } }; Ok(Some(command)) } } impl ExecExpression for FileSourceExpression { fn exec(self: &mut FileSourceExpression, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { return Ok(None) } let source = self.source.get(ctx)?.to_string(); let target = &mut self.target; let target = match target { Some(expr) => expr.exec(ctx)?, None => { Some(Command::new("less")) } }; let mut command = match target { None => { bail!("Invalid command") }, Some(cmd) => cmd }; let source = File::open(source).with_context(|| "Couldn't open file to read")?; command.stdin(source); Ok(Some(command)) } } impl ExecExpression for Vec { fn exec(self: &mut Vec, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { return Ok(None) } let mut last = None; for expr in self { last.exec(ctx)?; last = expr.exec(ctx)?; if ctx.break_num > 0 { return Ok(last) } } Ok(last) } } impl ExecExpression for OrExpression { fn exec(self: &mut OrExpression, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { return Ok(None) } let mut first = match self.first.exec(ctx)? { None => bail!("Invalid OR expression"), Some(cmd) => cmd }; first.exec(ctx)?; let code = ctx.get_last_exit_code().unwrap_or(1); if code == 0 { Ok(Some(first)) } else { self.second.exec(ctx) } } } impl ExecExpression for AndExpression { fn exec(self: &mut AndExpression, ctx: &mut Context) -> Result> { if ctx.break_num > 0 { return Ok(None) } let mut first = match self.first.exec(ctx)? { None => bail!("Invalid AND expression"), Some(cmd) => cmd }; first.exec(ctx)?; let code = ctx.get_last_exit_code().unwrap_or(1); if code == 0 { self.second.exec(ctx) } else { Ok(Some(first)) } } } pub fn exec_tree(tree: Vec, ctx: &mut Context) -> Result<()> { for mut expression in tree { let mut cmd = expression.exec(ctx)?; cmd.exec(ctx)?; if ctx.break_num > 0 { bail!("Too many break statements") } } Ok(()) }