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 _ => return Err(ShellError::CannotSpreadAsList { span: expr_span }),
82 },
83 }
84 }
85 Ok(Value::list(output, expr_span))
86 }
87 Expr::Record(items) => {
88 let mut record = Record::new();
89 let mut col_names = HashMap::new();
90 for item in items {
91 match item {
92 RecordItem::Pair(col, val) => {
93 let col_name = Self::eval::<D>(state, mut_state, col)?.coerce_into_string()?;
95 let col_span = col.span(&state);
96 if let Some(orig_span) = col_names.get(&col_name) {
97 return Err(ShellError::ColumnDefinedTwice {
98 col_name,
99 second_use: col_span,
100 first_use: *orig_span,
101 });
102 } else {
103 col_names.insert(col_name.clone(), col_span);
104 record.push(col_name, Self::eval::<D>(state, mut_state, val)?);
105 }
106 }
107 RecordItem::Spread(_, inner) => {
108 let inner_span = inner.span(&state);
109 match Self::eval::<D>(state, mut_state, inner)? {
110 Value::Record { val: inner_val, .. } => {
111 for (col_name, val) in inner_val.into_owned() {
112 if let Some(orig_span) = col_names.get(&col_name) {
113 return Err(ShellError::ColumnDefinedTwice {
114 col_name,
115 second_use: inner_span,
116 first_use: *orig_span,
117 });
118 } else {
119 col_names.insert(col_name.clone(), inner_span);
120 record.push(col_name, val);
121 }
122 }
123 }
124 _ => {
125 return Err(ShellError::CannotSpreadAsRecord {
126 span: inner_span,
127 })
128 }
129 }
130 }
131 }
132 }
133
134 Ok(Value::record(record, expr_span))
135 }
136 Expr::Table(table) => {
137 let mut output_headers = vec![];
138 for expr in table.columns.as_ref() {
139 let header = Self::eval::<D>(state, mut_state, expr)?.coerce_into_string()?;
140 if let Some(idx) = output_headers
141 .iter()
142 .position(|existing| existing == &header)
143 {
144 let first_use = table.columns[idx].span(&state);
145 return Err(ShellError::ColumnDefinedTwice {
146 col_name: header,
147 second_use: expr_span,
148 first_use,
149 });
150 } else {
151 output_headers.push(header);
152 }
153 }
154
155 let mut output_rows = vec![];
156 for val in table.rows.as_ref() {
157 let record = output_headers.iter().zip(val.as_ref()).map(|(col, expr)| {
158 Self::eval::<D>(state, mut_state, expr).map(|val| (col.clone(), val))
159 }).collect::<Result<_,_>>()?;
160
161 output_rows.push(Value::record(
162 record,
163 expr_span,
164 ));
165 }
166 Ok(Value::list(output_rows, expr_span))
167 }
168 Expr::Keyword(kw) => Self::eval::<D>(state, mut_state, &kw.expr),
169 Expr::String(s) | Expr::RawString(s) => Ok(Value::string(s.clone(), expr_span)),
170 Expr::Nothing => Ok(Value::nothing(expr_span)),
171 Expr::ValueWithUnit(value) => match Self::eval::<D>(state, mut_state, &value.expr)? {
172 Value::Int { val, .. } => value.unit.item.build_value(val, value.unit.span),
173 x => Err(ShellError::CantConvert {
174 to_type: "unit value".into(),
175 from_type: x.get_type().to_string(),
176 span: value.expr.span(&state),
177 help: None,
178 }),
179 },
180 Expr::Call(call) => Self::eval_call::<D>(state, mut_state, call, expr_span),
181 Expr::ExternalCall(head, args) => {
182 Self::eval_external_call(state, mut_state, head, args, expr_span)
183 }
184 Expr::Collect(var_id, expr) => {
185 Self::eval_collect::<D>(state, mut_state, *var_id, expr)
186 }
187 Expr::Subexpression(block_id) => {
188 Self::eval_subexpression::<D>(state, mut_state, *block_id, expr_span)
189 }
190 Expr::Range(range) => {
191 let from = if let Some(f) = &range.from {
192 Self::eval::<D>(state, mut_state, f)?
193 } else {
194 Value::nothing(expr_span)
195 };
196
197 let next = if let Some(s) = &range.next {
198 Self::eval::<D>(state, mut_state, s)?
199 } else {
200 Value::nothing(expr_span)
201 };
202
203 let to = if let Some(t) = &range.to {
204 Self::eval::<D>(state, mut_state, t)?
205 } else {
206 Value::nothing(expr_span)
207 };
208
209 Ok(Value::range(
210 Range::new(from, next, to, range.operator.inclusion, expr_span)?,
211 expr_span,
212 ))
213 }
214 Expr::UnaryNot(expr) => {
215 let lhs = Self::eval::<D>(state, mut_state, expr)?;
216 match lhs {
217 Value::Bool { val, .. } => Ok(Value::bool(!val, expr_span)),
218 other => Err(ShellError::TypeMismatch {
219 err_message: format!("expected bool, found {}", other.get_type()),
220 span: expr_span,
221 }),
222 }
223 }
224 Expr::BinaryOp(lhs, op, rhs) => {
225 let op_span = op.span(&state);
226 let op = eval_operator(op)?;
227
228 match op {
229 Operator::Boolean(boolean) => {
230 let lhs = Self::eval::<D>(state, mut_state, lhs)?;
231 match boolean {
232 Boolean::And => {
233 if lhs.is_false() {
234 Ok(Value::bool(false, expr_span))
235 } else {
236 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
237 lhs.and(op_span, &rhs, expr_span)
238 }
239 }
240 Boolean::Or => {
241 if lhs.is_true() {
242 Ok(Value::bool(true, expr_span))
243 } else {
244 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
245 lhs.or(op_span, &rhs, expr_span)
246 }
247 }
248 Boolean::Xor => {
249 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
250 lhs.xor(op_span, &rhs, expr_span)
251 }
252 }
253 }
254 Operator::Math(math) => {
255 let lhs = Self::eval::<D>(state, mut_state, lhs)?;
256 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
257
258 match math {
259 Math::Add => lhs.add(op_span, &rhs, expr_span),
260 Math::Subtract => lhs.sub(op_span, &rhs, expr_span),
261 Math::Multiply => lhs.mul(op_span, &rhs, expr_span),
262 Math::Divide => lhs.div(op_span, &rhs, expr_span),
263 Math::FloorDivide => lhs.floor_div(op_span, &rhs, expr_span),
264 Math::Modulo => lhs.modulo(op_span, &rhs, expr_span),
265 Math::Pow => lhs.pow(op_span, &rhs, expr_span),
266 Math::Concatenate => lhs.concat(op_span, &rhs, expr_span),
267 }
268 }
269 Operator::Comparison(comparison) => {
270 let lhs = Self::eval::<D>(state, mut_state, lhs)?;
271 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
272 match comparison {
273 Comparison::LessThan => lhs.lt(op_span, &rhs, expr_span),
274 Comparison::LessThanOrEqual => lhs.lte(op_span, &rhs, expr_span),
275 Comparison::GreaterThan => lhs.gt(op_span, &rhs, expr_span),
276 Comparison::GreaterThanOrEqual => lhs.gte(op_span, &rhs, expr_span),
277 Comparison::Equal => lhs.eq(op_span, &rhs, expr_span),
278 Comparison::NotEqual => lhs.ne(op_span, &rhs, expr_span),
279 Comparison::In => lhs.r#in(op_span, &rhs, expr_span),
280 Comparison::NotIn => lhs.not_in(op_span, &rhs, expr_span),
281 Comparison::Has => lhs.has(op_span, &rhs, expr_span),
282 Comparison::NotHas => lhs.not_has(op_span, &rhs, expr_span),
283 Comparison::StartsWith => lhs.starts_with(op_span, &rhs, expr_span),
284 Comparison::EndsWith => lhs.ends_with(op_span, &rhs, expr_span),
285 Comparison::RegexMatch => {
286 Self::regex_match(state, op_span, &lhs, &rhs, false, expr_span)
287 }
288 Comparison::NotRegexMatch => {
289 Self::regex_match(state, op_span, &lhs, &rhs, true, expr_span)
290 }
291 }
292 }
293 Operator::Bits(bits) => {
294 let lhs = Self::eval::<D>(state, mut_state, lhs)?;
295 let rhs = Self::eval::<D>(state, mut_state, rhs)?;
296 match bits {
297 Bits::BitAnd => lhs.bit_and(op_span, &rhs, expr_span),
298 Bits::BitOr => lhs.bit_or(op_span, &rhs, expr_span),
299 Bits::BitXor => lhs.bit_xor(op_span, &rhs, expr_span),
300 Bits::ShiftLeft => lhs.bit_shl(op_span, &rhs, expr_span),
301 Bits::ShiftRight => lhs.bit_shr(op_span, &rhs, expr_span),
302 }
303 }
304 Operator::Assignment(assignment) => Self::eval_assignment::<D>(
305 state, mut_state, lhs, rhs, assignment, op_span, expr_span
306 ),
307 }
308 }
309 Expr::RowCondition(block_id) | Expr::Closure(block_id) => {
310 Self::eval_row_condition_or_closure(state, mut_state, *block_id, expr_span)
311 }
312 Expr::StringInterpolation(exprs) => {
313 let config = Self::get_config(state, mut_state);
314 let str = exprs
315 .iter()
316 .map(|expr| Self::eval::<D>(state, mut_state, expr).map(|v| v.to_expanded_string(", ", &config)))
317 .collect::<Result<String, _>>()?;
318
319 Ok(Value::string(str, expr_span))
320 }
321 Expr::GlobInterpolation(exprs, quoted) => {
322 let config = Self::get_config(state, mut_state);
323 let str = exprs
324 .iter()
325 .map(|expr| Self::eval::<D>(state, mut_state, expr).map(|v| v.to_expanded_string(", ", &config)))
326 .collect::<Result<String, _>>()?;
327
328 Ok(Value::glob(str, *quoted, expr_span))
329 }
330 Expr::Overlay(_) => Self::eval_overlay(state, expr_span),
331 Expr::GlobPattern(pattern, quoted) => {
332 Ok(Value::glob(pattern, *quoted, expr_span))
335 }
336 Expr::MatchBlock(_) | Expr::Block(_) | Expr::VarDecl(_)
339 | Expr::ImportPattern(_)
340 | Expr::Signature(_)
341 | Expr::Operator(_)
342 | Expr::Garbage => Self::unreachable(state, expr),
343 }
344 }
345
346 fn get_config(state: Self::State<'_>, mut_state: &mut Self::MutState) -> Arc<Config>;
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}