From cbcb6eb53ee65710657b2e058d2bfe8c5837a96d Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 17 Jan 2022 16:50:27 -0500 Subject: implement else --- src/parse/ast.rs | 4 ++++ src/runner/mod.rs | 41 +++++++++++++++++++++++++++++++++++------ src/shell.pest | 5 ++++- 3 files changed, 43 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/parse/ast.rs b/src/parse/ast.rs index 9d74331..534c87e 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -42,6 +42,7 @@ pub enum Command { If(Pipeline), While(Pipeline), For(String, Vec), + Else(Option), End, } @@ -70,6 +71,9 @@ impl Command { list.into_inner().map(Word::build_ast).collect(); Self::For(var.as_str().to_string(), vals) } + Rule::control_else => Self::Else( + ty.into_inner().next().map(Pipeline::build_ast), + ), Rule::control_end => Self::End, _ => unreachable!(), } diff --git a/src/runner/mod.rs b/src/runner/mod.rs index 84be9a1..6d3710e 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -41,7 +41,7 @@ impl Stack { fn current_pc(&self, pc: usize) -> bool { match self.top() { - Some(Frame::If(_)) | None => false, + Some(Frame::If(..)) | None => false, Some(Frame::While(_, start) | Frame::For(_, start, _)) => { *start == pc } @@ -52,7 +52,7 @@ impl Stack { for frame in &self.frames { if matches!( frame, - Frame::If(false) + Frame::If(false, ..) | Frame::While(false, ..) | Frame::For(false, ..) ) { @@ -64,7 +64,7 @@ impl Stack { } enum Frame { - If(bool), + If(bool, bool), While(bool, usize), For(bool, usize, Vec), } @@ -104,13 +104,16 @@ async fn run_commands( crate::parse::ast::Command::If(pipeline) => { let should = stack.should_execute(); if !stack.current_pc(pc) { - stack.push(Frame::If(false)); + stack.push(Frame::If(false, false)); } if should { let status = env.latest_status(); run_pipeline(pipeline.clone(), env, shell_write).await?; - if let Some(Frame::If(should)) = stack.top_mut() { + if let Some(Frame::If(should, found)) = stack.top_mut() { *should = env.latest_status().success(); + if *should { + *found = true; + } } else { unreachable!(); } @@ -174,8 +177,34 @@ async fn run_commands( } pc += 1; } + crate::parse::ast::Command::Else(pipeline) => { + let mut top = stack.pop(); + if stack.should_execute() { + if let Frame::If(ref mut should, ref mut found) = top { + if *found { + *should = false; + } else if let Some(pipeline) = pipeline { + let status = env.latest_status(); + run_pipeline(pipeline.clone(), env, shell_write) + .await?; + *should = env.latest_status().success(); + if *should { + *found = true; + } + env.set_status(status); + } else { + *should = true; + *found = true; + } + } else { + todo!(); + } + } + stack.push(top); + pc += 1; + } crate::parse::ast::Command::End => match stack.top() { - Some(Frame::If(_)) => { + Some(Frame::If(..)) => { stack.pop(); pc += 1; } diff --git a/src/shell.pest b/src/shell.pest index fdfb1b1..bb06caa 100644 --- a/src/shell.pest +++ b/src/shell.pest @@ -52,8 +52,11 @@ pipeline = ${ (subshell | exe) ~ (w? ~ "|" ~ w? ~ (subshell | exe))* } control_if = ${ "if" ~ w ~ pipeline } control_while = ${ "while" ~ w ~ pipeline } control_for = ${ "for" ~ w ~ bareword ~ w ~ "in" ~ w ~ list } +control_else = ${ "else" ~ (w ~ "if" ~ w ~ pipeline)? } control_end = ${ "end" } -control = ${ control_if | control_while | control_for | control_end } +control = ${ + control_if | control_while | control_for | control_else | control_end +} command = ${ control | pipeline } commands = ${ command ~ (w? ~ ";" ~ w? ~ command)* } -- cgit v1.2.3-54-g00ecf