1use crate::{
3 ast::{
4 eval_operator, Assignment, Bits, Boolean, Call, Comparison, Expr, Expression,
5 ExternalArgument, ListItem, Math, Operator, RecordItem,
6 },
7 debugger::DebugContext,
8 BlockId, Config, GetSpan, Range, Record, ShellError, Span, Value, VarId, ENV_VARIABLE_ID,
9};
10use std::{collections::HashMap, sync::Arc};
11
12pub trait Eval {
14 type State<'a>: Copy + GetSpan;
17
18 type MutState;
21
22 fn eval<D: DebugContext>(
23 state: Self::State<'_>,
24 mut_state: &mut Self::MutState,
25 expr: &Expression,
26 ) -> Result<Value, ShellError> {
27 let expr_span = expr.span(&state);
28
29 match &expr.expr {
30 Expr::AttributeBlock(ab) => Self::eval::<D>(state, mut_state, &ab.item),
31 Expr::Bool(b) => Ok(Value::bool(*b, expr_span)),
32 Expr::Int(i) => Ok(Value::int(*i, expr_span)),
33 Expr::Float(f) => Ok(Value::float(*f, expr_span)),
34 Expr::Binary(b) => Ok(Value::binary(b.clone(), expr_span)),
35 Expr::Filepath(path, quoted) => Self::eval_filepath(state, mut_state, path.clone(), *quoted, expr_span),
36 Expr::Directory(path, quoted) => {
37 Self::eval_directory(state, mut_state, path.clone(), *quoted, expr_span)
38 }
39 Expr::Var(var_id) => Self::eval_var(state, mut_state, *var_id, expr_span),
40 Expr::CellPath(cell_path) => Ok(Value::cell_path(cell_path.clone(), expr_span)),
41 Expr::FullCellPath(cell_path) => {
42 let value = Self::eval::<D>(state, mut_state, &cell_path.head)?;
43
44 if cell_path.head.expr == Expr::Var(ENV_VARIABLE_ID) {
47 value.follow_cell_path(&cell_path.tail, true)
48 } else {
49 value.follow_cell_path(&cell_path.tail, false)
50 }
51 }
52 Expr::DateTime(dt) => Ok(Value::date(*dt, expr_span)),
53 Expr::List(list) => {
54 let mut output = vec![];
55 for item in list {
56 match item {
57 ListItem::Item(expr) => output.push(Self::eval::<D>(state, mut_state, expr)?),
58 ListItem::Spread(_, expr) => match Self::eval::<D>(state, mut_state, expr)? {
59 Value::List { vals, .. } => output.extend(vals),
60 _ => return Err(ShellError::CannotSpreadAsList { span: expr_span }),
61 },
62 }
63 }
64 Ok(Value::list(output, expr_span))
65 }
66 Expr::Record(items) => {
67 let mut record = Record::new();
68 let mut col_names = HashMap::new();
69 for item in items {
70 match item {
71 RecordItem::Pair(col, val) => {
72 let col_name = Self::eval::<D>(state, mut_state, col)?.coerce_into_string()?;
74 let col_span = col.span(&state);
75 if let Some(orig_span) = col_names.get(&col_name) {
76 return Err(ShellError::ColumnDefinedTwice {
77 col_name,
78 second_use: col_span,
79 first_use: *orig_span,
80 });
81 } else {
82 col_names.insert(col_name.clone(), col_span);
83 record.push(col_name, Self::eval::<D>(state, mut_state, val)?);
84 }
85 }
86 RecordItem::Spread(_, inner) => {
87 let inner_span = inner.span(&state);
88 match Self::eval::<D>(state, mut_state, inner)? {
89 Value::Record { val: inner_val, .. } => {
90 for (col_name, val) in inner_val.into_owned() {
91 if let Some(orig_span) = col_names.get(&col_name) {
92 return Err(ShellError::ColumnDefinedTwice {
93 col_name,
94 second_use: inner_span,
95 first_use: *orig_span,
96 });
97 } else {
98 col_names.insert(col_name.clone(), inner_span);
99 record.push(col_name, val);
100 }
101 }
102 }
103 _ => {
104 return Err(ShellError::CannotSpreadAsRecord {
105 span: inner_span,
106 })
107 }
108 }
109 }
110 }
111 }
112
113 Ok(Value::record(record, expr_span))
114 }
115 Expr::Table(table) => {
116 let mut output_headers = vec![];
117 for expr in table.columns.as_ref() {
118 let header = Self::eval::<D>(state, mut_state, expr)?.coerce_into_string()?;
119 if let Some(idx) = output_headers
120 .iter()
121 .position(|existing| existing == &header)
122 {
123 let first_use = table.columns[idx].span(&state);
124 return Err(ShellError::ColumnDefinedTwice {
125 col_name: header,
126 second_use: expr_span,
127 first_use,
128 });
129 } else {
130 output_headers.push(header);
131 }
132 }
133
134 let mut output_rows = vec![];
135 for val in table.rows.as_ref() {
136 let record = output_headers.iter().zip(val.as_ref()).map(|(col, expr)| {
137 Self::eval::<D>(state, mut_state, expr).map(|val| (col.clone(), val))
138 }).collect::<Result<_,_>>()?;
139
140 output_rows.push(Value::record(
141 record,
142 expr_span,
143 ));
144 }
145 Ok(Value::list(output_rows, expr_span))
146 }
147 Expr::Keyword(kw) => Self::eval::<D>(state, mut_state, &kw.expr),
148 Expr::String(s) | Expr::RawString(s) => Ok(Value::string(s.clone(), expr_span)),
149 Expr::Nothing => Ok(Value::nothing(expr_span)),
150 Expr::ValueWithUnit(value) => match Self::eval::<D>(state, mut_state, &value.expr)? {
151 Value::Int { val, .. } => value.unit.item.build_value(val, value.unit.span),
152 x => Err(ShellError::CantConvert {
153 to_type: "unit value".into(),
154 from_type: x.get_type().to_string(),
155 span: value.expr.span(&state),
156 help: None,
157 }),
158 },
159 Expr::Call(call) => Self::eval_call::<D>(state, mut_state, call, expr_span),
160 Expr::ExternalCall(head, args) => {
161 Self::eval_external_call(state, mut_state, head, args, expr_span)
162 }
163 Expr::Collect(var_id, expr) => {
164 Self::eval_collect::<D>(state, mut_state, *var_id, expr)
165 }
166 Expr::Subexpression(block_id) => {
167 Self::eval_subexpression::<D>(state, mut_state, *block_id, expr_span)
168 }
169 Expr::Range(range) => {
170 let from = if let Some(f) = &range.from {
171 Self::eval::<D>(state, mut_state, f)?
172 } else {
173 Value::nothing(expr_span)
174 };
175
176 let next = if let Some(s) = &range.next {
177 Self::eval::<D>(state, mut_state, s)?
178 } else {
179 Value::nothing(expr_span)
180 };
181
182 let to = if let Some(t) = &range.to {
183 Self::eval::<D>(state, mut_state, t)?
184 } else {
185 Value::nothing(expr_span)
186 };
187
188 Ok(Value::range(
189 Range::new(from, next, to, range.operator.inclusion, expr_span)?,
190 expr_span,
191 ))
192 }
193 Expr::UnaryNot(expr) => {
194 let lhs = Self::eval::<D>(state, mut_state, expr)?;
195 match lhs {
196 Value::Bool { val, .. } => Ok(Value::bool(!val, expr_span)),
197 other => Err(ShellError::TypeMismatch {
198 err_message: format!("expected bool, found {}", other.get_type()),
199 span: expr_span,
200 }),
201 }
202 }
203 Expr::BinaryOp(lhs, op, rhs) => {
204 let op_span = op.span(&state);
205 let op = eval_operator(op)?;
206
207 match op {
208 Operator::Boolean(boolean) => {
209 let lhs = Self::eval::<D>(state, mut_state, lhs)?;
210 match boolean {
211 Boolean::And => {
212 if lhs.is_false() {
213 Ok(Value::bool(false, expr_span))
214 } else {
215 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
216 lhs.and(op_span, &rhs, expr_span)
217 }
218 }
219 Boolean::Or => {
220 if lhs.is_true() {
221 Ok(Value::bool(true, expr_span))
222 } else {
223 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
224 lhs.or(op_span, &rhs, expr_span)
225 }
226 }
227 Boolean::Xor => {
228 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
229 lhs.xor(op_span, &rhs, expr_span)
230 }
231 }
232 }
233 Operator::Math(math) => {
234 let lhs = Self::eval::<D>(state, mut_state, lhs)?;
235 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
236
237 match math {
238 Math::Add => lhs.add(op_span, &rhs, expr_span),
239 Math::Subtract => lhs.sub(op_span, &rhs, expr_span),
240 Math::Multiply => lhs.mul(op_span, &rhs, expr_span),
241 Math::Divide => lhs.div(op_span, &rhs, expr_span),
242 Math::FloorDivide => lhs.floor_div(op_span, &rhs, expr_span),
243 Math::Modulo => lhs.modulo(op_span, &rhs, expr_span),
244 Math::Pow => lhs.pow(op_span, &rhs, expr_span),
245 Math::Concatenate => lhs.concat(op_span, &rhs, expr_span),
246 }
247 }
248 Operator::Comparison(comparison) => {
249 let lhs = Self::eval::<D>(state, mut_state, lhs)?;
250 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
251 match comparison {
252 Comparison::LessThan => lhs.lt(op_span, &rhs, expr_span),
253 Comparison::LessThanOrEqual => lhs.lte(op_span, &rhs, expr_span),
254 Comparison::GreaterThan => lhs.gt(op_span, &rhs, expr_span),
255 Comparison::GreaterThanOrEqual => lhs.gte(op_span, &rhs, expr_span),
256 Comparison::Equal => lhs.eq(op_span, &rhs, expr_span),
257 Comparison::NotEqual => lhs.ne(op_span, &rhs, expr_span),
258 Comparison::In => lhs.r#in(op_span, &rhs, expr_span),
259 Comparison::NotIn => lhs.not_in(op_span, &rhs, expr_span),
260 Comparison::Has => lhs.has(op_span, &rhs, expr_span),
261 Comparison::NotHas => lhs.not_has(op_span, &rhs, expr_span),
262 Comparison::StartsWith => lhs.starts_with(op_span, &rhs, expr_span),
263 Comparison::EndsWith => lhs.ends_with(op_span, &rhs, expr_span),
264 Comparison::RegexMatch => {
265 Self::regex_match(state, op_span, &lhs, &rhs, false, expr_span)
266 }
267 Comparison::NotRegexMatch => {
268 Self::regex_match(state, op_span, &lhs, &rhs, true, expr_span)
269 }
270 }
271 }
272 Operator::Bits(bits) => {
273 let lhs = Self::eval::<D>(state, mut_state, lhs)?;
274 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
275 match bits {
276 Bits::BitAnd => lhs.bit_and(op_span, &rhs, expr_span),
277 Bits::BitOr => lhs.bit_or(op_span, &rhs, expr_span),
278 Bits::BitXor => lhs.bit_xor(op_span, &rhs, expr_span),
279 Bits::ShiftLeft => lhs.bit_shl(op_span, &rhs, expr_span),
280 Bits::ShiftRight => lhs.bit_shr(op_span, &rhs, expr_span),
281 }
282 }
283 Operator::Assignment(assignment) => Self::eval_assignment::<D>(
284 state, mut_state, lhs, rhs, assignment, op_span, expr_span
285 ),
286 }
287 }
288 Expr::RowCondition(block_id) | Expr::Closure(block_id) => {
289 Self::eval_row_condition_or_closure(state, mut_state, *block_id, expr_span)
290 }
291 Expr::StringInterpolation(exprs) => {
292 let config = Self::get_config(state, mut_state);
293 let str = exprs
294 .iter()
295 .map(|expr| Self::eval::<D>(state, mut_state, expr).map(|v| v.to_expanded_string(", ", &config)))
296 .collect::<Result<String, _>>()?;
297
298 Ok(Value::string(str, expr_span))
299 }
300 Expr::GlobInterpolation(exprs, quoted) => {
301 let config = Self::get_config(state, mut_state);
302 let str = exprs
303 .iter()
304 .map(|expr| Self::eval::<D>(state, mut_state, expr).map(|v| v.to_expanded_string(", ", &config)))
305 .collect::<Result<String, _>>()?;
306
307 Ok(Value::glob(str, *quoted, expr_span))
308 }
309 Expr::Overlay(_) => Self::eval_overlay(state, expr_span),
310 Expr::GlobPattern(pattern, quoted) => {
311 Ok(Value::glob(pattern, *quoted, expr_span))
314 }
315 Expr::MatchBlock(_) | Expr::Block(_) | Expr::VarDecl(_)
318 | Expr::ImportPattern(_)
319 | Expr::Signature(_)
320 | Expr::Operator(_)
321 | Expr::Garbage => Self::unreachable(state, expr),
322 }
323 }
324
325 fn get_config(state: Self::State<'_>, mut_state: &mut Self::MutState) -> Arc<Config>;
326
327 fn eval_filepath(
328 state: Self::State<'_>,
329 mut_state: &mut Self::MutState,
330 path: String,
331 quoted: bool,
332 span: Span,
333 ) -> Result<Value, ShellError>;
334
335 fn eval_directory(
336 state: Self::State<'_>,
337 mut_state: &mut Self::MutState,
338 path: String,
339 quoted: bool,
340 span: Span,
341 ) -> Result<Value, ShellError>;
342
343 fn eval_var(
344 state: Self::State<'_>,
345 mut_state: &mut Self::MutState,
346 var_id: VarId,
347 span: Span,
348 ) -> Result<Value, ShellError>;
349
350 fn eval_call<D: DebugContext>(
351 state: Self::State<'_>,
352 mut_state: &mut Self::MutState,
353 call: &Call,
354 span: Span,
355 ) -> Result<Value, ShellError>;
356
357 fn eval_external_call(
358 state: Self::State<'_>,
359 mut_state: &mut Self::MutState,
360 head: &Expression,
361 args: &[ExternalArgument],
362 span: Span,
363 ) -> Result<Value, ShellError>;
364
365 fn eval_collect<D: DebugContext>(
366 state: Self::State<'_>,
367 mut_state: &mut Self::MutState,
368 var_id: VarId,
369 expr: &Expression,
370 ) -> Result<Value, ShellError>;
371
372 fn eval_subexpression<D: DebugContext>(
373 state: Self::State<'_>,
374 mut_state: &mut Self::MutState,
375 block_id: BlockId,
376 span: Span,
377 ) -> Result<Value, ShellError>;
378
379 fn regex_match(
380 state: Self::State<'_>,
381 op_span: Span,
382 lhs: &Value,
383 rhs: &Value,
384 invert: bool,
385 expr_span: Span,
386 ) -> Result<Value, ShellError>;
387
388 #[allow(clippy::too_many_arguments)]
389 fn eval_assignment<D: DebugContext>(
390 state: Self::State<'_>,
391 mut_state: &mut Self::MutState,
392 lhs: &Expression,
393 rhs: &Expression,
394 assignment: Assignment,
395 op_span: Span,
396 expr_span: Span,
397 ) -> Result<Value, ShellError>;
398
399 fn eval_row_condition_or_closure(
400 state: Self::State<'_>,
401 mut_state: &mut Self::MutState,
402 block_id: BlockId,
403 span: Span,
404 ) -> Result<Value, ShellError>;
405
406 fn eval_overlay(state: Self::State<'_>, span: Span) -> Result<Value, ShellError>;
407
408 fn unreachable(state: Self::State<'_>, expr: &Expression) -> Result<Value, ShellError>;
410}