1use crate::Env;
34use crate::semantics::Field;
35use std::ops::Deref;
36use std::ops::DerefMut;
37
38#[derive(Clone, Debug, Eq, PartialEq)]
43pub struct Builtin {
44 pub name: Field,
46
47 pub is_special: bool,
53}
54
55#[derive(Clone, Debug, Eq, PartialEq)]
57#[non_exhaustive]
58pub enum Frame {
59 Loop,
61
62 Subshell,
64
65 Condition,
70
71 Builtin(Builtin),
73
74 DotScript,
76
77 Trap(crate::trap::Condition),
79
80 InitFile,
83}
84
85impl From<Builtin> for Frame {
86 fn from(builtin: Builtin) -> Self {
87 Frame::Builtin(builtin)
88 }
89}
90
91impl From<crate::trap::Condition> for Frame {
92 fn from(condition: crate::trap::Condition) -> Self {
93 Frame::Trap(condition)
94 }
95}
96
97#[derive(Clone, Debug, Default, Eq, PartialEq)]
101pub struct Stack {
102 inner: Vec<Frame>,
103}
104
105impl Deref for Stack {
106 type Target = Vec<Frame>;
107 fn deref(&self) -> &Vec<Frame> {
108 &self.inner
109 }
110}
111
112impl From<Vec<Frame>> for Stack {
113 fn from(vec: Vec<Frame>) -> Self {
114 Stack { inner: vec }
115 }
116}
117
118impl From<Stack> for Vec<Frame> {
119 fn from(vec: Stack) -> Self {
120 vec.inner
121 }
122}
123
124#[derive(Debug)]
128#[must_use = "The frame is popped when the guard is dropped"]
129pub struct StackFrameGuard<'a> {
130 stack: &'a mut Stack,
131}
132
133impl Stack {
134 #[inline]
138 pub fn push(&mut self, frame: Frame) -> StackFrameGuard<'_> {
139 self.inner.push(frame);
140 StackFrameGuard { stack: self }
141 }
142
143 #[inline]
145 pub fn pop(guard: StackFrameGuard<'_>) -> Frame {
146 let frame = guard.stack.inner.pop().unwrap();
147 std::mem::forget(guard);
148 frame
149 }
150
151 #[must_use]
162 pub fn loop_count(&self, max_count: usize) -> usize {
163 fn retains_context(frame: &Frame) -> bool {
164 match frame {
165 Frame::Loop | Frame::Condition | Frame::Builtin(_) => true,
166 Frame::Subshell | Frame::DotScript | Frame::Trap(_) | Frame::InitFile => false,
167 }
168 }
169
170 self.inner
171 .iter()
172 .rev()
173 .take_while(|&frame| retains_context(frame))
174 .filter(|&frame| frame == &Frame::Loop)
175 .take(max_count)
176 .count()
177 }
178
179 #[must_use]
181 pub fn current_builtin(&self) -> Option<&Builtin> {
182 self.inner.iter().rev().find_map(|frame| match frame {
183 Frame::Builtin(builtin) => Some(builtin),
184 _ => None,
185 })
186 }
187}
188
189impl Drop for StackFrameGuard<'_> {
192 fn drop(&mut self) {
193 self.stack.inner.pop().unwrap();
194 }
195}
196
197impl Deref for StackFrameGuard<'_> {
198 type Target = Stack;
199 fn deref(&self) -> &Stack {
200 self.stack
201 }
202}
203
204impl DerefMut for StackFrameGuard<'_> {
205 fn deref_mut(&mut self) -> &mut Stack {
206 self.stack
207 }
208}
209
210#[derive(Debug)]
214#[must_use = "The frame is popped when the guard is dropped"]
215pub struct EnvFrameGuard<'a> {
216 env: &'a mut Env,
217}
218
219impl Env {
220 #[inline]
225 pub fn push_frame(&mut self, frame: Frame) -> EnvFrameGuard<'_> {
226 self.stack.inner.push(frame);
227 EnvFrameGuard { env: self }
228 }
229
230 #[inline]
232 pub fn pop_frame(guard: EnvFrameGuard<'_>) -> Frame {
233 let frame = guard.env.stack.inner.pop().unwrap();
234 std::mem::forget(guard);
235 frame
236 }
237}
238
239impl Drop for EnvFrameGuard<'_> {
242 fn drop(&mut self) {
243 self.env.stack.inner.pop().unwrap();
244 }
245}
246
247impl Deref for EnvFrameGuard<'_> {
248 type Target = Env;
249 fn deref(&self) -> &Env {
250 self.env
251 }
252}
253
254impl DerefMut for EnvFrameGuard<'_> {
255 fn deref_mut(&mut self) -> &mut Env {
256 self.env
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 #[test]
265 fn loop_count_empty() {
266 let stack = Stack::default();
267 assert_eq!(stack.loop_count(usize::MAX), 0);
268 }
269
270 #[test]
271 fn loop_count_with_non_loop_frames() {
272 let mut stack = Stack::default();
273 let mut stack = stack.push(Frame::Builtin(Builtin {
274 name: Field::dummy(""),
275 is_special: false,
276 }));
277 assert_eq!(stack.loop_count(usize::MAX), 0);
278 let stack = stack.push(Frame::Condition);
279 assert_eq!(stack.loop_count(usize::MAX), 0);
280 }
281
282 #[test]
283 fn loop_count_with_one_loop() {
284 let mut stack = Stack::default();
285 let mut stack = stack.push(Frame::Loop);
286 assert_eq!(stack.loop_count(usize::MAX), 1);
287 let stack = stack.push(Frame::Condition);
288 assert_eq!(stack.loop_count(usize::MAX), 1);
289 }
290
291 #[test]
292 fn loop_count_with_two_loops() {
293 let mut stack = Stack::default();
294 let mut stack = stack.push(Frame::Loop);
295 let mut stack = stack.push(Frame::Condition);
296 let mut stack = stack.push(Frame::Loop);
297 assert_eq!(stack.loop_count(usize::MAX), 2);
298 let stack = stack.push(Frame::Condition);
299 assert_eq!(stack.loop_count(usize::MAX), 2);
300 }
301
302 #[test]
303 fn loop_count_with_subshells() {
304 let mut stack = Stack::default();
305 let mut stack = stack.push(Frame::Loop);
306 let mut stack = stack.push(Frame::Subshell);
307 assert_eq!(stack.loop_count(usize::MAX), 0);
308 let mut stack = stack.push(Frame::Loop);
309 assert_eq!(stack.loop_count(usize::MAX), 1);
310 let mut stack = stack.push(Frame::Loop);
311 assert_eq!(stack.loop_count(usize::MAX), 2);
312 let mut stack = stack.push(Frame::Subshell);
313 assert_eq!(stack.loop_count(usize::MAX), 0);
314 let stack = stack.push(Frame::Loop);
315 assert_eq!(stack.loop_count(usize::MAX), 1);
316 }
317
318 #[test]
319 fn loop_count_with_conditions() {
320 let mut stack = Stack::default();
321 let mut stack = stack.push(Frame::Loop);
322 let mut stack = stack.push(Frame::Condition);
323 assert_eq!(stack.loop_count(usize::MAX), 1);
324 let stack = stack.push(Frame::Loop);
325 assert_eq!(stack.loop_count(usize::MAX), 2);
326 }
327
328 #[test]
329 fn loop_count_with_builtins() {
330 let mut stack = Stack::default();
331 let mut stack = stack.push(Frame::Loop);
332 let mut stack = stack.push(Frame::Builtin(Builtin {
333 name: Field::dummy(""),
334 is_special: false,
335 }));
336 assert_eq!(stack.loop_count(usize::MAX), 1);
337 let stack = stack.push(Frame::Loop);
338 assert_eq!(stack.loop_count(usize::MAX), 2);
339 }
340
341 #[test]
342 fn loop_count_with_dot_scripts() {
343 let mut stack = Stack::default();
344 let mut stack = stack.push(Frame::Loop);
345 let mut stack = stack.push(Frame::DotScript);
346 assert_eq!(stack.loop_count(usize::MAX), 0);
347 let mut stack = stack.push(Frame::Loop);
348 assert_eq!(stack.loop_count(usize::MAX), 1);
349 let mut stack = stack.push(Frame::Loop);
350 assert_eq!(stack.loop_count(usize::MAX), 2);
351 let mut stack = stack.push(Frame::DotScript);
352 assert_eq!(stack.loop_count(usize::MAX), 0);
353 let stack = stack.push(Frame::Loop);
354 assert_eq!(stack.loop_count(usize::MAX), 1);
355 }
356
357 #[test]
358 fn loop_count_with_traps() {
359 let mut stack = Stack::default();
360 let mut stack = stack.push(Frame::Loop);
361 let mut stack = stack.push(Frame::Trap(crate::trap::Condition::Exit));
362 assert_eq!(stack.loop_count(usize::MAX), 0);
363 let mut stack = stack.push(Frame::Loop);
364 assert_eq!(stack.loop_count(usize::MAX), 1);
365 let mut stack = stack.push(Frame::Loop);
366 assert_eq!(stack.loop_count(usize::MAX), 2);
367 let mut stack = stack.push(Frame::Trap(crate::trap::Condition::Signal(
368 crate::signal::Number::from_raw_unchecked(1.try_into().unwrap()),
369 )));
370 assert_eq!(stack.loop_count(usize::MAX), 0);
371 let stack = stack.push(Frame::Loop);
372 assert_eq!(stack.loop_count(usize::MAX), 1);
373 }
374
375 #[test]
376 fn loop_count_with_small_max_count() {
377 let mut stack = Stack::default();
378 let mut stack = stack.push(Frame::Loop);
379 let mut stack = stack.push(Frame::Condition);
380 let mut stack = stack.push(Frame::Loop);
381 assert_eq!(stack.loop_count(usize::MAX), 2);
382 assert_eq!(stack.loop_count(3), 2);
383 assert_eq!(stack.loop_count(2), 2);
384 assert_eq!(stack.loop_count(1), 1);
385 assert_eq!(stack.loop_count(0), 0);
386
387 let stack = stack.push(Frame::Loop);
388 assert_eq!(stack.loop_count(4), 3);
389 assert_eq!(stack.loop_count(3), 3);
390 assert_eq!(stack.loop_count(2), 2);
391 }
392
393 #[test]
394 fn current_builtin() {
395 let mut stack = Stack::default();
396 assert_eq!(stack.current_builtin(), None);
397
398 let mut stack = stack.push(Frame::Loop);
399 assert_eq!(stack.current_builtin(), None);
400
401 let builtin = Builtin {
402 name: Field::dummy(""),
403 is_special: false,
404 };
405 let mut stack = stack.push(Frame::Builtin(builtin.clone()));
406 assert_eq!(stack.current_builtin(), Some(&builtin));
407
408 let builtin = Builtin {
409 name: Field::dummy("foo"),
410 is_special: true,
411 };
412 let stack = stack.push(Frame::Builtin(builtin.clone()));
413 assert_eq!(stack.current_builtin(), Some(&builtin));
414 }
415}