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