summaryrefslogtreecommitdiffstats
path: root/src/shell/history/mod.rs
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2022-01-08 19:02:52 -0500
committerJesse Luehrs <doy@tozt.net>2022-01-08 19:02:52 -0500
commit1839a1f5b65c84871de6a547df2192d06ab14092 (patch)
treeed370d2d6fca7c2b3f3aa098f9d521aaeca94778 /src/shell/history/mod.rs
parent96b45b2d3dd1ff0ee9312150f2a642058df7668b (diff)
downloadnbsh-1839a1f5b65c84871de6a547df2192d06ab14092.tar.gz
nbsh-1839a1f5b65c84871de6a547df2192d06ab14092.zip
implement for loops
Diffstat (limited to 'src/shell/history/mod.rs')
-rw-r--r--src/shell/history/mod.rs107
1 files changed, 87 insertions, 20 deletions
diff --git a/src/shell/history/mod.rs b/src/shell/history/mod.rs
index 0caffa6..7b5634d 100644
--- a/src/shell/history/mod.rs
+++ b/src/shell/history/mod.rs
@@ -285,9 +285,31 @@ impl Stack {
self.frames.pop().unwrap()
}
+ fn top(&self) -> Option<&Frame> {
+ self.frames.last()
+ }
+
+ fn top_mut(&mut self) -> Option<&mut Frame> {
+ self.frames.last_mut()
+ }
+
+ fn current_pc(&self, pc: usize) -> bool {
+ match self.top() {
+ Some(Frame::If(_)) | None => false,
+ Some(Frame::While(_, start) | Frame::For(_, start, _)) => {
+ *start == pc
+ }
+ }
+ }
+
fn should_execute(&self) -> bool {
for frame in &self.frames {
- if matches!(frame, Frame::If(false) | Frame::While(_, false)) {
+ if matches!(
+ frame,
+ Frame::If(false)
+ | Frame::While(false, ..)
+ | Frame::For(false, ..)
+ ) {
return false;
}
}
@@ -297,8 +319,8 @@ impl Stack {
enum Frame {
If(bool),
- While(usize, bool),
- For,
+ While(bool, usize),
+ For(bool, usize, Vec<String>),
}
fn run_commands(
@@ -373,39 +395,84 @@ fn run_commands(
pc += 1;
}
crate::parse::ast::Command::If(pipeline) => {
- if stack.should_execute() {
+ let should = stack.should_execute();
+ if !stack.current_pc(pc) {
+ stack.push(Frame::If(false));
+ }
+ if should {
run_pipeline!(pipeline);
+ if let Some(Frame::If(should)) = stack.top_mut() {
+ *should = env.latest_status().success();
+ } else {
+ unreachable!();
+ }
}
- stack.push(Frame::If(env.latest_status().success()));
pc += 1;
}
crate::parse::ast::Command::While(pipeline) => {
- if stack.should_execute() {
+ let should = stack.should_execute();
+ if !stack.current_pc(pc) {
+ stack.push(Frame::While(false, pc));
+ }
+ if should {
run_pipeline!(pipeline);
+ if let Some(Frame::While(should, _)) = stack.top_mut()
+ {
+ *should = env.latest_status().success();
+ } else {
+ unreachable!();
+ }
}
- stack.push(Frame::While(
- pc,
- env.latest_status().success(),
- ));
pc += 1;
}
- crate::parse::ast::Command::For(_var, _pipeline) => {
- todo!();
+ crate::parse::ast::Command::For(var, list) => {
+ let should = stack.should_execute();
+ if !stack.current_pc(pc) {
+ stack.push(Frame::For(
+ false,
+ pc,
+ if stack.should_execute() {
+ list.clone()
+ .into_iter()
+ .map(|w| w.eval(&env))
+ .collect()
+ } else {
+ vec![]
+ },
+ ));
+ }
+ if should {
+ if let Some(Frame::For(should, _, list)) =
+ stack.top_mut()
+ {
+ *should = !list.is_empty();
+ if *should {
+ let val = list.remove(0);
+ env.set_var(var, &val);
+ }
+ } else {
+ unreachable!();
+ }
+ }
+ pc += 1;
}
- crate::parse::ast::Command::End => match stack.pop() {
- Frame::If(_) => {
+ crate::parse::ast::Command::End => match stack.top() {
+ Some(Frame::If(_)) => {
+ stack.pop();
pc += 1;
}
- Frame::While(start, should) => {
- if should {
- pc = start;
+ Some(
+ Frame::While(should, start)
+ | Frame::For(should, start, _),
+ ) => {
+ if *should {
+ pc = *start;
} else {
+ stack.pop();
pc += 1;
}
}
- Frame::For => {
- todo!()
- }
+ None => todo!(),
},
}
}