Implemented logic for loops and if statements
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
|
||||
use crate::{builtin::{cd::cd, echo::echo, export::export, jobctl::{continue_job, jobs, JobBehavior}, pwd::pwd, shift::shift, source::source}, jobs::{dispatch_job, ChildProc, Job, JobBldr}, libsh::error::ShResult, prelude::*, procio::{IoFrame, IoPipe, IoStack}, state::{self, write_vars}};
|
||||
use crate::{builtin::{cd::cd, echo::echo, export::export, jobctl::{continue_job, jobs, JobBehavior}, pwd::pwd, shift::shift, source::source}, jobs::{dispatch_job, ChildProc, Job, JobBldr, JobStack}, libsh::{error::{ShErrKind, ShResult}, utils::RedirVecUtils}, prelude::*, procio::{IoFrame, IoMode, IoStack}, state::{self, write_vars}};
|
||||
|
||||
use super::{lex::{Span, Tk, TkFlags}, AssignKind, ConjunctNode, ConjunctOp, NdFlags, NdRule, Node, Redir, RedirType};
|
||||
use super::{lex::{Span, Tk, TkFlags}, AssignKind, CondNode, ConjunctNode, ConjunctOp, LoopKind, NdFlags, NdRule, Node, Redir, RedirType};
|
||||
|
||||
pub enum AssignBehavior {
|
||||
Export,
|
||||
@@ -40,13 +40,13 @@ impl ExecArgs {
|
||||
pub struct Dispatcher<'t> {
|
||||
nodes: VecDeque<Node<'t>>,
|
||||
pub io_stack: IoStack,
|
||||
pub curr_job: Option<JobBldr>
|
||||
pub job_stack: JobStack
|
||||
}
|
||||
|
||||
impl<'t> Dispatcher<'t> {
|
||||
pub fn new(nodes: Vec<Node<'t>>) -> Self {
|
||||
let nodes = VecDeque::from(nodes);
|
||||
Self { nodes, io_stack: IoStack::new(), curr_job: None }
|
||||
Self { nodes, io_stack: IoStack::new(), job_stack: JobStack::new() }
|
||||
}
|
||||
pub fn begin_dispatch(&mut self) -> ShResult<()> {
|
||||
flog!(TRACE, "beginning dispatch");
|
||||
@@ -57,8 +57,10 @@ impl<'t> Dispatcher<'t> {
|
||||
}
|
||||
pub fn dispatch_node(&mut self, node: Node<'t>) -> ShResult<()> {
|
||||
match node.class {
|
||||
NdRule::CmdList {..} => self.exec_conjunction(node)?,
|
||||
NdRule::Conjunction {..} => self.exec_conjunction(node)?,
|
||||
NdRule::Pipeline {..} => self.exec_pipeline(node)?,
|
||||
NdRule::IfNode {..} => self.exec_if(node)?,
|
||||
NdRule::LoopNode {..} => self.exec_loop(node)?,
|
||||
NdRule::Command {..} => self.dispatch_cmd(node)?,
|
||||
_ => unreachable!()
|
||||
}
|
||||
@@ -75,7 +77,7 @@ impl<'t> Dispatcher<'t> {
|
||||
}
|
||||
}
|
||||
pub fn exec_conjunction(&mut self, conjunction: Node<'t>) -> ShResult<()> {
|
||||
let NdRule::CmdList { elements } = conjunction.class else {
|
||||
let NdRule::Conjunction { elements } = conjunction.class else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
@@ -93,11 +95,96 @@ impl<'t> Dispatcher<'t> {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn exec_loop(&mut self, loop_stmt: Node<'t>) -> ShResult<()> {
|
||||
let NdRule::LoopNode { kind, cond_node } = loop_stmt.class else {
|
||||
unreachable!();
|
||||
};
|
||||
let keep_going = |kind: LoopKind, status: i32| -> bool {
|
||||
match kind {
|
||||
LoopKind::While => status == 0,
|
||||
LoopKind::Until => status != 0
|
||||
}
|
||||
};
|
||||
|
||||
let io_frame = self.io_stack.pop_frame();
|
||||
let (mut cond_frame,mut body_frame) = io_frame.split_frame();
|
||||
let (in_redirs,out_redirs) = loop_stmt.redirs.split_by_channel();
|
||||
cond_frame.extend(in_redirs);
|
||||
body_frame.extend(out_redirs);
|
||||
|
||||
let CondNode { cond, body } = cond_node;
|
||||
loop {
|
||||
self.io_stack.push(cond_frame.clone());
|
||||
|
||||
if let Err(e) = self.dispatch_node(*cond.clone()) {
|
||||
state::set_status(1);
|
||||
return Err(e.into());
|
||||
}
|
||||
|
||||
let status = state::get_status();
|
||||
if keep_going(kind,status) {
|
||||
self.io_stack.push(body_frame.clone());
|
||||
for node in &body {
|
||||
if let Err(e) = self.dispatch_node(node.clone()) {
|
||||
match e.kind() {
|
||||
ShErrKind::LoopBreak => break,
|
||||
ShErrKind::LoopContinue => continue,
|
||||
_ => return Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn exec_if(&mut self, if_stmt: Node<'t>) -> ShResult<()> {
|
||||
let NdRule::IfNode { cond_nodes, else_block } = if_stmt.class else {
|
||||
unreachable!();
|
||||
};
|
||||
// Pop the current frame and split it
|
||||
let io_frame = self.io_stack.pop_frame();
|
||||
let (mut cond_frame,mut body_frame) = io_frame.split_frame();
|
||||
let (in_redirs,out_redirs) = if_stmt.redirs.split_by_channel();
|
||||
cond_frame.extend(in_redirs); // Condition gets input redirs
|
||||
body_frame.extend(out_redirs); // Body gets output redirs
|
||||
|
||||
for node in cond_nodes {
|
||||
let CondNode { cond, body } = node;
|
||||
self.io_stack.push(cond_frame.clone());
|
||||
|
||||
if let Err(e) = self.dispatch_node(*cond) {
|
||||
state::set_status(1);
|
||||
return Err(e.into());
|
||||
}
|
||||
|
||||
match state::get_status() {
|
||||
0 => {
|
||||
for body_node in body {
|
||||
self.io_stack.push(body_frame.clone());
|
||||
self.dispatch_node(body_node)?;
|
||||
}
|
||||
}
|
||||
_ => continue
|
||||
}
|
||||
}
|
||||
|
||||
if !else_block.is_empty() {
|
||||
for node in else_block {
|
||||
self.io_stack.push(body_frame.clone());
|
||||
self.dispatch_node(node)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn exec_pipeline(&mut self, pipeline: Node<'t>) -> ShResult<()> {
|
||||
let NdRule::Pipeline { cmds, pipe_err } = pipeline.class else {
|
||||
unreachable!()
|
||||
};
|
||||
self.curr_job = Some(JobBldr::new());
|
||||
self.job_stack.new_job();
|
||||
// Zip the commands and their respective pipes into an iterator
|
||||
let pipes_and_cmds = get_pipe_stack(cmds.len())
|
||||
.into_iter()
|
||||
@@ -112,21 +199,18 @@ impl<'t> Dispatcher<'t> {
|
||||
}
|
||||
self.dispatch_node(cmd)?;
|
||||
}
|
||||
let job = self.finalize_job();
|
||||
let job = self.job_stack.finalize_job().unwrap();
|
||||
let is_bg = pipeline.flags.contains(NdFlags::BACKGROUND);
|
||||
dispatch_job(job, is_bg)?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn finalize_job(&mut self) -> Job {
|
||||
self.curr_job.take().unwrap().build()
|
||||
}
|
||||
pub fn exec_builtin(&mut self, mut cmd: Node<'t>) -> ShResult<()> {
|
||||
let NdRule::Command { ref mut assignments, argv } = &mut cmd.class else {
|
||||
unreachable!()
|
||||
};
|
||||
let env_vars_to_unset = self.set_assignments(mem::take(assignments), AssignBehavior::Export);
|
||||
let cmd_raw = cmd.get_command().unwrap();
|
||||
let curr_job_mut = self.curr_job.as_mut().unwrap();
|
||||
let curr_job_mut = self.job_stack.curr_job_mut().unwrap();
|
||||
let io_stack_mut = &mut self.io_stack;
|
||||
|
||||
flog!(TRACE, "doing builtin");
|
||||
@@ -178,7 +262,7 @@ impl<'t> Dispatcher<'t> {
|
||||
run_fork(
|
||||
io_frame,
|
||||
Some(exec_args),
|
||||
self.curr_job.as_mut().unwrap(),
|
||||
self.job_stack.curr_job_mut().unwrap(),
|
||||
def_child_action,
|
||||
def_parent_action
|
||||
)?;
|
||||
@@ -318,9 +402,9 @@ pub fn get_pipe_stack(num_cmds: usize) -> Vec<(Option<Redir>,Option<Redir>)> {
|
||||
if i == num_cmds - 1 {
|
||||
stack.push((prev_read.take(), None));
|
||||
} else {
|
||||
let (rpipe,wpipe) = IoPipe::get_pipes();
|
||||
let r_redir = Redir::new(Box::new(rpipe), RedirType::Input);
|
||||
let w_redir = Redir::new(Box::new(wpipe), RedirType::Output);
|
||||
let (rpipe,wpipe) = IoMode::get_pipes();
|
||||
let r_redir = Redir::new(rpipe, RedirType::Input);
|
||||
let w_redir = Redir::new(wpipe, RedirType::Output);
|
||||
|
||||
// Push (prev_read, Some(w_redir)) and set prev_read to r_redir
|
||||
stack.push((prev_read.take(), Some(w_redir)));
|
||||
|
||||
Reference in New Issue
Block a user