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