1use crate::{
2 ast::{self, Expression},
3 ir, DeclId, FromValue, ShellError, Span, Value,
4};
5
6use super::{EngineState, Stack, StateWorkingSet};
7
8#[derive(Debug, Clone)]
12pub struct Call<'a> {
13 pub head: Span,
14 pub decl_id: DeclId,
15 pub inner: CallImpl<'a>,
16}
17
18#[derive(Debug, Clone)]
19pub enum CallImpl<'a> {
20 AstRef(&'a ast::Call),
21 AstBox(Box<ast::Call>),
22 IrRef(&'a ir::Call),
23 IrBox(Box<ir::Call>),
24}
25
26impl Call<'_> {
27 pub fn new(span: Span) -> Self {
30 Call {
33 head: span,
34 decl_id: DeclId::new(0),
35 inner: CallImpl::AstBox(Box::new(ast::Call::new(span))),
36 }
37 }
38
39 pub fn to_owned(&self) -> Call<'static> {
42 Call {
43 head: self.head,
44 decl_id: self.decl_id,
45 inner: self.inner.to_owned(),
46 }
47 }
48
49 pub fn assert_ast_call(&self) -> Result<&ast::Call, ShellError> {
54 match &self.inner {
55 CallImpl::AstRef(call) => Ok(call),
56 CallImpl::AstBox(call) => Ok(call),
57 _ => Err(ShellError::NushellFailedSpanned {
58 msg: "Can't be used in IR context".into(),
59 label: "this command is not yet supported by IR evaluation".into(),
60 span: self.head,
61 }),
62 }
63 }
64
65 pub fn has_flag_const(
67 &self,
68 working_set: &StateWorkingSet,
69 flag_name: &str,
70 ) -> Result<bool, ShellError> {
71 self.assert_ast_call()?
72 .has_flag_const(working_set, flag_name)
73 }
74
75 pub fn get_flag_const<T: FromValue>(
77 &self,
78 working_set: &StateWorkingSet,
79 name: &str,
80 ) -> Result<Option<T>, ShellError> {
81 self.assert_ast_call()?.get_flag_const(working_set, name)
82 }
83
84 pub fn req_const<T: FromValue>(
86 &self,
87 working_set: &StateWorkingSet,
88 pos: usize,
89 ) -> Result<T, ShellError> {
90 self.assert_ast_call()?.req_const(working_set, pos)
91 }
92
93 pub fn rest_const<T: FromValue>(
95 &self,
96 working_set: &StateWorkingSet,
97 starting_pos: usize,
98 ) -> Result<Vec<T>, ShellError> {
99 self.assert_ast_call()?
100 .rest_const(working_set, starting_pos)
101 }
102
103 pub fn arguments_span(&self) -> Span {
105 match &self.inner {
106 CallImpl::AstRef(call) => call.arguments_span(),
107 CallImpl::AstBox(call) => call.arguments_span(),
108 CallImpl::IrRef(call) => call.arguments_span(),
109 CallImpl::IrBox(call) => call.arguments_span(),
110 }
111 }
112
113 pub fn span(&self) -> Span {
115 match &self.inner {
116 CallImpl::AstRef(call) => call.span(),
117 CallImpl::AstBox(call) => call.span(),
118 CallImpl::IrRef(call) => call.span(),
119 CallImpl::IrBox(call) => call.span(),
120 }
121 }
122
123 pub fn get_parser_info<'a>(&'a self, stack: &'a Stack, name: &str) -> Option<&'a Expression> {
125 match &self.inner {
126 CallImpl::AstRef(call) => call.get_parser_info(name),
127 CallImpl::AstBox(call) => call.get_parser_info(name),
128 CallImpl::IrRef(call) => call.get_parser_info(stack, name),
129 CallImpl::IrBox(call) => call.get_parser_info(stack, name),
130 }
131 }
132
133 pub fn rest_iter_flattened(
136 &self,
137 engine_state: &EngineState,
138 stack: &mut Stack,
139 eval_expression: fn(
140 &EngineState,
141 &mut Stack,
142 &ast::Expression,
143 ) -> Result<Value, ShellError>,
144 starting_pos: usize,
145 ) -> Result<Vec<Value>, ShellError> {
146 fn by_ast(
147 call: &ast::Call,
148 engine_state: &EngineState,
149 stack: &mut Stack,
150 eval_expression: fn(
151 &EngineState,
152 &mut Stack,
153 &ast::Expression,
154 ) -> Result<Value, ShellError>,
155 starting_pos: usize,
156 ) -> Result<Vec<Value>, ShellError> {
157 call.rest_iter_flattened(starting_pos, |expr| {
158 eval_expression(engine_state, stack, expr)
159 })
160 }
161
162 fn by_ir(
163 call: &ir::Call,
164 stack: &Stack,
165 starting_pos: usize,
166 ) -> Result<Vec<Value>, ShellError> {
167 call.rest_iter_flattened(stack, starting_pos)
168 }
169
170 match &self.inner {
171 CallImpl::AstRef(call) => {
172 by_ast(call, engine_state, stack, eval_expression, starting_pos)
173 }
174 CallImpl::AstBox(call) => {
175 by_ast(call, engine_state, stack, eval_expression, starting_pos)
176 }
177 CallImpl::IrRef(call) => by_ir(call, stack, starting_pos),
178 CallImpl::IrBox(call) => by_ir(call, stack, starting_pos),
179 }
180 }
181
182 pub fn positional_nth<'a>(&'a self, stack: &'a Stack, index: usize) -> Option<&'a Expression> {
185 match &self.inner {
186 CallImpl::AstRef(call) => call.positional_nth(index),
187 CallImpl::AstBox(call) => call.positional_nth(index),
188 CallImpl::IrRef(call) => call.positional_ast(stack, index).map(|arc| arc.as_ref()),
189 CallImpl::IrBox(call) => call.positional_ast(stack, index).map(|arc| arc.as_ref()),
190 }
191 }
192}
193
194impl CallImpl<'_> {
195 pub fn to_owned(&self) -> CallImpl<'static> {
196 match self {
197 CallImpl::AstRef(call) => CallImpl::AstBox(Box::new((*call).clone())),
198 CallImpl::AstBox(call) => CallImpl::AstBox(call.clone()),
199 CallImpl::IrRef(call) => CallImpl::IrBox(Box::new((*call).clone())),
200 CallImpl::IrBox(call) => CallImpl::IrBox(call.clone()),
201 }
202 }
203}
204
205impl<'a> From<&'a ast::Call> for Call<'a> {
206 fn from(call: &'a ast::Call) -> Self {
207 Call {
208 head: call.head,
209 decl_id: call.decl_id,
210 inner: CallImpl::AstRef(call),
211 }
212 }
213}
214
215impl<'a> From<&'a ir::Call> for Call<'a> {
216 fn from(call: &'a ir::Call) -> Self {
217 Call {
218 head: call.head,
219 decl_id: call.decl_id,
220 inner: CallImpl::IrRef(call),
221 }
222 }
223}