1use crate::env::StringWrapper;
5use crate::error::ExpansionError;
6use futures_core::future::BoxFuture;
7
8mod assignment;
9mod concat;
10mod double_quoted;
11mod fields;
12mod param_subst;
13mod redirect;
14mod redirect_or_cmd_word;
15mod redirect_or_var_assig;
16
17#[cfg(feature = "conch-parser")]
18pub mod ast_impl;
19
20pub use self::assignment::eval_as_assignment;
21pub use self::concat::concat;
22pub use self::double_quoted::double_quoted;
23pub use self::fields::Fields;
24pub use self::param_subst::{alternative, assign, default, error, len};
25pub use self::param_subst::{
26 remove_largest_prefix, remove_largest_suffix, remove_smallest_prefix, remove_smallest_suffix,
27};
28pub use self::redirect::{
29 redirect_append, redirect_clobber, redirect_dup_read, redirect_dup_write, redirect_heredoc,
30 redirect_read, redirect_readwrite, redirect_write, RedirectAction, RedirectEval,
31};
32pub use self::redirect_or_cmd_word::{
33 eval_redirects_or_cmd_words_with_restorer, EvalRedirectOrCmdWordError, RedirectOrCmdWord,
34};
35pub use self::redirect_or_var_assig::{
36 eval_redirects_or_var_assignments_with_restorer, EvalRedirectOrVarAssigError,
37 RedirectOrVarAssig,
38};
39
40pub trait ParamEval<E: ?Sized> {
42 type EvalResult: StringWrapper;
44
45 fn eval(&self, split_fields_further: bool, env: &E) -> Option<Fields<Self::EvalResult>>;
50
51 fn assig_name(&self) -> Option<Self::EvalResult>;
53}
54
55impl<'a, E: ?Sized, P: ?Sized + ParamEval<E>> ParamEval<E> for &'a P {
56 type EvalResult = P::EvalResult;
57
58 fn eval(&self, split_fields_further: bool, env: &E) -> Option<Fields<Self::EvalResult>> {
59 (**self).eval(split_fields_further, env)
60 }
61
62 fn assig_name(&self) -> Option<Self::EvalResult> {
63 (**self).assig_name()
64 }
65}
66
67pub trait ArithEval<E: ?Sized> {
69 fn eval(&self, env: &mut E) -> Result<isize, ExpansionError>;
74}
75
76impl<'a, T: ?Sized + ArithEval<E>, E: ?Sized> ArithEval<E> for &'a T {
77 fn eval(&self, env: &mut E) -> Result<isize, ExpansionError> {
78 (**self).eval(env)
79 }
80}
81
82#[derive(PartialEq, Eq, Copy, Clone, Debug)]
84pub enum TildeExpansion {
85 None,
87 First,
89 All,
91}
92
93#[derive(PartialEq, Eq, Copy, Clone, Debug)]
95pub struct WordEvalConfig {
96 pub tilde_expansion: TildeExpansion,
98 pub split_fields_further: bool,
100}
101
102pub type WordEvalResult<T, E> = Result<BoxFuture<'static, Fields<T>>, E>;
104
105pub trait WordEval<E: ?Sized> {
107 type EvalResult: StringWrapper;
109 type Error;
111
112 fn eval<'life0, 'life1, 'async_trait>(
121 &'life0 self,
122 env: &'life1 mut E,
123 ) -> BoxFuture<'async_trait, WordEvalResult<Self::EvalResult, Self::Error>>
124 where
125 'life0: 'async_trait,
126 'life1: 'async_trait,
127 Self: 'async_trait,
128 {
129 self.eval_with_config(
130 env,
131 WordEvalConfig {
132 tilde_expansion: TildeExpansion::First,
133 split_fields_further: true,
134 },
135 )
136 }
137
138 fn eval_with_config<'life0, 'life1, 'async_trait>(
147 &'life0 self,
148 env: &'life1 mut E,
149 cfg: WordEvalConfig,
150 ) -> BoxFuture<'async_trait, WordEvalResult<Self::EvalResult, Self::Error>>
151 where
152 'life0: 'async_trait,
153 'life1: 'async_trait,
154 Self: 'async_trait;
155}
156
157impl<'a, T, E> WordEval<E> for &'a T
158where
159 T: ?Sized + WordEval<E>,
160 E: ?Sized,
161{
162 type EvalResult = T::EvalResult;
163 type Error = T::Error;
164
165 fn eval<'life0, 'life1, 'async_trait>(
166 &'life0 self,
167 env: &'life1 mut E,
168 ) -> BoxFuture<'async_trait, WordEvalResult<Self::EvalResult, Self::Error>>
169 where
170 'life0: 'async_trait,
171 'life1: 'async_trait,
172 Self: 'async_trait,
173 {
174 (**self).eval(env)
175 }
176
177 fn eval_with_config<'life0, 'life1, 'async_trait>(
178 &'life0 self,
179 env: &'life1 mut E,
180 cfg: WordEvalConfig,
181 ) -> BoxFuture<'async_trait, WordEvalResult<Self::EvalResult, Self::Error>>
182 where
183 'life0: 'async_trait,
184 'life1: 'async_trait,
185 Self: 'async_trait,
186 {
187 (**self).eval_with_config(env, cfg)
188 }
189}
190
191impl<T, E> WordEval<E> for Box<T>
192where
193 T: ?Sized + WordEval<E>,
194 E: ?Sized,
195{
196 type EvalResult = T::EvalResult;
197 type Error = T::Error;
198
199 fn eval<'life0, 'life1, 'async_trait>(
200 &'life0 self,
201 env: &'life1 mut E,
202 ) -> BoxFuture<'async_trait, WordEvalResult<Self::EvalResult, Self::Error>>
203 where
204 'life0: 'async_trait,
205 'life1: 'async_trait,
206 Self: 'async_trait,
207 {
208 (**self).eval(env)
209 }
210
211 fn eval_with_config<'life0, 'life1, 'async_trait>(
212 &'life0 self,
213 env: &'life1 mut E,
214 cfg: WordEvalConfig,
215 ) -> BoxFuture<'async_trait, WordEvalResult<Self::EvalResult, Self::Error>>
216 where
217 'life0: 'async_trait,
218 'life1: 'async_trait,
219 Self: 'async_trait,
220 {
221 (**self).eval_with_config(env, cfg)
222 }
223}
224
225impl<T, E> WordEval<E> for std::sync::Arc<T>
226where
227 T: ?Sized + WordEval<E>,
228 E: ?Sized,
229{
230 type EvalResult = T::EvalResult;
231 type Error = T::Error;
232
233 fn eval<'life0, 'life1, 'async_trait>(
234 &'life0 self,
235 env: &'life1 mut E,
236 ) -> BoxFuture<'async_trait, WordEvalResult<Self::EvalResult, Self::Error>>
237 where
238 'life0: 'async_trait,
239 'life1: 'async_trait,
240 Self: 'async_trait,
241 {
242 (**self).eval(env)
243 }
244
245 fn eval_with_config<'life0, 'life1, 'async_trait>(
246 &'life0 self,
247 env: &'life1 mut E,
248 cfg: WordEvalConfig,
249 ) -> BoxFuture<'async_trait, WordEvalResult<Self::EvalResult, Self::Error>>
250 where
251 'life0: 'async_trait,
252 'life1: 'async_trait,
253 Self: 'async_trait,
254 {
255 (**self).eval_with_config(env, cfg)
256 }
257}
258
259pub(crate) async fn eval_as_pattern<W, E>(word: W, env: &mut E) -> Result<glob::Pattern, W::Error>
263where
264 W: WordEval<E>,
265 E: ?Sized,
266{
267 let future = word.eval_with_config(
268 env,
269 WordEvalConfig {
270 tilde_expansion: TildeExpansion::First,
271 split_fields_further: false,
272 },
273 );
274
275 let pat = future.await?.await.join();
286 let pat = glob::Pattern::new(pat.as_str())
287 .or_else(|_| glob::Pattern::new(&glob::Pattern::escape(pat.as_str())))
288 .expect("pattern compilation unexpectedly failed");
289 Ok(pat)
290}