1use crate::{
2 DeclId, FromValue, ShellError, Span, Value,
3 ast::{self, Expression},
4 ir,
5};
6
7use super::{EngineState, Stack, StateWorkingSet};
8
9#[derive(Debug, Clone)]
13pub struct Call<'a> {
14 pub head: Span,
15 pub decl_id: DeclId,
16 pub inner: CallImpl<'a>,
17}
18
19#[derive(Debug, Clone)]
20pub enum CallImpl<'a> {
21 AstRef(&'a ast::Call),
22 AstBox(Box<ast::Call>),
23 IrRef(&'a ir::Call),
24 IrBox(Box<ir::Call>),
25}
26
27impl Call<'_> {
28 pub fn new(span: Span) -> Self {
31 Call {
34 head: span,
35 decl_id: DeclId::new(0),
36 inner: CallImpl::AstBox(Box::new(ast::Call::new(span))),
37 }
38 }
39
40 pub fn to_owned(&self) -> Call<'static> {
43 Call {
44 head: self.head,
45 decl_id: self.decl_id,
46 inner: self.inner.to_owned(),
47 }
48 }
49
50 pub fn has_flag_const(
52 &self,
53 working_set: &StateWorkingSet,
54 stack: &Stack,
55 flag_name: &str,
56 ) -> Result<bool, ShellError> {
57 match &self.inner {
58 CallImpl::AstRef(call) => call.has_flag_const(working_set, flag_name),
59 CallImpl::AstBox(call) => call.has_flag_const(working_set, flag_name),
60 CallImpl::IrRef(call) => ir_has_flag_const(call, stack, flag_name),
61 CallImpl::IrBox(call) => ir_has_flag_const(call, stack, flag_name),
62 }
63 }
64
65 pub fn get_flag_const<T: FromValue>(
67 &self,
68 working_set: &StateWorkingSet,
69 stack: &Stack,
70 name: &str,
71 ) -> Result<Option<T>, ShellError> {
72 match &self.inner {
73 CallImpl::AstRef(call) => call.get_flag_const(working_set, name),
74 CallImpl::AstBox(call) => call.get_flag_const(working_set, name),
75 CallImpl::IrRef(call) => ir_get_flag_const(call, stack, name),
76 CallImpl::IrBox(call) => ir_get_flag_const(call, stack, name),
77 }
78 }
79
80 pub fn req_const<T: FromValue>(
82 &self,
83 working_set: &StateWorkingSet,
84 stack: &Stack,
85 pos: usize,
86 ) -> Result<T, ShellError> {
87 match &self.inner {
88 CallImpl::AstRef(call) => call.req_const(working_set, pos),
89 CallImpl::AstBox(call) => call.req_const(working_set, pos),
90 CallImpl::IrRef(call) => ir_req_const(call, stack, self.head, pos),
91 CallImpl::IrBox(call) => ir_req_const(call, stack, self.head, pos),
92 }
93 }
94
95 pub fn rest_const<T: FromValue>(
97 &self,
98 working_set: &StateWorkingSet,
99 stack: &Stack,
100 starting_pos: usize,
101 ) -> Result<Vec<T>, ShellError> {
102 match &self.inner {
103 CallImpl::AstRef(call) => call.rest_const(working_set, starting_pos),
104 CallImpl::AstBox(call) => call.rest_const(working_set, starting_pos),
105 CallImpl::IrRef(call) => ir_rest_const(call, stack, starting_pos),
106 CallImpl::IrBox(call) => ir_rest_const(call, stack, starting_pos),
107 }
108 }
109
110 pub fn arguments_span(&self) -> Span {
112 match &self.inner {
113 CallImpl::AstRef(call) => call.arguments_span(),
114 CallImpl::AstBox(call) => call.arguments_span(),
115 CallImpl::IrRef(call) => call.arguments_span(),
116 CallImpl::IrBox(call) => call.arguments_span(),
117 }
118 }
119
120 pub fn span(&self) -> Span {
122 match &self.inner {
123 CallImpl::AstRef(call) => call.span(),
124 CallImpl::AstBox(call) => call.span(),
125 CallImpl::IrRef(call) => call.span(),
126 CallImpl::IrBox(call) => call.span(),
127 }
128 }
129
130 pub fn get_parser_info<'a>(&'a self, stack: &'a Stack, name: &str) -> Option<&'a Expression> {
132 match &self.inner {
133 CallImpl::AstRef(call) => call.get_parser_info(name),
134 CallImpl::AstBox(call) => call.get_parser_info(name),
135 CallImpl::IrRef(call) => call.get_parser_info(stack, name),
136 CallImpl::IrBox(call) => call.get_parser_info(stack, name),
137 }
138 }
139
140 pub fn rest_iter_flattened(
143 &self,
144 engine_state: &EngineState,
145 stack: &mut Stack,
146 eval_expression: fn(
147 &EngineState,
148 &mut Stack,
149 &ast::Expression,
150 ) -> Result<Value, ShellError>,
151 starting_pos: usize,
152 ) -> Result<Vec<Value>, ShellError> {
153 fn by_ast(
154 call: &ast::Call,
155 engine_state: &EngineState,
156 stack: &mut Stack,
157 eval_expression: fn(
158 &EngineState,
159 &mut Stack,
160 &ast::Expression,
161 ) -> Result<Value, ShellError>,
162 starting_pos: usize,
163 ) -> Result<Vec<Value>, ShellError> {
164 call.rest_iter_flattened(starting_pos, |expr| {
165 eval_expression(engine_state, stack, expr)
166 })
167 }
168
169 fn by_ir(
170 call: &ir::Call,
171 stack: &Stack,
172 starting_pos: usize,
173 ) -> Result<Vec<Value>, ShellError> {
174 call.rest_iter_flattened(stack, starting_pos)
175 }
176
177 match &self.inner {
178 CallImpl::AstRef(call) => {
179 by_ast(call, engine_state, stack, eval_expression, starting_pos)
180 }
181 CallImpl::AstBox(call) => {
182 by_ast(call, engine_state, stack, eval_expression, starting_pos)
183 }
184 CallImpl::IrRef(call) => by_ir(call, stack, starting_pos),
185 CallImpl::IrBox(call) => by_ir(call, stack, starting_pos),
186 }
187 }
188
189 pub fn positional_nth<'a>(&'a self, stack: &'a Stack, index: usize) -> Option<&'a Expression> {
193 match &self.inner {
194 CallImpl::AstRef(call) => call.positional_iter().nth(index),
195 CallImpl::AstBox(call) => call.positional_iter().nth(index),
196 CallImpl::IrRef(call) => call.positional_ast(stack, index).map(|arc| arc.as_ref()),
197 CallImpl::IrBox(call) => call.positional_ast(stack, index).map(|arc| arc.as_ref()),
198 }
199 }
200}
201
202impl CallImpl<'_> {
203 pub fn to_owned(&self) -> CallImpl<'static> {
204 match self {
205 CallImpl::AstRef(call) => CallImpl::AstBox(Box::new((*call).clone())),
206 CallImpl::AstBox(call) => CallImpl::AstBox(call.clone()),
207 CallImpl::IrRef(call) => CallImpl::IrBox(Box::new((*call).clone())),
208 CallImpl::IrBox(call) => CallImpl::IrBox(call.clone()),
209 }
210 }
211}
212
213fn ir_has_flag_const(call: &ir::Call, stack: &Stack, flag_name: &str) -> Result<bool, ShellError> {
214 Ok(call
215 .named_iter(stack)
216 .find(|(name, _)| name.item == flag_name)
217 .is_some_and(|(_, value)| !matches!(value, Some(Value::Bool { val: false, .. }))))
218}
219
220fn ir_get_flag_const<T: FromValue>(
221 call: &ir::Call,
222 stack: &Stack,
223 name: &str,
224) -> Result<Option<T>, ShellError> {
225 if let Some(val) = call.get_named_arg(stack, name) {
226 T::from_value(val.clone()).map(Some)
227 } else {
228 Ok(None)
229 }
230}
231
232fn ir_req_const<T: FromValue>(
233 call: &ir::Call,
234 stack: &Stack,
235 head: Span,
236 pos: usize,
237) -> Result<T, ShellError> {
238 let maybe_val = call.positional_nth(stack, pos).cloned();
239 let val = maybe_val.ok_or_else(|| {
240 let max_idx = call.positional_len(stack).checked_sub(1);
241 match max_idx {
242 None => ShellError::AccessEmptyContent { span: head },
243 Some(max_idx) => ShellError::AccessBeyondEnd {
244 max_idx,
245 span: head,
246 },
247 }
248 })?;
249 T::from_value(val)
250}
251
252fn ir_rest_const<T: FromValue>(
253 call: &ir::Call,
254 stack: &Stack,
255 starting_pos: usize,
256) -> Result<Vec<T>, ShellError> {
257 call.rest_iter_flattened(stack, starting_pos)?
258 .into_iter()
259 .map(T::from_value)
260 .collect()
261}
262
263impl<'a> From<&'a ast::Call> for Call<'a> {
264 fn from(call: &'a ast::Call) -> Self {
265 Call {
266 head: call.head,
267 decl_id: call.decl_id,
268 inner: CallImpl::AstRef(call),
269 }
270 }
271}
272
273impl<'a> From<&'a ir::Call> for Call<'a> {
274 fn from(call: &'a ir::Call) -> Self {
275 Call {
276 head: call.head,
277 decl_id: call.decl_id,
278 inner: CallImpl::IrRef(call),
279 }
280 }
281}