1use std::sync::Arc;
2
3use crate::{
4 ast::Expression,
5 engine::{self, Argument, Stack},
6 DeclId, ShellError, Span, Spanned, Value,
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::Error { error, .. } => return Err(ShellError::clone(error)),
191 _ => {
192 return Err(ShellError::CannotSpreadAsList {
193 span: rest_val.span(),
194 })
195 }
196 }
197 } else {
198 acc.push(rest_val.clone());
199 }
200 }
201 Ok(acc)
202 }
203
204 pub fn get_parser_info<'a>(&self, stack: &'a Stack, name: &str) -> Option<&'a Expression> {
206 self.arguments(stack)
207 .iter()
208 .find_map(|argument| match argument {
209 Argument::ParserInfo {
210 data,
211 name: name_slice,
212 info: expr,
213 } if &data[*name_slice] == name.as_bytes() => Some(expr.as_ref()),
214 _ => None,
215 })
216 }
217
218 pub fn span(&self) -> Span {
220 self.span
221 }
222
223 pub fn leave(&self, stack: &mut Stack) {
225 stack.arguments.leave_frame(self.args_base);
226 }
227}
228
229pub struct CallBuilder {
231 inner: Call,
232}
233
234impl CallBuilder {
235 pub fn add_argument(&mut self, stack: &mut Stack, argument: Argument) -> &mut Self {
237 if self.inner.args_len == 0 {
238 self.inner.args_base = stack.arguments.get_base();
239 }
240 self.inner.args_len += 1;
241 if let Some(span) = argument.span() {
242 self.inner.span = self.inner.span.merge(span);
243 }
244 stack.arguments.push(argument);
245 self
246 }
247
248 pub fn add_positional(&mut self, stack: &mut Stack, span: Span, val: Value) -> &mut Self {
250 self.add_argument(
251 stack,
252 Argument::Positional {
253 span,
254 val,
255 ast: None,
256 },
257 )
258 }
259
260 pub fn add_spread(&mut self, stack: &mut Stack, span: Span, vals: Value) -> &mut Self {
262 self.add_argument(
263 stack,
264 Argument::Spread {
265 span,
266 vals,
267 ast: None,
268 },
269 )
270 }
271
272 pub fn add_flag(
274 &mut self,
275 stack: &mut Stack,
276 name: impl AsRef<str>,
277 short: impl AsRef<str>,
278 span: Span,
279 ) -> &mut Self {
280 let (data, name, short) = data_from_name_and_short(name.as_ref(), short.as_ref());
281 self.add_argument(
282 stack,
283 Argument::Flag {
284 data,
285 name,
286 short,
287 span,
288 },
289 )
290 }
291
292 pub fn add_named(
294 &mut self,
295 stack: &mut Stack,
296 name: impl AsRef<str>,
297 short: impl AsRef<str>,
298 span: Span,
299 val: Value,
300 ) -> &mut Self {
301 let (data, name, short) = data_from_name_and_short(name.as_ref(), short.as_ref());
302 self.add_argument(
303 stack,
304 Argument::Named {
305 data,
306 name,
307 short,
308 span,
309 val,
310 ast: None,
311 },
312 )
313 }
314
315 pub fn finish(&self) -> Call {
320 self.inner.clone()
321 }
322
323 pub fn with<T>(
328 self,
329 stack: &mut Stack,
330 f: impl FnOnce(&mut Stack, &engine::Call<'_>) -> T,
331 ) -> T {
332 let call = engine::Call::from(&self.inner);
333 let result = f(stack, &call);
334 self.inner.leave(stack);
335 result
336 }
337}
338
339fn data_from_name_and_short(name: &str, short: &str) -> (Arc<[u8]>, DataSlice, DataSlice) {
340 let data: Vec<u8> = name.bytes().chain(short.bytes()).collect();
341 let data: Arc<[u8]> = data.into();
342 let name = DataSlice {
343 start: 0,
344 len: name.len().try_into().expect("flag name too big"),
345 };
346 let short = DataSlice {
347 start: name.start.checked_add(name.len).expect("flag name too big"),
348 len: short.len().try_into().expect("flag short name too big"),
349 };
350 (data, name, short)
351}