1#[allow(deprecated)]
2use crate::get_full_help;
3use crate::{EvalBlockWithEarlyReturnFn, eval_ir::eval_ir_block};
4use nu_protocol::{
5 BlockId, CompareTypes, Config, ENV_VARIABLE_ID, IntoPipelineData, PipelineData,
6 PipelineExecutionData, ShellError, Signature, Span, Value, VarId,
7 ast::{Assignment, Block, Call, Expr, Expression, ExternalArgument, PathMember},
8 debugger::{DebugContext, WithDebug, WithoutDebug},
9 engine::{Closure, EngineState, EnvName, EnvVars, Stack},
10 eval_base::Eval,
11};
12use nu_utils::IgnoreCaseExt;
13use std::borrow::Cow;
14use std::collections::{HashMap, HashSet};
15use std::sync::Arc;
16
17#[derive(Clone)]
29pub struct CallEval {
30 callee_stack: Stack,
31 head_span: Span,
32 callee_span: Span,
33 arg_index: usize,
34 named_args: Vec<String>,
35 rest_args: Vec<Value>,
36 eval: EvalBlockWithEarlyReturnFn,
37}
38
39impl CallEval {
40 pub fn new(
42 callee_stack: Stack,
43 call_head: Span,
44 callee_span: Span,
45 eval: EvalBlockWithEarlyReturnFn,
46 ) -> Self {
47 Self {
48 callee_stack,
49 head_span: call_head,
50 callee_span,
51 arg_index: 0,
52 named_args: Vec::new(),
53 rest_args: Vec::new(),
54 eval,
55 }
56 }
57
58 pub fn add_positional(
63 &mut self,
64 signature: &Signature,
65 value: Cow<Value>,
66 ) -> Result<&mut Self, ShellError> {
67 let maybe_param = match self
68 .arg_index
69 .checked_sub(signature.required_positional.len())
70 {
71 None => signature.required_positional.get(self.arg_index),
73 Some(opt_idx) if opt_idx < signature.optional_positional.len() => {
75 signature.optional_positional.get(opt_idx)
76 }
77 _ => None,
79 };
80
81 if let Some(param) = maybe_param {
82 let param_type = param.shape.to_type();
83 if !value.is_subtype_of(¶m_type) {
84 return Err(ShellError::CantConvert {
85 to_type: param_type.to_string(),
86 from_type: value.get_type().to_string(),
87 span: value.span(),
88 help: None,
89 });
90 }
91
92 let var_id = param
93 .var_id
94 .expect("internal error: all custom parameters must have var_ids");
95 self.callee_stack.add_var(var_id, value.into_owned());
96 self.arg_index += 1;
97 Ok(self)
98 } else {
99 let Some(rest_positional) = &signature.rest_positional else {
101 return Ok(self);
105 };
106
107 let param_type = rest_positional.shape.to_type();
108 if !value.is_subtype_of(¶m_type) {
109 return Err(ShellError::CantConvert {
110 to_type: param_type.to_string(),
111 from_type: value.get_type().to_string(),
112 span: value.span(),
113 help: None,
114 });
115 }
116
117 self.rest_args.push(value.into_owned());
118 Ok(self)
119 }
120 }
121
122 pub fn add_named(
124 &mut self,
125 signature: &Signature,
126 long: &str,
127 short: Option<String>,
128 value: Option<Cow<Value>>,
129 ) -> Result<&mut Self, ShellError> {
130 let named = signature.named.iter().find(|named| {
131 long == named.long
132 || short
133 .as_deref()
134 .zip(named.short)
135 .is_some_and(|(arg, param)| {
136 let mut buf = [0; 4];
137 param.encode_utf8(&mut buf) == arg
138 })
139 });
140
141 if let Some(named) = named {
142 let var_id = named
143 .var_id
144 .expect("internal error: all custom parameters must have var_ids");
145
146 let value = value
147 .or_else(|| named.default_value.as_ref().map(Cow::Borrowed))
148 .unwrap_or_else(|| Cow::Owned(Value::bool(true, self.head_span)));
149
150 self.callee_stack.add_var(var_id, value.into_owned());
151 self.named_args.push(long.to_string());
152 }
153
154 Ok(self)
155 }
156
157 pub fn with_env(
159 &mut self,
160 env_vars: &[Arc<EnvVars>],
161 env_hidden: &Arc<HashMap<String, HashSet<EnvName>>>,
162 ) -> &mut Self {
163 self.callee_stack.with_env(env_vars, env_hidden);
164 self
165 }
166
167 pub fn debug(&mut self, debug: bool) -> &mut Self {
169 if debug {
170 self.eval = eval_block_with_early_return::<WithDebug>
171 } else {
172 self.eval = eval_block_with_early_return::<WithoutDebug>
173 };
174 self
175 }
176
177 pub fn run(
179 &mut self,
180 engine_state: &EngineState,
181 block: &Block,
182 input: PipelineData,
183 ) -> Result<PipelineData, ShellError> {
184 self.finalize_arguments(&block.signature)?;
185 self.arg_index = 0;
186 self.rest_args.clear();
187 (self.eval)(engine_state, &mut self.callee_stack, block, input).map(|p| p.body)
188 }
189
190 pub fn finalize_for_signature(
195 &mut self,
196 signature: &Signature,
197 ) -> Result<&mut Self, ShellError> {
198 self.finalize_arguments(signature)?;
199 Ok(self)
200 }
201
202 pub fn run_prebound(
204 &mut self,
205 engine_state: &EngineState,
206 block: &Block,
207 input: PipelineData,
208 ) -> Result<PipelineData, ShellError> {
209 self.arg_index = 0;
210 self.rest_args.clear();
211 (self.eval)(engine_state, &mut self.callee_stack, block, input).map(|p| p.body)
212 }
213
214 pub fn redirect_env(&self, engine_state: &EngineState, stack: &mut Stack) {
216 redirect_env(engine_state, stack, &self.callee_stack);
217 }
218
219 fn finalize_arguments(&mut self, signature: &Signature) -> Result<(), ShellError> {
222 let remaining_positionals = signature
223 .required_positional
224 .iter()
225 .map(|p| (p, true))
226 .chain(signature.optional_positional.iter().map(|p| (p, false)))
227 .skip(self.arg_index);
229
230 for (param, required) in remaining_positionals {
231 let var_id = param
232 .var_id
233 .expect("internal error: all custom parameters must have var_ids");
234
235 let maybe_value = param
236 .default_value
237 .clone()
238 .or((!required).then_some(Value::nothing(self.callee_span)));
239
240 if let Some(value) = maybe_value {
241 self.callee_stack.add_var(var_id, value);
242 } else {
243 return Err(ShellError::MissingParameter {
244 param_name: param.name.to_string(),
245 span: self.callee_span,
246 });
247 }
248 }
249
250 if let Some(rest_positional) = &signature.rest_positional {
251 let span = self
252 .rest_args
253 .first()
254 .map(|x| x.span())
255 .unwrap_or(self.callee_span);
256
257 self.callee_stack.add_var(
258 rest_positional
259 .var_id
260 .expect("Internal error: rest positional parameter lackes var_id"),
261 Value::list(self.rest_args.to_owned(), span),
262 );
263 }
264
265 let remaining_flags = signature
266 .named
267 .iter()
268 .filter(|flag| !self.named_args.contains(&flag.long))
270 .filter_map(|flag| Some((flag.var_id?, flag)));
273
274 for (var_id, flag) in remaining_flags {
275 if flag.arg.is_none() {
276 self.callee_stack
277 .add_var(var_id, Value::bool(false, self.head_span));
278 } else {
279 let value = flag
280 .default_value
281 .clone()
282 .unwrap_or(Value::nothing(self.head_span));
283 self.callee_stack.add_var(var_id, value);
284 }
285 }
286
287 Ok(())
288 }
289}
290
291pub fn eval_call<D: DebugContext>(
293 engine_state: &EngineState,
294 caller_stack: &mut Stack,
295 call: &Call,
296 input: PipelineData,
297) -> Result<PipelineData, ShellError> {
298 engine_state.signals().check(&call.head)?;
299 let decl = engine_state.get_decl(call.decl_id);
300
301 if !decl.is_known_external() && call.named_iter().any(|(flag, _, _)| flag.item == "help") {
302 let help = get_full_help(decl, engine_state, caller_stack, call.head);
303 Ok(Value::string(help, call.head).into_pipeline_data())
304 } else if let Some(block_id) = decl.block_id() {
305 let block = engine_state.get_block(block_id);
307 let mut callee_stack = caller_stack.gather_captures(engine_state, &block.captures);
308
309 let maximum_call_stack_depth: u64 = engine_state.config.recursion_limit as u64;
315 callee_stack.recursion_count += 1;
316 if callee_stack.recursion_count > maximum_call_stack_depth {
317 callee_stack.recursion_count = 0;
318 return Err(ShellError::RecursionLimitReached {
319 recursion_limit: maximum_call_stack_depth,
320 span: block.span,
321 });
322 }
323
324 let mut call_eval = CallEval::new(
325 callee_stack,
326 call.head,
327 block.span.unwrap_or(Span::unknown()),
328 eval_block_with_early_return::<D>,
329 );
330 for arg in call.positional_iter() {
331 let result = eval_expression::<D>(engine_state, caller_stack, arg)?;
332 call_eval.add_positional(&decl.signature(), Cow::Owned(result))?;
333 }
334 for call_named in call.named_iter() {
335 let result: Option<Cow<Value>> = if let Some(arg) = &call_named.2 {
336 Some(Cow::Owned(eval_expression::<D>(
337 engine_state,
338 caller_stack,
339 arg,
340 )?))
341 } else {
342 None
343 };
344 call_eval.add_named(
345 &decl.signature(),
346 &call_named.0.item,
347 call_named.1.clone().map(|x| x.item),
348 result,
349 )?;
350 }
351
352 let result = call_eval.run(engine_state, block, input);
353
354 if block.redirect_env {
355 call_eval.redirect_env(engine_state, caller_stack);
356 }
357
358 result
359 } else {
360 decl.run(engine_state, caller_stack, &call.into(), input)
365 }
366}
367
368pub fn redirect_env(engine_state: &EngineState, caller_stack: &mut Stack, callee_stack: &Stack) {
370 let caller_env_vars = caller_stack.get_env_var_names(engine_state);
372
373 for var in caller_env_vars.iter() {
376 if !callee_stack.has_env_var(engine_state, var) {
377 caller_stack.hide_env_var(engine_state, var);
378 }
379 }
380
381 for (var, value) in callee_stack.get_stack_env_vars() {
383 caller_stack.add_env_var(var, value);
384 }
385
386 caller_stack.config.clone_from(&callee_stack.config);
388}
389
390fn eval_external(
391 engine_state: &EngineState,
392 stack: &mut Stack,
393 head: &Expression,
394 args: &[ExternalArgument],
395 input: PipelineData,
396) -> Result<PipelineData, ShellError> {
397 let decl_id = engine_state
398 .find_decl("run-external".as_bytes(), &[])
399 .ok_or(ShellError::ExternalNotSupported {
400 span: head.span(&engine_state),
401 })?;
402
403 let command = engine_state.get_decl(decl_id);
404
405 let mut call = Call::new(head.span(&engine_state));
406
407 call.add_positional(head.clone());
408
409 for arg in args {
410 match arg {
411 ExternalArgument::Regular(expr) => call.add_positional(expr.clone()),
412 ExternalArgument::Spread(expr) => call.add_spread(expr.clone()),
413 }
414 }
415
416 command.run(engine_state, stack, &(&call).into(), input)
417}
418
419pub fn eval_expression<D: DebugContext>(
420 engine_state: &EngineState,
421 stack: &mut Stack,
422 expr: &Expression,
423) -> Result<Value, ShellError> {
424 let stack = &mut stack.start_collect_value();
425 <EvalRuntime as Eval>::eval::<D>(engine_state, stack, expr)
426}
427
428pub fn eval_expression_with_input<D: DebugContext>(
435 engine_state: &EngineState,
436 stack: &mut Stack,
437 expr: &Expression,
438 mut input: PipelineData,
439) -> Result<PipelineData, ShellError> {
440 match &expr.expr {
441 Expr::Call(call) => {
442 input = eval_call::<D>(engine_state, stack, call, input)?;
443 }
444 Expr::ExternalCall(head, args) => {
445 input = eval_external(engine_state, stack, head, args, input)?;
446 }
447
448 Expr::Collect(var_id, expr) => {
449 input = eval_collect::<D>(engine_state, stack, *var_id, expr, input)?;
450 }
451
452 Expr::Subexpression(block_id) => {
453 let block = engine_state.get_block(*block_id);
454 input = eval_subexpression::<D>(engine_state, stack, block, input)?;
456 }
457
458 Expr::FullCellPath(full_cell_path) => match &full_cell_path.head {
459 Expression {
460 expr: Expr::Subexpression(block_id),
461 span,
462 ..
463 } => {
464 let block = engine_state.get_block(*block_id);
465
466 if !full_cell_path.tail.is_empty() {
467 let stack = &mut stack.start_collect_value();
468 input = eval_subexpression::<D>(engine_state, stack, block, input)?
470 .into_value(*span)?
471 .follow_cell_path(&full_cell_path.tail)?
472 .into_owned()
473 .into_pipeline_data()
474 } else {
475 input = eval_subexpression::<D>(engine_state, stack, block, input)?;
476 }
477 }
478 _ => {
479 let input_value = input.into_value(expr.span)?;
480 stack.add_var(nu_protocol::IN_VARIABLE_ID, input_value);
481 input = eval_expression::<D>(engine_state, stack, expr)?.into_pipeline_data();
482 }
483 },
484
485 Expr::StringInterpolation(_) | Expr::GlobInterpolation(_, _) => {
486 let input_value = input.into_value(expr.span)?;
487 stack.add_var(nu_protocol::IN_VARIABLE_ID, input_value);
488 let value = eval_expression::<D>(engine_state, stack, expr)?;
489 input = PipelineData::Value(value, None);
490 }
491
492 _ => {
493 let input_value = input.into_value(expr.span)?;
494 stack.add_var(nu_protocol::IN_VARIABLE_ID, input_value);
495 let value = eval_expression::<D>(engine_state, stack, expr)?;
496 input = PipelineData::Value(value, None);
497 }
498 };
499
500 Ok(input)
501}
502
503pub fn eval_block<D: DebugContext>(
504 engine_state: &EngineState,
505 stack: &mut Stack,
506 block: &Block,
507 input: PipelineData,
508) -> Result<PipelineExecutionData, ShellError> {
509 let result = eval_ir_block::<D>(engine_state, stack, block, input);
510 if let Err(err) = &result {
511 stack.set_last_error(err);
512 }
513 result
514}
515
516pub fn eval_block_with_early_return<D: DebugContext>(
517 engine_state: &EngineState,
518 stack: &mut Stack,
519 block: &Block,
520 input: PipelineData,
521) -> Result<PipelineExecutionData, ShellError> {
522 match eval_block::<D>(engine_state, stack, block, input) {
523 Err(ShellError::Return { span: _, value }) => Ok(PipelineExecutionData::from(
524 PipelineData::value(*value, None),
525 )),
526 x => x,
527 }
528}
529
530pub fn eval_collect<D: DebugContext>(
531 engine_state: &EngineState,
532 stack: &mut Stack,
533 var_id: VarId,
534 expr: &Expression,
535 mut input: PipelineData,
536) -> Result<PipelineData, ShellError> {
537 let span = input.span().unwrap_or(expr.span);
539
540 let metadata = input.take_metadata().and_then(|m| m.for_collect());
541
542 let input = input.into_value(span)?;
543
544 stack.add_var(var_id, input.clone());
545
546 let result = eval_expression_with_input::<D>(
547 engine_state,
548 stack,
549 expr,
550 input.into_pipeline_data_with_metadata(metadata),
552 );
553
554 stack.remove_var(var_id);
555
556 result
557}
558
559pub fn eval_subexpression<D: DebugContext>(
560 engine_state: &EngineState,
561 stack: &mut Stack,
562 block: &Block,
563 input: PipelineData,
564) -> Result<PipelineData, ShellError> {
565 eval_block::<D>(engine_state, stack, block, input).map(|p| p.body)
566}
567
568pub fn eval_variable(
569 engine_state: &EngineState,
570 stack: &Stack,
571 var_id: VarId,
572 span: Span,
573) -> Result<Value, ShellError> {
574 match var_id {
575 nu_protocol::NU_VARIABLE_ID => {
577 if let Some(val) = engine_state.get_constant(var_id) {
578 Ok(val.clone())
579 } else {
580 Err(ShellError::VariableNotFoundAtRuntime { span })
581 }
582 }
583 ENV_VARIABLE_ID => {
585 let env_vars = stack.get_env_vars(engine_state);
586 let env_columns = env_vars.keys();
587 let env_values = env_vars.values();
588
589 let mut pairs = env_columns
590 .map(|x| x.to_string())
591 .zip(env_values.cloned())
592 .collect::<Vec<(String, Value)>>();
593
594 pairs.sort_by(|a, b| a.0.cmp(&b.0));
595
596 Ok(Value::record(pairs.into_iter().collect(), span))
597 }
598 var_id => stack.get_var(var_id, span),
599 }
600}
601
602struct EvalRuntime;
603
604impl Eval for EvalRuntime {
605 type State<'a> = &'a EngineState;
606
607 type MutState = Stack;
608
609 fn get_config(engine_state: Self::State<'_>, stack: &mut Stack) -> Arc<Config> {
610 stack.get_config(engine_state)
611 }
612
613 fn eval_var(
614 engine_state: &EngineState,
615 stack: &mut Stack,
616 var_id: VarId,
617 span: Span,
618 ) -> Result<Value, ShellError> {
619 eval_variable(engine_state, stack, var_id, span)
620 }
621
622 fn eval_call<D: DebugContext>(
623 engine_state: &EngineState,
624 stack: &mut Stack,
625 call: &Call,
626 _: Span,
627 ) -> Result<Value, ShellError> {
628 eval_call::<D>(engine_state, stack, call, PipelineData::empty())?.into_value(call.head)
630 }
631
632 fn eval_external_call(
633 engine_state: &EngineState,
634 stack: &mut Stack,
635 head: &Expression,
636 args: &[ExternalArgument],
637 _: Span,
638 ) -> Result<Value, ShellError> {
639 let span = head.span(&engine_state);
640 eval_external(engine_state, stack, head, args, PipelineData::empty())?.into_value(span)
642 }
643
644 fn eval_collect<D: DebugContext>(
645 engine_state: &EngineState,
646 stack: &mut Stack,
647 var_id: VarId,
648 expr: &Expression,
649 ) -> Result<Value, ShellError> {
650 eval_collect::<D>(engine_state, stack, var_id, expr, PipelineData::empty())?
653 .into_value(expr.span)
654 }
655
656 fn eval_subexpression<D: DebugContext>(
657 engine_state: &EngineState,
658 stack: &mut Stack,
659 block_id: BlockId,
660 span: Span,
661 ) -> Result<Value, ShellError> {
662 let block = engine_state.get_block(block_id);
663 eval_subexpression::<D>(engine_state, stack, block, PipelineData::empty())?.into_value(span)
665 }
666
667 fn regex_match(
668 engine_state: &EngineState,
669 op_span: Span,
670 lhs: &Value,
671 rhs: &Value,
672 invert: bool,
673 expr_span: Span,
674 ) -> Result<Value, ShellError> {
675 lhs.regex_match(engine_state, op_span, rhs, invert, expr_span)
676 }
677
678 fn eval_assignment<D: DebugContext>(
679 engine_state: &EngineState,
680 stack: &mut Stack,
681 lhs: &Expression,
682 rhs: &Expression,
683 assignment: Assignment,
684 op_span: Span,
685 _expr_span: Span,
686 ) -> Result<Value, ShellError> {
687 let rhs = eval_expression::<D>(engine_state, stack, rhs)?;
688
689 let rhs = match assignment {
690 Assignment::Assign => rhs,
691 Assignment::AddAssign => {
692 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
693 lhs.add(op_span, &rhs, op_span)?
694 }
695 Assignment::SubtractAssign => {
696 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
697 lhs.sub(op_span, &rhs, op_span)?
698 }
699 Assignment::MultiplyAssign => {
700 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
701 lhs.mul(op_span, &rhs, op_span)?
702 }
703 Assignment::DivideAssign => {
704 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
705 lhs.div(op_span, &rhs, op_span)?
706 }
707 Assignment::ConcatenateAssign => {
708 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
709 lhs.concat(op_span, &rhs, op_span)?
710 }
711 };
712
713 match &lhs.expr {
714 Expr::Var(var_id) | Expr::VarDecl(var_id) => {
715 let var_info = engine_state.get_var(*var_id);
716 if var_info.mutable {
717 stack.add_var(*var_id, rhs);
718 Ok(Value::nothing(lhs.span(&engine_state)))
719 } else {
720 Err(ShellError::AssignmentRequiresMutableVar {
721 lhs_span: lhs.span(&engine_state),
722 })
723 }
724 }
725 Expr::FullCellPath(cell_path) => {
726 match &cell_path.head.expr {
727 Expr::Var(var_id) | Expr::VarDecl(var_id) => {
728 let is_env = var_id == &ENV_VARIABLE_ID;
731 if is_env || engine_state.get_var(*var_id).mutable {
732 let mut lhs =
733 eval_expression::<D>(engine_state, stack, &cell_path.head)?;
734 if is_env {
735 if cell_path.tail.is_empty() {
737 return Err(ShellError::CannotReplaceEnv {
738 span: cell_path.head.span(&engine_state),
739 });
740 }
741
742 let (key, span) = match &cell_path.tail[0] {
745 PathMember::String { val, span, .. } => (val.to_string(), span),
746 PathMember::Int { val, span, .. } => (val.to_string(), span),
747 };
748 let original_key = if let Value::Record { val: record, .. } = &lhs {
749 record
750 .iter()
751 .rev()
752 .map(|(k, _)| k)
753 .find(|x| x.eq_ignore_case(&key))
754 .cloned()
755 .unwrap_or(key)
756 } else {
757 key
758 };
759
760 lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?;
762 let value = lhs.follow_cell_path(&[{
763 let mut pm = cell_path.tail[0].clone();
764 pm.make_insensitive();
765 pm
766 }])?;
767
768 if is_automatic_env_var(&original_key) {
770 return Err(ShellError::AutomaticEnvVarSetManually {
771 envvar_name: original_key,
772 span: *span,
773 });
774 }
775
776 let is_config = original_key == "config";
777
778 stack.add_env_var(original_key, value.into_owned());
779
780 if is_config {
782 stack.update_config(engine_state)?;
783 }
784 } else {
785 lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?;
786 stack.add_var(*var_id, lhs);
787 }
788 Ok(Value::nothing(cell_path.head.span(&engine_state)))
789 } else {
790 Err(ShellError::AssignmentRequiresMutableVar {
791 lhs_span: lhs.span(&engine_state),
792 })
793 }
794 }
795 _ => Err(ShellError::AssignmentRequiresVar {
796 lhs_span: lhs.span(&engine_state),
797 }),
798 }
799 }
800 _ => Err(ShellError::AssignmentRequiresVar {
801 lhs_span: lhs.span(&engine_state),
802 }),
803 }
804 }
805
806 fn eval_row_condition_or_closure(
807 engine_state: &EngineState,
808 stack: &mut Stack,
809 block_id: BlockId,
810 span: Span,
811 ) -> Result<Value, ShellError> {
812 let captures = engine_state
813 .get_block(block_id)
814 .captures
815 .iter()
816 .map(|(id, span)| {
817 stack
818 .get_var(*id, *span)
819 .or_else(|_| {
820 engine_state
821 .get_var(*id)
822 .const_val
823 .clone()
824 .ok_or(ShellError::VariableNotFoundAtRuntime { span: *span })
825 })
826 .map(|var| (*id, var))
827 })
828 .collect::<Result<_, _>>()?;
829
830 Ok(Value::closure(Closure { block_id, captures }, span))
831 }
832
833 fn eval_overlay(engine_state: &EngineState, span: Span) -> Result<Value, ShellError> {
834 let name = String::from_utf8_lossy(engine_state.get_span_contents(span)).to_string();
835
836 Ok(Value::string(name, span))
837 }
838
839 fn unreachable(engine_state: &EngineState, expr: &Expression) -> Result<Value, ShellError> {
840 Ok(Value::nothing(expr.span(&engine_state)))
841 }
842}
843
844pub(crate) fn is_automatic_env_var(var: &str) -> bool {
850 let names = ["PWD", "FILE_PWD", "CURRENT_FILE"];
851 names.iter().any(|&name| {
852 if cfg!(windows) {
853 name.eq_ignore_case(var)
854 } else {
855 name.eq(var)
856 }
857 })
858}