1use std::sync::Arc;
2
3use crate::{
4 DeclId, ShellError, Span, Spanned, Value,
5 ast::Expression,
6 engine::{self, Argument, Stack},
7};
8
9use super::DataSlice;
10
11#[derive(Debug, Clone)]
13pub struct Call {
14 pub decl_id: DeclId,
16 pub head: Span,
18 pub span: Span,
20 pub args_base: usize,
23 pub args_len: usize,
27}
28
29impl Call {
30 pub fn build(decl_id: DeclId, head: Span) -> CallBuilder {
32 CallBuilder {
33 inner: Call {
34 decl_id,
35 head,
36 span: head,
37 args_base: 0,
38 args_len: 0,
39 },
40 }
41 }
42
43 pub fn arguments<'a>(&self, stack: &'a Stack) -> &'a [Argument] {
45 stack.arguments.get_args(self.args_base, self.args_len)
46 }
47
48 pub fn arguments_span(&self) -> Span {
55 let past = self.head.past();
56 Span::new(past.start, self.span.end)
57 }
58
59 pub fn named_len(&self, stack: &Stack) -> usize {
61 self.arguments(stack)
62 .iter()
63 .filter(|arg| matches!(arg, Argument::Named { .. } | Argument::Flag { .. }))
64 .count()
65 }
66
67 pub fn named_iter<'a>(
69 &'a self,
70 stack: &'a Stack,
71 ) -> impl Iterator<Item = (Spanned<&'a str>, Option<&'a Value>)> + 'a {
72 self.arguments(stack).iter().filter_map(
73 |arg: &Argument| -> Option<(Spanned<&str>, Option<&Value>)> {
74 match arg {
75 Argument::Flag {
76 data, name, span, ..
77 } => Some((
78 Spanned {
79 item: std::str::from_utf8(&data[*name]).expect("invalid arg name"),
80 span: *span,
81 },
82 None,
83 )),
84 Argument::Named {
85 data,
86 name,
87 span,
88 val,
89 ..
90 } => Some((
91 Spanned {
92 item: std::str::from_utf8(&data[*name]).expect("invalid arg name"),
93 span: *span,
94 },
95 Some(val),
96 )),
97 _ => None,
98 }
99 },
100 )
101 }
102
103 pub fn get_named_arg<'a>(&self, stack: &'a Stack, flag_name: &str) -> Option<&'a Value> {
106 self.arguments(stack)
108 .iter()
109 .find_map(|arg: &Argument| -> Option<Option<&Value>> {
110 match arg {
111 Argument::Flag { data, name, .. } if &data[*name] == flag_name.as_bytes() => {
112 Some(None)
113 }
114 Argument::Named {
115 data, name, val, ..
116 } if &data[*name] == flag_name.as_bytes() => Some(Some(val)),
117 _ => None,
118 }
119 })
120 .flatten()
121 }
122
123 pub fn positional_len(&self, stack: &Stack) -> usize {
125 self.arguments(stack)
126 .iter()
127 .filter(|arg| matches!(arg, Argument::Positional { .. }))
128 .count()
129 }
130
131 pub fn positional_iter<'a>(&self, stack: &'a Stack) -> impl Iterator<Item = &'a Value> {
133 self.arguments(stack).iter().filter_map(|arg| match arg {
134 Argument::Positional { val, .. } => Some(val),
135 _ => None,
136 })
137 }
138
139 pub fn positional_nth<'a>(&self, stack: &'a Stack, index: usize) -> Option<&'a Value> {
141 self.positional_iter(stack).nth(index)
142 }
143
144 pub fn positional_ast<'a>(
147 &self,
148 stack: &'a Stack,
149 index: usize,
150 ) -> Option<&'a Arc<Expression>> {
151 self.arguments(stack)
152 .iter()
153 .filter_map(|arg| match arg {
154 Argument::Positional { ast, .. } => Some(ast),
155 _ => None,
156 })
157 .nth(index)
158 .and_then(|option| option.as_ref())
159 }
160
161 pub fn rest_iter<'a>(
164 &self,
165 stack: &'a Stack,
166 start: usize,
167 ) -> impl Iterator<Item = (&'a Value, bool)> + 'a {
168 self.arguments(stack)
169 .iter()
170 .filter_map(|arg| match arg {
171 Argument::Positional { val, .. } => Some((val, false)),
172 Argument::Spread { vals, .. } => Some((vals, true)),
173 _ => None,
174 })
175 .skip(start)
176 }
177
178 pub fn rest_iter_flattened(
181 &self,
182 stack: &Stack,
183 start: usize,
184 ) -> Result<Vec<Value>, ShellError> {
185 let mut acc = vec![];
186 for (rest_val, spread) in self.rest_iter(stack, start) {
187 if spread {
188 match rest_val {
189 Value::List { vals, .. } => acc.extend(vals.iter().cloned()),
190 Value::Nothing { .. } => (),
191 Value::Error { error, .. } => return Err(ShellError::clone(error)),
192 _ => {
193 return Err(ShellError::CannotSpreadAsList {
194 span: rest_val.span(),
195 });
196 }
197 }
198 } else {
199 acc.push(rest_val.clone());
200 }
201 }
202 Ok(acc)
203 }
204
205 pub fn get_parser_info<'a>(&self, stack: &'a Stack, name: &str) -> Option<&'a Expression> {
207 self.arguments(stack)
208 .iter()
209 .find_map(|argument| match argument {
210 Argument::ParserInfo {
211 data,
212 name: name_slice,
213 info: expr,
214 } if &data[*name_slice] == name.as_bytes() => Some(expr.as_ref()),
215 _ => None,
216 })
217 }
218
219 pub fn span(&self) -> Span {
221 self.span
222 }
223
224 pub fn leave(&self, stack: &mut Stack) {
226 stack.arguments.leave_frame(self.args_base);
227 }
228}
229
230pub struct CallBuilder {
232 inner: Call,
233}
234
235impl CallBuilder {
236 pub fn add_argument(&mut self, stack: &mut Stack, argument: Argument) -> &mut Self {
238 if self.inner.args_len == 0 {
239 self.inner.args_base = stack.arguments.get_base();
240 }
241 self.inner.args_len += 1;
242 if let Some(span) = argument.span() {
243 self.inner.span = self.inner.span.merge(span);
244 }
245 stack.arguments.push(argument);
246 self
247 }
248
249 pub fn add_positional(&mut self, stack: &mut Stack, span: Span, val: Value) -> &mut Self {
251 self.add_argument(
252 stack,
253 Argument::Positional {
254 span,
255 val,
256 ast: None,
257 },
258 )
259 }
260
261 pub fn add_spread(&mut self, stack: &mut Stack, span: Span, vals: Value) -> &mut Self {
263 self.add_argument(
264 stack,
265 Argument::Spread {
266 span,
267 vals,
268 ast: None,
269 },
270 )
271 }
272
273 pub fn add_flag(
275 &mut self,
276 stack: &mut Stack,
277 name: impl AsRef<str>,
278 short: impl AsRef<str>,
279 span: Span,
280 ) -> &mut Self {
281 let (data, name, short) = data_from_name_and_short(name.as_ref(), short.as_ref());
282 self.add_argument(
283 stack,
284 Argument::Flag {
285 data,
286 name,
287 short,
288 span,
289 },
290 )
291 }
292
293 pub fn add_named(
295 &mut self,
296 stack: &mut Stack,
297 name: impl AsRef<str>,
298 short: impl AsRef<str>,
299 span: Span,
300 val: Value,
301 ) -> &mut Self {
302 let (data, name, short) = data_from_name_and_short(name.as_ref(), short.as_ref());
303 self.add_argument(
304 stack,
305 Argument::Named {
306 data,
307 name,
308 short,
309 span,
310 val,
311 ast: None,
312 },
313 )
314 }
315
316 pub fn finish(&self) -> Call {
321 self.inner.clone()
322 }
323
324 pub fn with<T>(
329 self,
330 stack: &mut Stack,
331 f: impl FnOnce(&mut Stack, &engine::Call<'_>) -> T,
332 ) -> T {
333 let call = engine::Call::from(&self.inner);
334 let result = f(stack, &call);
335 self.inner.leave(stack);
336 result
337 }
338}
339
340fn data_from_name_and_short(name: &str, short: &str) -> (Arc<[u8]>, DataSlice, DataSlice) {
341 let data: Vec<u8> = name.bytes().chain(short.bytes()).collect();
342 let data: Arc<[u8]> = data.into();
343 let name = DataSlice {
344 start: 0,
345 len: name.len().try_into().expect("flag name too big"),
346 };
347 let short = DataSlice {
348 start: name.start.checked_add(name.len).expect("flag name too big"),
349 len: short.len().try_into().expect("flag short name too big"),
350 };
351 (data, name, short)
352}