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 assert_ast_call(&self) -> Result<&ast::Call, ShellError> {
55 match &self.inner {
56 CallImpl::AstRef(call) => Ok(call),
57 CallImpl::AstBox(call) => Ok(call),
58 _ => Err(ShellError::NushellFailedSpanned {
59 msg: "Can't be used in IR context".into(),
60 label: "this command is not yet supported by IR evaluation".into(),
61 span: self.head,
62 }),
63 }
64 }
65
66 pub fn has_flag_const(
68 &self,
69 working_set: &StateWorkingSet,
70 flag_name: &str,
71 ) -> Result<bool, ShellError> {
72 self.assert_ast_call()?
73 .has_flag_const(working_set, flag_name)
74 }
75
76 pub fn get_flag_const<T: FromValue>(
78 &self,
79 working_set: &StateWorkingSet,
80 name: &str,
81 ) -> Result<Option<T>, ShellError> {
82 self.assert_ast_call()?.get_flag_const(working_set, name)
83 }
84
85 pub fn req_const<T: FromValue>(
87 &self,
88 working_set: &StateWorkingSet,
89 pos: usize,
90 ) -> Result<T, ShellError> {
91 self.assert_ast_call()?.req_const(working_set, pos)
92 }
93
94 pub fn rest_const<T: FromValue>(
96 &self,
97 working_set: &StateWorkingSet,
98 starting_pos: usize,
99 ) -> Result<Vec<T>, ShellError> {
100 self.assert_ast_call()?
101 .rest_const(working_set, starting_pos)
102 }
103
104 pub fn arguments_span(&self) -> Span {
106 match &self.inner {
107 CallImpl::AstRef(call) => call.arguments_span(),
108 CallImpl::AstBox(call) => call.arguments_span(),
109 CallImpl::IrRef(call) => call.arguments_span(),
110 CallImpl::IrBox(call) => call.arguments_span(),
111 }
112 }
113
114 pub fn span(&self) -> Span {
116 match &self.inner {
117 CallImpl::AstRef(call) => call.span(),
118 CallImpl::AstBox(call) => call.span(),
119 CallImpl::IrRef(call) => call.span(),
120 CallImpl::IrBox(call) => call.span(),
121 }
122 }
123
124 pub fn get_parser_info<'a>(&'a self, stack: &'a Stack, name: &str) -> Option<&'a Expression> {
126 match &self.inner {
127 CallImpl::AstRef(call) => call.get_parser_info(name),
128 CallImpl::AstBox(call) => call.get_parser_info(name),
129 CallImpl::IrRef(call) => call.get_parser_info(stack, name),
130 CallImpl::IrBox(call) => call.get_parser_info(stack, name),
131 }
132 }
133
134 pub fn rest_iter_flattened(
137 &self,
138 engine_state: &EngineState,
139 stack: &mut Stack,
140 eval_expression: fn(
141 &EngineState,
142 &mut Stack,
143 &ast::Expression,
144 ) -> Result<Value, ShellError>,
145 starting_pos: usize,
146 ) -> Result<Vec<Value>, ShellError> {
147 fn by_ast(
148 call: &ast::Call,
149 engine_state: &EngineState,
150 stack: &mut Stack,
151 eval_expression: fn(
152 &EngineState,
153 &mut Stack,
154 &ast::Expression,
155 ) -> Result<Value, ShellError>,
156 starting_pos: usize,
157 ) -> Result<Vec<Value>, ShellError> {
158 call.rest_iter_flattened(starting_pos, |expr| {
159 eval_expression(engine_state, stack, expr)
160 })
161 }
162
163 fn by_ir(
164 call: &ir::Call,
165 stack: &Stack,
166 starting_pos: usize,
167 ) -> Result<Vec<Value>, ShellError> {
168 call.rest_iter_flattened(stack, starting_pos)
169 }
170
171 match &self.inner {
172 CallImpl::AstRef(call) => {
173 by_ast(call, engine_state, stack, eval_expression, starting_pos)
174 }
175 CallImpl::AstBox(call) => {
176 by_ast(call, engine_state, stack, eval_expression, starting_pos)
177 }
178 CallImpl::IrRef(call) => by_ir(call, stack, starting_pos),
179 CallImpl::IrBox(call) => by_ir(call, stack, starting_pos),
180 }
181 }
182
183 pub fn positional_nth<'a>(&'a self, stack: &'a Stack, index: usize) -> Option<&'a Expression> {
186 match &self.inner {
187 CallImpl::AstRef(call) => call.positional_nth(index),
188 CallImpl::AstBox(call) => call.positional_nth(index),
189 CallImpl::IrRef(call) => call.positional_ast(stack, index).map(|arc| arc.as_ref()),
190 CallImpl::IrBox(call) => call.positional_ast(stack, index).map(|arc| arc.as_ref()),
191 }
192 }
193}
194
195impl CallImpl<'_> {
196 pub fn to_owned(&self) -> CallImpl<'static> {
197 match self {
198 CallImpl::AstRef(call) => CallImpl::AstBox(Box::new((*call).clone())),
199 CallImpl::AstBox(call) => CallImpl::AstBox(call.clone()),
200 CallImpl::IrRef(call) => CallImpl::IrBox(Box::new((*call).clone())),
201 CallImpl::IrBox(call) => CallImpl::IrBox(call.clone()),
202 }
203 }
204}
205
206impl<'a> From<&'a ast::Call> for Call<'a> {
207 fn from(call: &'a ast::Call) -> Self {
208 Call {
209 head: call.head,
210 decl_id: call.decl_id,
211 inner: CallImpl::AstRef(call),
212 }
213 }
214}
215
216impl<'a> From<&'a ir::Call> for Call<'a> {
217 fn from(call: &'a ir::Call) -> Self {
218 Call {
219 head: call.head,
220 decl_id: call.decl_id,
221 inner: CallImpl::IrRef(call),
222 }
223 }
224}