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>(
534 engine_state: &EngineState,
535 stack: &mut Stack,
536 block: &Block,
537 input: PipelineData,
538) -> Result<PipelineExecutionData, ShellError> {
539 let mut result = eval_block::<D>(engine_state, stack, block, input)?;
540 result.early_return = false;
541 Ok(result)
542}
543
544pub fn eval_collect<D: DebugContext>(
545 engine_state: &EngineState,
546 stack: &mut Stack,
547 var_id: VarId,
548 expr: &Expression,
549 mut input: PipelineData,
550) -> Result<PipelineData, ShellError> {
551 let span = input.span().unwrap_or(expr.span);
553
554 let metadata = input.take_metadata().and_then(|m| m.for_collect());
555
556 let input = input.into_value(span)?;
557
558 stack.add_var(var_id, input.clone());
559
560 let result = eval_expression_with_input::<D>(
561 engine_state,
562 stack,
563 expr,
564 input.into_pipeline_data_with_metadata(metadata),
566 );
567
568 stack.remove_var(var_id);
569
570 result
571}
572
573pub fn eval_subexpression<D: DebugContext>(
574 engine_state: &EngineState,
575 stack: &mut Stack,
576 block: &Block,
577 input: PipelineData,
578) -> Result<PipelineData, ShellError> {
579 eval_block::<D>(engine_state, stack, block, input).map(|p| p.body)
580}
581
582pub fn eval_variable(
583 engine_state: &EngineState,
584 stack: &Stack,
585 var_id: VarId,
586 span: Span,
587) -> Result<Value, ShellError> {
588 match var_id {
589 nu_protocol::NU_VARIABLE_ID => {
591 if let Some(val) = engine_state.get_constant(var_id) {
592 Ok(val.clone())
593 } else {
594 Err(ShellError::VariableNotFoundAtRuntime { span })
595 }
596 }
597 ENV_VARIABLE_ID => {
599 let env_vars = stack.get_env_vars(engine_state);
600 let env_columns = env_vars.keys();
601 let env_values = env_vars.values();
602
603 let mut pairs = env_columns
604 .map(|x| x.to_string())
605 .zip(env_values.cloned())
606 .collect::<Vec<(String, Value)>>();
607
608 pairs.sort_by(|a, b| a.0.cmp(&b.0));
609
610 Ok(Value::record(pairs.into_iter().collect(), span))
611 }
612 id if id == nu_protocol::LAST_VARIABLE_ID => {
615 stack.defer_last_result_truncation_warning();
616 stack.get_var(var_id, span)
617 }
618 var_id => stack.get_var(var_id, span),
619 }
620}
621
622struct EvalRuntime;
623
624impl Eval for EvalRuntime {
625 type State<'a> = &'a EngineState;
626
627 type MutState = Stack;
628
629 fn get_config(engine_state: Self::State<'_>, stack: &mut Stack) -> Arc<Config> {
630 stack.get_config(engine_state)
631 }
632
633 fn eval_var(
634 engine_state: &EngineState,
635 stack: &mut Stack,
636 var_id: VarId,
637 span: Span,
638 ) -> Result<Value, ShellError> {
639 eval_variable(engine_state, stack, var_id, span)
640 }
641
642 fn eval_call<D: DebugContext>(
643 engine_state: &EngineState,
644 stack: &mut Stack,
645 call: &Call,
646 _: Span,
647 ) -> Result<Value, ShellError> {
648 eval_call::<D>(engine_state, stack, call, PipelineData::empty())?.into_value(call.head)
650 }
651
652 fn eval_external_call(
653 engine_state: &EngineState,
654 stack: &mut Stack,
655 head: &Expression,
656 args: &[ExternalArgument],
657 _: Span,
658 ) -> Result<Value, ShellError> {
659 let span = head.span(&engine_state);
660 eval_external(engine_state, stack, head, args, PipelineData::empty())?.into_value(span)
662 }
663
664 fn eval_collect<D: DebugContext>(
665 engine_state: &EngineState,
666 stack: &mut Stack,
667 var_id: VarId,
668 expr: &Expression,
669 ) -> Result<Value, ShellError> {
670 eval_collect::<D>(engine_state, stack, var_id, expr, PipelineData::empty())?
673 .into_value(expr.span)
674 }
675
676 fn eval_subexpression<D: DebugContext>(
677 engine_state: &EngineState,
678 stack: &mut Stack,
679 block_id: BlockId,
680 span: Span,
681 ) -> Result<Value, ShellError> {
682 let block = engine_state.get_block(block_id);
683 eval_subexpression::<D>(engine_state, stack, block, PipelineData::empty())?.into_value(span)
685 }
686
687 fn regex_match(
688 engine_state: &EngineState,
689 op_span: Span,
690 lhs: &Value,
691 rhs: &Value,
692 invert: bool,
693 expr_span: Span,
694 ) -> Result<Value, ShellError> {
695 lhs.regex_match(engine_state, op_span, rhs, invert, expr_span)
696 }
697
698 fn eval_assignment<D: DebugContext>(
699 engine_state: &EngineState,
700 stack: &mut Stack,
701 lhs: &Expression,
702 rhs: &Expression,
703 assignment: Assignment,
704 op_span: Span,
705 _expr_span: Span,
706 ) -> Result<Value, ShellError> {
707 let rhs = eval_expression::<D>(engine_state, stack, rhs)?;
708
709 let rhs = match assignment {
710 Assignment::Assign => rhs,
711 Assignment::AddAssign => {
712 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
713 lhs.add(op_span, &rhs, op_span)?
714 }
715 Assignment::SubtractAssign => {
716 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
717 lhs.sub(op_span, &rhs, op_span)?
718 }
719 Assignment::MultiplyAssign => {
720 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
721 lhs.mul(op_span, &rhs, op_span)?
722 }
723 Assignment::DivideAssign => {
724 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
725 lhs.div(op_span, &rhs, op_span)?
726 }
727 Assignment::ConcatenateAssign => {
728 let lhs = eval_expression::<D>(engine_state, stack, lhs)?;
729 lhs.concat(op_span, &rhs, op_span)?
730 }
731 };
732
733 match &lhs.expr {
734 Expr::Var(var_id) | Expr::VarDecl(var_id) => {
735 let var_info = engine_state.get_var(*var_id);
736 if var_info.mutable {
737 stack.add_var(*var_id, rhs);
738 Ok(Value::nothing(lhs.span(&engine_state)))
739 } else {
740 Err(ShellError::AssignmentRequiresMutableVar {
741 lhs_span: lhs.span(&engine_state),
742 })
743 }
744 }
745 Expr::FullCellPath(cell_path) => {
746 match &cell_path.head.expr {
747 Expr::Var(var_id) | Expr::VarDecl(var_id) => {
748 let is_env = var_id == &ENV_VARIABLE_ID;
751 if is_env || engine_state.get_var(*var_id).mutable {
752 if is_env {
753 let mut lhs =
754 eval_expression::<D>(engine_state, stack, &cell_path.head)?;
755
756 if cell_path.tail.is_empty() {
758 return Err(ShellError::CannotReplaceEnv {
759 span: cell_path.head.span(&engine_state),
760 });
761 }
762
763 let (key, span) = match &cell_path.tail[0] {
766 PathMember::String { val, span, .. } => (val.to_string(), span),
767 PathMember::Int { val, span, .. } => (val.to_string(), span),
768 };
769 let original_key = if let Value::Record { val: record, .. } = &lhs {
770 record
771 .iter()
772 .rev()
773 .map(|(k, _)| k)
774 .find(|x| x.eq_ignore_case(&key))
775 .cloned()
776 .unwrap_or(key)
777 } else {
778 key
779 };
780
781 lhs.upsert_data_at_cell_path(&cell_path.tail, rhs)?;
783 let value = lhs.follow_cell_path(&[{
784 let mut pm = cell_path.tail[0].clone();
785 pm.make_insensitive();
786 pm
787 }])?;
788
789 if is_automatic_env_var(&original_key) {
791 return Err(ShellError::AutomaticEnvVarSetManually {
792 envvar_name: original_key,
793 span: *span,
794 });
795 }
796
797 let is_config = original_key == "config";
798
799 stack.add_env_var(original_key, value.into_owned());
800
801 if is_config {
803 stack.update_config(engine_state)?;
804 }
805 } else {
806 stack.upsert_var_cell_path(
809 *var_id,
810 &cell_path.tail,
811 rhs,
812 cell_path.head.span(&engine_state),
813 )?;
814 }
815 Ok(Value::nothing(cell_path.head.span(&engine_state)))
816 } else {
817 Err(ShellError::AssignmentRequiresMutableVar {
818 lhs_span: lhs.span(&engine_state),
819 })
820 }
821 }
822 _ => Err(ShellError::AssignmentRequiresVar {
823 lhs_span: lhs.span(&engine_state),
824 }),
825 }
826 }
827 _ => Err(ShellError::AssignmentRequiresVar {
828 lhs_span: lhs.span(&engine_state),
829 }),
830 }
831 }
832
833 fn eval_row_condition_or_closure(
834 engine_state: &EngineState,
835 stack: &mut Stack,
836 block_id: BlockId,
837 span: Span,
838 ) -> Result<Value, ShellError> {
839 let captures = engine_state
840 .get_block(block_id)
841 .captures
842 .iter()
843 .map(|(id, span)| {
844 stack
845 .get_var(*id, *span)
846 .or_else(|_| {
847 engine_state
848 .get_var(*id)
849 .const_val
850 .clone()
851 .ok_or(ShellError::VariableNotFoundAtRuntime { span: *span })
852 })
853 .map(|var| (*id, var))
854 })
855 .collect::<Result<_, _>>()?;
856
857 Ok(Value::closure(Closure { block_id, captures }, span))
858 }
859
860 fn eval_overlay(engine_state: &EngineState, span: Span) -> Result<Value, ShellError> {
861 let name = String::from_utf8_lossy(engine_state.get_span_contents(span)).to_string();
862
863 Ok(Value::string(name, span))
864 }
865
866 fn unreachable(engine_state: &EngineState, expr: &Expression) -> Result<Value, ShellError> {
867 Ok(Value::nothing(expr.span(&engine_state)))
868 }
869}
870
871pub(crate) fn is_automatic_env_var(var: &str) -> bool {
877 let names = ["PWD", "FILE_PWD", "CURRENT_FILE"];
878 names.iter().any(|&name| {
879 if cfg!(windows) {
880 name.eq_ignore_case(var)
881 } else {
882 name.eq(var)
883 }
884 })
885}