conch_runtime_pshaw/spawn/ast_impl/
compound.rs1use crate::env::{
2 ArgumentsEnvironment, AsyncIoEnvironment, EnvRestorer, ExportedVariableEnvironment,
3 FileDescEnvironment, FileDescOpener, LastStatusEnvironment, ReportErrorEnvironment,
4 SubEnvironment, UnsetVariableEnvironment, VariableEnvironment,
5};
6use crate::error::{IsFatalError, RedirectionError};
7use crate::eval::{RedirectEval, WordEval};
8use crate::spawn::{
9 case, for_args, for_loop, if_cmd, loop_cmd, sequence_exact, sequence_slice,
10 spawn_with_local_redirections_and_restorer, subshell, GuardBodyPair, PatternBodyPair, Spawn,
11};
12use crate::{ExitStatus, EXIT_SUCCESS};
13use conch_parser::ast;
14use futures_core::future::BoxFuture;
15
16#[async_trait::async_trait]
17impl<S, R, E> Spawn<E> for ast::CompoundCommand<S, R>
18where
19 S: Send + Sync + Spawn<E>,
20 S::Error: From<RedirectionError> + From<R::Error>,
21 R: Send + Sync + RedirectEval<E, Handle = E::FileHandle>,
22 E: ?Sized
23 + Sync
24 + Send
25 + AsyncIoEnvironment
26 + ExportedVariableEnvironment
27 + FileDescEnvironment
28 + FileDescOpener
29 + UnsetVariableEnvironment,
30 E::FileHandle: Clone + Send + From<E::OpenedFileHandle>,
31 E::IoHandle: Send + From<E::FileHandle>,
32 E::VarName: Send + Clone,
33 E::Var: Send + Clone,
34{
35 type Error = S::Error;
36
37 async fn spawn(&self, env: &mut E) -> Result<BoxFuture<'static, ExitStatus>, Self::Error> {
38 spawn_with_local_redirections_and_restorer(&self.io, &self.kind, &mut EnvRestorer::new(env))
39 .await
40 }
41}
42
43#[async_trait::async_trait]
44impl<V, W, S, E> Spawn<E> for ast::CompoundCommandKind<V, W, S>
45where
46 V: Send + Sync + Clone,
47 W: Sync + WordEval<E>,
48 W::Error: Send + IsFatalError,
49 S: Send + Sync + Spawn<E>,
50 S::Error: From<W::Error> + IsFatalError,
51 E: ?Sized
52 + Send
53 + Sync
54 + ArgumentsEnvironment
55 + LastStatusEnvironment
56 + ReportErrorEnvironment
57 + SubEnvironment
58 + VariableEnvironment,
59 E::Var: Send + From<E::Arg> + From<W::EvalResult>,
60 E::VarName: Send + Clone + From<V>,
61{
62 type Error = S::Error;
63
64 async fn spawn(&self, env: &mut E) -> Result<BoxFuture<'static, ExitStatus>, Self::Error> {
65 use ast::CompoundCommandKind::*;
66 match self {
67 Brace(cmds) => sequence_exact(cmds, env).await,
68
69 If {
70 conditionals,
71 else_branch,
72 } => {
73 if_cmd(
74 conditionals.iter().map(|gbp| GuardBodyPair {
75 guard: sequence_slice(&gbp.guard),
76 body: sequence_slice(&gbp.body),
77 }),
78 else_branch.as_ref().map(|e| sequence_slice(e)),
79 env,
80 )
81 .await
82 }
83
84 For { var, words, body } => match words {
85 Some(words) => for_loop(var.clone().into(), words, sequence_slice(body), env).await,
86 None => for_args(var.clone().into(), sequence_slice(body), env).await,
87 },
88
89 Case { word, arms } => {
90 case(
91 word,
92 arms.iter().map(|pbp| PatternBodyPair {
93 patterns: pbp.patterns.as_slice(),
94 body: sequence_slice(&pbp.body),
95 }),
96 env,
97 )
98 .await
99 }
100
101 While(ast::GuardBodyPair { guard, body }) => spawn_loop(false, guard, body, env).await,
102 Until(ast::GuardBodyPair { guard, body }) => spawn_loop(true, guard, body, env).await,
103
104 Subshell(cmds) => {
105 let ret = subshell(sequence_slice(cmds), env).await;
106 Ok(Box::pin(async move { ret }))
107 }
108 }
109 }
110}
111
112async fn spawn_loop<S, E>(
113 invert_guard_status: bool,
114 guard: &[S],
115 body: &[S],
116 env: &mut E,
117) -> Result<BoxFuture<'static, ExitStatus>, S::Error>
118where
119 S: Send + Sync + Spawn<E>,
120 S::Error: IsFatalError,
121 E: ?Sized + Send + Sync + LastStatusEnvironment + ReportErrorEnvironment,
122{
123 let ret = if guard.is_empty() && body.is_empty() {
124 EXIT_SUCCESS
127 } else {
128 loop_cmd(
129 invert_guard_status,
130 sequence_slice(guard),
131 sequence_slice(body),
132 env,
133 )
134 .await?
135 };
136
137 Ok(Box::pin(async move { ret }))
138}