1use crate::{
2 exportable::Exportable,
3 parse_block,
4 parser::{
5 ArgumentParsingLevel, CallKind, compile_block, compile_block_with_id, parse_attribute,
6 parse_redirection, redirecting_builtin_error,
7 },
8 type_check::{check_block_input_output, type_compatible},
9};
10
11use log::trace;
12use nu_path::canonicalize_with;
13use nu_path::is_windows_device_path;
14use nu_protocol::{
15 Alias, BlockId, CommandWideCompleter, CustomExample, DeclId, FromValue, Module, ModuleId,
16 ParseError, PositionalArg, ResolvedImportPattern, ShellError, Signature, Span, Spanned,
17 SyntaxShape, Type, Value, VarId,
18 ast::{
19 Argument, AttributeBlock, Block, Call, Expr, Expression, ImportPattern, ImportPatternHead,
20 ImportPatternMember, Pipeline, PipelineElement,
21 },
22 category_from_string,
23 engine::{DEFAULT_OVERLAY_NAME, StateWorkingSet},
24 eval_const::eval_constant,
25 parser_path::ParserPath,
26};
27use std::{
28 collections::{HashMap, HashSet},
29 path::{Path, PathBuf},
30 sync::Arc,
31};
32
33pub const LIB_DIRS_VAR: &str = "NU_LIB_DIRS";
34#[cfg(feature = "plugin")]
35pub const PLUGIN_DIRS_VAR: &str = "NU_PLUGIN_DIRS";
36
37use crate::{
38 Token, TokenContents, is_math_expression_like,
39 known_external::KnownExternal,
40 lex,
41 lite_parser::{LiteCommand, lite_parse},
42 parser::{
43 ParsedInternalCall, garbage, garbage_pipeline, parse, parse_call, parse_expression,
44 parse_full_signature, parse_import_pattern, parse_internal_call, parse_string,
45 parse_var_with_opt_type, trim_quotes,
46 },
47 unescape_unquote_string,
48};
49
50pub const ALIASABLE_PARSER_KEYWORDS: &[&[u8]] = &[
52 b"if",
53 b"match",
54 b"try",
55 b"overlay",
56 b"overlay hide",
57 b"overlay new",
58 b"overlay use",
59];
60
61pub const RESERVED_VARIABLE_NAMES: [&str; 3] = ["in", "nu", "env"];
62
63pub const UNALIASABLE_PARSER_KEYWORDS: &[&[u8]] = &[
65 b"alias",
66 b"const",
67 b"def",
68 b"extern",
69 b"module",
70 b"use",
71 b"export",
72 b"export alias",
73 b"export const",
74 b"export def",
75 b"export extern",
76 b"export module",
77 b"export use",
78 b"for",
79 b"loop",
80 b"while",
81 b"return",
82 b"break",
83 b"continue",
84 b"let",
85 b"mut",
86 b"hide",
87 b"export-env",
88 b"source-env",
89 b"source",
90 b"where",
91 b"plugin use",
92];
93
94pub fn is_unaliasable_parser_keyword(working_set: &StateWorkingSet, spans: &[Span]) -> bool {
96 if let (Some(&span1), Some(&span2)) = (spans.first(), spans.get(1)) {
98 let cmd_name = working_set.get_span_contents(Span::append(span1, span2));
99 return UNALIASABLE_PARSER_KEYWORDS.contains(&cmd_name);
100 }
101
102 if let Some(&span1) = spans.first() {
104 let cmd_name = working_set.get_span_contents(span1);
105 UNALIASABLE_PARSER_KEYWORDS.contains(&cmd_name)
106 } else {
107 false
108 }
109}
110
111pub fn parse_keyword(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline {
114 let orig_parse_errors_len = working_set.parse_errors.len();
115
116 let call_expr = parse_call(working_set, &lite_command.parts, lite_command.parts[0]);
117
118 if working_set.parse_errors.len() > orig_parse_errors_len {
120 return Pipeline::from_vec(vec![call_expr]);
121 }
122
123 if let Expression {
124 expr: Expr::Call(call),
125 ..
126 } = call_expr.clone()
127 {
128 let cmd = working_set.get_decl(call.decl_id);
130 if call.named_iter().any(|(flag, _, _)| flag.item == "help") {
132 let call_span = call.span();
133 return Pipeline::from_vec(vec![Expression::new(
134 working_set,
135 Expr::Call(call),
136 call_span,
137 Type::Any,
138 )]);
139 }
140
141 match cmd.name() {
142 "overlay hide" => parse_overlay_hide(working_set, call),
143 "overlay new" => parse_overlay_new(working_set, call),
144 "overlay use" => parse_overlay_use(working_set, call),
145 #[cfg(feature = "plugin")]
146 "plugin use" => parse_plugin_use(working_set, call),
147 _ => Pipeline::from_vec(vec![call_expr]),
148 }
149 } else {
150 Pipeline::from_vec(vec![call_expr])
151 }
152}
153
154pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) {
155 let mut pos = 0;
156
157 let def_type_name = if spans.len() >= 3 {
158 let first_word = working_set.get_span_contents(spans[0]);
160
161 if first_word == b"export" {
162 pos += 2;
163 } else {
164 pos += 1;
165 }
166
167 working_set.get_span_contents(spans[pos - 1]).to_vec()
168 } else {
169 return;
170 };
171
172 if def_type_name != b"def" && def_type_name != b"extern" {
173 return;
174 }
175
176 while pos < spans.len() && working_set.get_span_contents(spans[pos]).starts_with(b"-") {
179 pos += 1;
180 }
181
182 if pos >= spans.len() {
183 return;
185 }
186
187 let name_pos = pos;
189
190 let Some(name) = parse_string(working_set, spans[name_pos]).as_string() else {
191 return;
192 };
193
194 if name.contains('#')
195 || name.contains('^')
196 || name.parse::<bytesize::ByteSize>().is_ok()
197 || name.parse::<f64>().is_ok()
198 {
199 working_set.error(ParseError::CommandDefNotValid(spans[name_pos]));
200 return;
201 }
202
203 let mut signature_pos = None;
205
206 while pos < spans.len() {
207 if working_set.get_span_contents(spans[pos]).starts_with(b"[")
208 || working_set.get_span_contents(spans[pos]).starts_with(b"(")
209 {
210 signature_pos = Some(pos);
211 break;
212 }
213
214 pos += 1;
215 }
216
217 let Some(signature_pos) = signature_pos else {
218 return;
219 };
220
221 let mut allow_unknown_args = false;
222
223 for span in spans {
224 if working_set.get_span_contents(*span) == b"--wrapped" && def_type_name == b"def" {
225 allow_unknown_args = true;
226 }
227 }
228
229 let starting_error_count = working_set.parse_errors.len();
230
231 working_set.enter_scope();
232 let sig = parse_full_signature(working_set, &spans[signature_pos..]);
239 working_set.parse_errors.truncate(starting_error_count);
240 working_set.exit_scope();
241
242 let Some(mut signature) = sig.as_signature() else {
243 return;
244 };
245
246 signature.name = name;
247
248 if allow_unknown_args {
249 signature.allows_unknown_args = true;
250 }
251
252 let decl = signature.predeclare();
253
254 if working_set.add_predecl(decl).is_some() {
255 working_set.error(ParseError::DuplicateCommandDef(spans[name_pos]));
256 }
257}
258
259pub fn parse_for(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Expression {
260 let spans = &lite_command.parts;
261 if working_set.get_span_contents(spans[0]) != b"for" {
264 working_set.error(ParseError::UnknownState(
265 "internal error: Wrong call name for 'for' function".into(),
266 Span::concat(spans),
267 ));
268 return garbage(working_set, spans[0]);
269 }
270 if let Some(redirection) = lite_command.redirection.as_ref() {
271 working_set.error(redirecting_builtin_error("for", redirection));
272 return garbage(working_set, spans[0]);
273 }
274
275 let (call, call_span) = match working_set.find_decl(b"for") {
279 None => {
280 working_set.error(ParseError::UnknownState(
281 "internal error: for declaration not found".into(),
282 Span::concat(spans),
283 ));
284 return garbage(working_set, spans[0]);
285 }
286 Some(decl_id) => {
287 let starting_error_count = working_set.parse_errors.len();
288 working_set.enter_scope();
289 let ParsedInternalCall {
290 call,
291 output,
292 call_kind,
293 } = parse_internal_call(
294 working_set,
295 spans[0],
296 &spans[1..],
297 decl_id,
298 ArgumentParsingLevel::Full,
299 );
300
301 if working_set
302 .parse_errors
303 .get(starting_error_count..)
304 .is_none_or(|new_errors| {
305 new_errors
306 .iter()
307 .all(|e| !matches!(e, ParseError::Unclosed(token, _) if token == "}"))
308 })
309 {
310 working_set.exit_scope();
311 }
312
313 let call_span = Span::concat(spans);
314 let decl = working_set.get_decl(decl_id);
315 let sig = decl.signature();
316
317 if call_kind != CallKind::Valid {
318 return Expression::new(working_set, Expr::Call(call), call_span, output);
319 }
320
321 if let Some(
323 Expression {
324 expr: Expr::Block(block_id),
325 ..
326 }
327 | Expression {
328 expr: Expr::RowCondition(block_id),
329 ..
330 },
331 ) = call.positional_nth(2)
332 {
333 {
334 let block = working_set.get_block_mut(*block_id);
335
336 block.signature = Box::new(sig);
337 }
338 }
339
340 (call, call_span)
341 }
342 };
343
344 let var_decl = call.positional_nth(0).expect("for call already checked");
346 let iteration_expr = call.positional_nth(1).expect("for call already checked");
347 let block = call.positional_nth(2).expect("for call already checked");
348
349 let iteration_expr_ty = iteration_expr.ty.clone();
350
351 let var_type = match iteration_expr_ty {
353 Type::List(x) => *x,
354 Type::Table(x) => Type::Record(x),
355 Type::Range => Type::Number, x => x,
357 };
358
359 if let (Some(var_id), Some(block_id)) = (&var_decl.as_var(), block.as_block()) {
360 working_set.set_variable_type(*var_id, var_type.clone());
361
362 let block = working_set.get_block_mut(block_id);
363
364 block.signature.required_positional.insert(
365 0,
366 PositionalArg {
367 name: String::new(),
368 desc: String::new(),
369 shape: var_type.to_shape(),
370 var_id: Some(*var_id),
371 default_value: None,
372 completion: None,
373 },
374 );
375 }
376
377 Expression::new(working_set, Expr::Call(call), call_span, Type::Nothing)
378}
379
380fn verify_not_reserved_variable_name(working_set: &mut StateWorkingSet, name: &str, span: Span) {
382 if RESERVED_VARIABLE_NAMES.contains(&name) {
383 working_set.error(ParseError::NameIsBuiltinVar(name.to_string(), span))
384 }
385}
386
387pub fn parse_attribute_block(
392 working_set: &mut StateWorkingSet,
393 lite_command: &LiteCommand,
394) -> Pipeline {
395 let attributes = lite_command
396 .attribute_commands()
397 .map(|cmd| parse_attribute(working_set, &cmd).0)
398 .collect::<Vec<_>>();
399
400 let last_attr_span = attributes
401 .last()
402 .expect("Attribute block must contain at least one attribute")
403 .expr
404 .span;
405
406 working_set.error(ParseError::AttributeRequiresDefinition(last_attr_span));
407 let cmd_span = if lite_command.command_parts().is_empty() {
408 last_attr_span.past()
409 } else {
410 Span::concat(lite_command.command_parts())
411 };
412 let cmd_expr = garbage(working_set, cmd_span);
413 let ty = cmd_expr.ty.clone();
414
415 let attr_block_span = Span::merge_many(
416 attributes
417 .first()
418 .map(|x| x.expr.span)
419 .into_iter()
420 .chain(Some(cmd_span)),
421 );
422
423 Pipeline::from_vec(vec![Expression::new(
424 working_set,
425 Expr::AttributeBlock(AttributeBlock {
426 attributes,
427 item: Box::new(cmd_expr),
428 }),
429 attr_block_span,
430 ty,
431 )])
432}
433
434pub fn parse_def(
436 working_set: &mut StateWorkingSet,
437 lite_command: &LiteCommand,
438 module_name: Option<&[u8]>,
439) -> (Pipeline, Option<(Vec<u8>, DeclId)>) {
440 let mut attributes = vec![];
441 let mut attribute_vals = vec![];
442
443 for attr_cmd in lite_command.attribute_commands() {
444 let (attr, name) = parse_attribute(working_set, &attr_cmd);
445 if let Some(name) = name {
446 let val = eval_constant(working_set, &attr.expr);
447 match val {
448 Ok(val) => attribute_vals.push((name, val)),
449 Err(e) => working_set.error(e.wrap(working_set, attr.expr.span)),
450 }
451 }
452 attributes.push(attr);
453 }
454
455 let (expr, decl) = parse_def_inner(working_set, attribute_vals, lite_command, module_name);
456
457 let ty = expr.ty.clone();
458
459 let attr_block_span = Span::merge_many(
460 attributes
461 .first()
462 .map(|x| x.expr.span)
463 .into_iter()
464 .chain(Some(expr.span)),
465 );
466
467 let expr = if attributes.is_empty() {
468 expr
469 } else {
470 Expression::new(
471 working_set,
472 Expr::AttributeBlock(AttributeBlock {
473 attributes,
474 item: Box::new(expr),
475 }),
476 attr_block_span,
477 ty,
478 )
479 };
480
481 (Pipeline::from_vec(vec![expr]), decl)
482}
483
484pub fn parse_extern(
485 working_set: &mut StateWorkingSet,
486 lite_command: &LiteCommand,
487 module_name: Option<&[u8]>,
488) -> Pipeline {
489 let mut attributes = vec![];
490 let mut attribute_vals = vec![];
491
492 for attr_cmd in lite_command.attribute_commands() {
493 let (attr, name) = parse_attribute(working_set, &attr_cmd);
494 if let Some(name) = name {
495 let val = eval_constant(working_set, &attr.expr);
496 match val {
497 Ok(val) => attribute_vals.push((name, val)),
498 Err(e) => working_set.error(e.wrap(working_set, attr.expr.span)),
499 }
500 }
501 attributes.push(attr);
502 }
503
504 let expr = parse_extern_inner(working_set, attribute_vals, lite_command, module_name);
505
506 let ty = expr.ty.clone();
507
508 let attr_block_span = Span::merge_many(
509 attributes
510 .first()
511 .map(|x| x.expr.span)
512 .into_iter()
513 .chain(Some(expr.span)),
514 );
515
516 let expr = if attributes.is_empty() {
517 expr
518 } else {
519 Expression::new(
520 working_set,
521 Expr::AttributeBlock(AttributeBlock {
522 attributes,
523 item: Box::new(expr),
524 }),
525 attr_block_span,
526 ty,
527 )
528 };
529
530 Pipeline::from_vec(vec![expr])
531}
532
533fn parse_def_inner(
535 working_set: &mut StateWorkingSet,
536 attributes: Vec<(String, Value)>,
537 lite_command: &LiteCommand,
538 module_name: Option<&[u8]>,
539) -> (Expression, Option<(Vec<u8>, DeclId)>) {
540 let spans = lite_command.command_parts();
541
542 let (desc, extra_desc) = working_set.build_desc(&lite_command.comments);
543 let garbage_result =
544 |working_set: &mut StateWorkingSet<'_>| (garbage(working_set, Span::concat(spans)), None);
545
546 let (name_span, split_id) =
551 if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
552 (spans[1], 2)
553 } else {
554 (spans[0], 1)
555 };
556
557 let def_call = working_set.get_span_contents(name_span);
558 if def_call != b"def" {
559 working_set.error(ParseError::UnknownState(
560 "internal error: Wrong call name for def function".into(),
561 Span::concat(spans),
562 ));
563 return garbage_result(working_set);
564 }
565 if let Some(redirection) = lite_command.redirection.as_ref() {
566 working_set.error(redirecting_builtin_error("def", redirection));
567 return garbage_result(working_set);
568 }
569
570 let (call, call_span) = match working_set.permanent_state.find_decl(def_call, &[]) {
578 None => {
579 working_set.error(ParseError::UnknownState(
580 "internal error: def declaration not found".into(),
581 Span::concat(spans),
582 ));
583 return garbage_result(working_set);
584 }
585 Some(decl_id) => {
586 working_set.enter_scope();
587 let (command_spans, rest_spans) = spans.split_at(split_id);
588
589 let mut decl_name_span = None;
591
592 for span in rest_spans {
593 if !working_set.get_span_contents(*span).starts_with(b"-") {
594 decl_name_span = Some(*span);
595 break;
596 }
597 }
598
599 if let Some(name_span) = decl_name_span {
600 if let Some(err) = detect_params_in_name(working_set, name_span, decl_id) {
602 working_set.error(err);
603 return garbage_result(working_set);
604 }
605 }
606
607 let starting_error_count = working_set.parse_errors.len();
608 let ParsedInternalCall {
609 call,
610 output,
611 call_kind,
612 } = parse_internal_call(
613 working_set,
614 Span::concat(command_spans),
615 rest_spans,
616 decl_id,
617 ArgumentParsingLevel::Full,
618 );
619
620 if working_set
621 .parse_errors
622 .get(starting_error_count..)
623 .is_none_or(|new_errors| {
624 new_errors
625 .iter()
626 .all(|e| !matches!(e, ParseError::Unclosed(token, _) if token == "}"))
627 })
628 {
629 working_set.exit_scope();
630 }
631
632 let call_span = Span::concat(spans);
633 let decl = working_set.get_decl(decl_id);
634 let sig = decl.signature();
635
636 if let Some(arg) = call.positional_nth(2) {
638 match arg {
639 Expression {
640 expr: Expr::Closure(block_id),
641 ..
642 } => {
643 compile_block_with_id(working_set, *block_id);
650 working_set.get_block_mut(*block_id).signature = Box::new(sig.clone());
651 }
652 _ => working_set.error(ParseError::Expected(
653 "definition body closure { ... }",
654 arg.span,
655 )),
656 }
657 }
658
659 if call_kind != CallKind::Valid {
660 return (
661 Expression::new(working_set, Expr::Call(call), call_span, output),
662 None,
663 );
664 }
665
666 (call, call_span)
667 }
668 };
669
670 let Ok(has_env) = has_flag_const(working_set, &call, "env") else {
671 return garbage_result(working_set);
672 };
673 let Ok(has_wrapped) = has_flag_const(working_set, &call, "wrapped") else {
674 return garbage_result(working_set);
675 };
676
677 let name_expr = call.positional_nth(0).expect("def call already checked");
679 let sig = call.positional_nth(1).expect("def call already checked");
680 let block = call.positional_nth(2).expect("def call already checked");
681
682 let name = if let Some(name) = name_expr.as_string() {
683 if let Some(mod_name) = module_name
684 && name.as_bytes() == mod_name
685 {
686 let name_expr_span = name_expr.span;
687
688 working_set.error(ParseError::NamedAsModule(
689 "command".to_string(),
690 name,
691 "main".to_string(),
692 name_expr_span,
693 ));
694 return (
695 Expression::new(working_set, Expr::Call(call), call_span, Type::Any),
696 None,
697 );
698 }
699
700 name
701 } else {
702 working_set.error(ParseError::UnknownState(
703 "Could not get string from string expression".into(),
704 name_expr.span,
705 ));
706 return garbage_result(working_set);
707 };
708
709 let mut result = None;
710
711 if let (Some(mut signature), Some(block_id)) = (sig.as_signature(), block.as_block()) {
712 for arg_name in &signature.required_positional {
713 verify_not_reserved_variable_name(working_set, &arg_name.name, sig.span);
714 }
715 for arg_name in &signature.optional_positional {
716 verify_not_reserved_variable_name(working_set, &arg_name.name, sig.span);
717 }
718 if let Some(arg_name) = &signature.rest_positional {
719 verify_not_reserved_variable_name(working_set, &arg_name.name, sig.span);
720 }
721 for flag_name in &signature.get_names() {
722 verify_not_reserved_variable_name(working_set, flag_name, sig.span);
723 }
724
725 if has_wrapped {
726 if let Some(rest) = &signature.rest_positional {
727 if let Some(var_id) = rest.var_id {
728 let rest_var = &working_set.get_variable(var_id);
729
730 if rest_var.ty != Type::Any && rest_var.ty != Type::List(Box::new(Type::String))
731 {
732 working_set.error(ParseError::TypeMismatchHelp(
733 Type::List(Box::new(Type::String)),
734 rest_var.ty.clone(),
735 rest_var.declaration_span,
736 format!("...rest-like positional argument used in 'def --wrapped' supports only strings. Change the type annotation of ...{} to 'string'.", &rest.name)));
737
738 return (
739 Expression::new(working_set, Expr::Call(call), call_span, Type::Any),
740 result,
741 );
742 }
743 }
744 } else {
745 working_set.error(ParseError::MissingPositional("...rest-like positional argument".to_string(), name_expr.span, "def --wrapped must have a ...rest-like positional argument. Add '...rest: string' to the command's signature.".to_string()));
746
747 return (
748 Expression::new(working_set, Expr::Call(call), call_span, Type::Any),
749 result,
750 );
751 }
752 }
753
754 if let Some(decl_id) = working_set.find_predecl(name.as_bytes()) {
755 signature.name.clone_from(&name);
756 if !has_wrapped {
757 *signature = signature.add_help();
758 }
759 signature.description = desc;
760 signature.extra_description = extra_desc;
761 signature.allows_unknown_args = has_wrapped;
762
763 let (attribute_vals, examples) =
764 handle_special_attributes(attributes, working_set, &mut signature);
765
766 let declaration = working_set.get_decl_mut(decl_id);
767
768 *declaration = signature
769 .clone()
770 .into_block_command(block_id, attribute_vals, examples);
771
772 let block = working_set.get_block_mut(block_id);
773 block.signature = signature;
774 block.redirect_env = has_env;
775
776 if block.signature.input_output_types.is_empty() {
777 block
778 .signature
779 .input_output_types
780 .push((Type::Any, Type::Any));
781 }
782
783 let block = working_set.get_block(block_id);
784
785 let typecheck_errors = check_block_input_output(working_set, block);
786
787 working_set
788 .parse_errors
789 .extend_from_slice(&typecheck_errors);
790
791 result = Some((name.as_bytes().to_vec(), decl_id));
792 } else {
793 working_set.error(ParseError::InternalError(
794 "Predeclaration failed to add declaration".into(),
795 name_expr.span,
796 ));
797 };
798 }
799
800 working_set.merge_predecl(name.as_bytes());
802
803 (
804 Expression::new(working_set, Expr::Call(call), call_span, Type::Any),
805 result,
806 )
807}
808
809fn parse_extern_inner(
810 working_set: &mut StateWorkingSet,
811 attributes: Vec<(String, Value)>,
812 lite_command: &LiteCommand,
813 module_name: Option<&[u8]>,
814) -> Expression {
815 let spans = lite_command.command_parts();
816
817 let (description, extra_description) = working_set.build_desc(&lite_command.comments);
818
819 let (name_span, split_id) =
823 if spans.len() > 1 && (working_set.get_span_contents(spans[0]) == b"export") {
824 (spans[1], 2)
825 } else {
826 (spans[0], 1)
827 };
828
829 let extern_call = working_set.get_span_contents(name_span);
830 if extern_call != b"extern" {
831 working_set.error(ParseError::UnknownState(
832 "internal error: Wrong call name for extern command".into(),
833 Span::concat(spans),
834 ));
835 return garbage(working_set, Span::concat(spans));
836 }
837 if let Some(redirection) = lite_command.redirection.as_ref() {
838 working_set.error(redirecting_builtin_error("extern", redirection));
839 return garbage(working_set, Span::concat(spans));
840 }
841
842 let (call, call_span) = match working_set.permanent().find_decl(extern_call, &[]) {
850 None => {
851 working_set.error(ParseError::UnknownState(
852 "internal error: def declaration not found".into(),
853 Span::concat(spans),
854 ));
855 return garbage(working_set, Span::concat(spans));
856 }
857 Some(decl_id) => {
858 working_set.enter_scope();
859
860 let (command_spans, rest_spans) = spans.split_at(split_id);
861
862 if let Some(name_span) = rest_spans.first()
863 && let Some(err) = detect_params_in_name(working_set, *name_span, decl_id)
864 {
865 working_set.error(err);
866 return garbage(working_set, Span::concat(spans));
867 }
868
869 let ParsedInternalCall { call, .. } = parse_internal_call(
870 working_set,
871 Span::concat(command_spans),
872 rest_spans,
873 decl_id,
874 ArgumentParsingLevel::Full,
875 );
876 working_set.exit_scope();
877
878 let call_span = Span::concat(spans);
879
880 (call, call_span)
881 }
882 };
883 let name_expr = call.positional_nth(0);
884 let sig = call.positional_nth(1);
885 let body = call.positional_nth(2);
886
887 if let (Some(name_expr), Some(sig)) = (name_expr, sig) {
888 if let (Some(name), Some(mut signature)) = (&name_expr.as_string(), sig.as_signature()) {
889 if let Some(mod_name) = module_name
890 && name.as_bytes() == mod_name
891 {
892 let name_expr_span = name_expr.span;
893 working_set.error(ParseError::NamedAsModule(
894 "known external".to_string(),
895 name.clone(),
896 "main".to_string(),
897 name_expr_span,
898 ));
899 return Expression::new(working_set, Expr::Call(call), call_span, Type::Any);
900 }
901
902 if let Some(decl_id) = working_set.find_predecl(name.as_bytes()) {
903 let external_name = if let Some(mod_name) = module_name {
904 if name.as_bytes() == b"main" {
905 String::from_utf8_lossy(mod_name).to_string()
906 } else {
907 name.clone()
908 }
909 } else {
910 name.clone()
911 };
912
913 signature.name = external_name;
914 signature.description = description;
915 signature.extra_description = extra_description;
916 signature.allows_unknown_args = true;
917
918 let (attribute_vals, examples) =
919 handle_special_attributes(attributes, working_set, &mut signature);
920
921 let declaration = working_set.get_decl_mut(decl_id);
922
923 if let Some(block_id) = body.and_then(|x| x.as_block()) {
924 if signature.rest_positional.is_none() {
925 working_set.error(ParseError::InternalError(
926 "Extern block must have a rest positional argument".into(),
927 name_expr.span,
928 ));
929 } else {
930 *declaration = signature.clone().into_block_command(
931 block_id,
932 attribute_vals,
933 examples,
934 );
935
936 working_set.get_block_mut(block_id).signature = signature;
937 }
938 } else {
939 if signature.rest_positional.is_none() {
940 *signature = signature.rest(
943 "args",
944 SyntaxShape::ExternalArgument,
945 "all other arguments to the command",
946 );
947 }
948
949 let decl = KnownExternal {
950 signature,
951 attributes: attribute_vals,
952 examples,
953 };
954
955 *declaration = Box::new(decl);
956 }
957 } else {
958 working_set.error(ParseError::InternalError(
959 "Predeclaration failed to add declaration".into(),
960 spans[split_id],
961 ));
962 };
963 }
964 if let Some(name) = name_expr.as_string() {
965 working_set.merge_predecl(name.as_bytes());
967 } else {
968 working_set.error(ParseError::UnknownState(
969 "Could not get string from string expression".into(),
970 name_expr.span,
971 ));
972 }
973 }
974
975 Expression::new(working_set, Expr::Call(call), call_span, Type::Any)
976}
977
978fn handle_special_attributes(
979 attributes: Vec<(String, Value)>,
980 working_set: &mut StateWorkingSet<'_>,
981 signature: &mut Signature,
982) -> (Vec<(String, Value)>, Vec<CustomExample>) {
983 let mut attribute_vals = vec![];
984 let mut examples = vec![];
985 let mut search_terms = vec![];
986 let mut category = String::new();
987
988 for (name, value) in attributes {
989 let val_span = value.span();
990 match name.as_str() {
991 "example" => match CustomExample::from_value(value) {
992 Ok(example) => examples.push(example),
993 Err(_) => {
994 let e = ShellError::GenericError {
995 error: "nu::shell::invalid_example".into(),
996 msg: "Value couldn't be converted to an example".into(),
997 span: Some(val_span),
998 help: Some("Is `attr example` shadowed?".into()),
999 inner: vec![],
1000 };
1001 working_set.error(e.wrap(working_set, val_span));
1002 }
1003 },
1004 "search-terms" => match <Vec<String>>::from_value(value) {
1005 Ok(mut terms) => {
1006 search_terms.append(&mut terms);
1007 }
1008 Err(_) => {
1009 let e = ShellError::GenericError {
1010 error: "nu::shell::invalid_search_terms".into(),
1011 msg: "Value couldn't be converted to search-terms".into(),
1012 span: Some(val_span),
1013 help: Some("Is `attr search-terms` shadowed?".into()),
1014 inner: vec![],
1015 };
1016 working_set.error(e.wrap(working_set, val_span));
1017 }
1018 },
1019 "category" => match <String>::from_value(value) {
1020 Ok(term) => {
1021 category.push_str(&term);
1022 }
1023 Err(_) => {
1024 let e = ShellError::GenericError {
1025 error: "nu::shell::invalid_category".into(),
1026 msg: "Value couldn't be converted to category".into(),
1027 span: Some(val_span),
1028 help: Some("Is `attr category` shadowed?".into()),
1029 inner: vec![],
1030 };
1031 working_set.error(e.wrap(working_set, val_span));
1032 }
1033 },
1034 "complete" => match <Spanned<String>>::from_value(value) {
1035 Ok(Spanned { item, span }) => {
1036 if let Some(decl) = working_set.find_decl(item.as_bytes()) {
1037 signature.complete = Some(CommandWideCompleter::Command(decl));
1040 } else {
1041 working_set.error(ParseError::UnknownCommand(span));
1042 }
1043 }
1044 Err(_) => {
1045 let e = ShellError::GenericError {
1046 error: "nu::shell::invalid_completer".into(),
1047 msg: "Value couldn't be converted to a completer".into(),
1048 span: Some(val_span),
1049 help: Some("Is `attr complete` shadowed?".into()),
1050 inner: vec![],
1051 };
1052 working_set.error(e.wrap(working_set, val_span));
1053 }
1054 },
1055 "complete external" => match value {
1056 Value::Nothing { .. } => {
1057 signature.complete = Some(CommandWideCompleter::External);
1058 }
1059 _ => {
1060 let e = ShellError::GenericError {
1061 error: "nu::shell::invalid_completer".into(),
1062 msg: "This attribute shouldn't return anything".into(),
1063 span: Some(val_span),
1064 help: Some("Is `attr complete` shadowed?".into()),
1065 inner: vec![],
1066 };
1067 working_set.error(e.wrap(working_set, val_span));
1068 }
1069 },
1070 _ => {
1071 attribute_vals.push((name, value));
1072 }
1073 }
1074 }
1075
1076 signature.search_terms = search_terms;
1077 signature.category = category_from_string(&category);
1078
1079 (attribute_vals, examples)
1080}
1081
1082fn check_alias_name<'a>(working_set: &mut StateWorkingSet, spans: &'a [Span]) -> Option<&'a Span> {
1083 let command_len = if !spans.is_empty() {
1084 if working_set.get_span_contents(spans[0]) == b"export" {
1085 2
1086 } else {
1087 1
1088 }
1089 } else {
1090 return None;
1091 };
1092
1093 if spans.len() == command_len {
1094 None
1095 } else if spans.len() < command_len + 3 {
1096 if working_set.get_span_contents(spans[command_len]) == b"=" {
1097 let name = String::from_utf8_lossy(
1098 working_set.get_span_contents(Span::concat(&spans[..command_len])),
1099 );
1100 working_set.error(ParseError::AssignmentMismatch(
1101 format!("{name} missing name"),
1102 "missing name".into(),
1103 spans[command_len],
1104 ));
1105 Some(&spans[command_len])
1106 } else {
1107 None
1108 }
1109 } else if working_set.get_span_contents(spans[command_len + 1]) != b"=" {
1110 let name = String::from_utf8_lossy(
1111 working_set.get_span_contents(Span::concat(&spans[..command_len])),
1112 );
1113 working_set.error(ParseError::AssignmentMismatch(
1114 format!("{name} missing sign"),
1115 "missing equal sign".into(),
1116 spans[command_len + 1],
1117 ));
1118 Some(&spans[command_len + 1])
1119 } else {
1120 None
1121 }
1122}
1123
1124pub fn parse_alias(
1125 working_set: &mut StateWorkingSet,
1126 lite_command: &LiteCommand,
1127 module_name: Option<&[u8]>,
1128) -> Pipeline {
1129 let spans = &lite_command.parts;
1130
1131 let (name_span, split_id) =
1132 if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
1133 (spans[1], 2)
1134 } else {
1135 (spans[0], 1)
1136 };
1137
1138 let name = working_set.get_span_contents(name_span);
1139
1140 if name != b"alias" {
1141 working_set.error(ParseError::InternalError(
1142 "Alias statement unparsable".into(),
1143 Span::concat(spans),
1144 ));
1145 return garbage_pipeline(working_set, spans);
1146 }
1147 if let Some(redirection) = lite_command.redirection.as_ref() {
1148 working_set.error(redirecting_builtin_error("alias", redirection));
1149 return garbage_pipeline(working_set, spans);
1150 }
1151
1152 if let Some(span) = check_alias_name(working_set, spans) {
1153 return Pipeline::from_vec(vec![garbage(working_set, *span)]);
1154 }
1155
1156 if let Some(decl_id) = working_set.find_decl(b"alias") {
1157 let (command_spans, rest_spans) = spans.split_at(split_id);
1158
1159 let original_starting_error_count = working_set.parse_errors.len();
1160
1161 let ParsedInternalCall {
1162 call: alias_call,
1163 output,
1164 call_kind,
1165 } = parse_internal_call(
1166 working_set,
1167 Span::concat(command_spans),
1168 rest_spans,
1169 decl_id,
1170 ArgumentParsingLevel::Full,
1171 );
1172
1173 working_set
1174 .parse_errors
1175 .truncate(original_starting_error_count);
1176
1177 let alias_pipeline = Pipeline::from_vec(vec![Expression::new(
1178 working_set,
1179 Expr::Call(alias_call.clone()),
1180 Span::concat(spans),
1181 output,
1182 )]);
1183
1184 if call_kind == CallKind::Help {
1185 return alias_pipeline;
1186 }
1187
1188 let Some(alias_name_expr) = alias_call.positional_nth(0) else {
1189 working_set.error(ParseError::UnknownState(
1190 "Missing positional after call check".to_string(),
1191 Span::concat(spans),
1192 ));
1193 return garbage_pipeline(working_set, spans);
1194 };
1195
1196 let alias_name = if let Some(name) = alias_name_expr.as_string() {
1197 if name.contains('#')
1198 || name.contains('^')
1199 || name.parse::<bytesize::ByteSize>().is_ok()
1200 || name.parse::<f64>().is_ok()
1201 {
1202 working_set.error(ParseError::AliasNotValid(alias_name_expr.span));
1203 return garbage_pipeline(working_set, spans);
1204 } else {
1205 name
1206 }
1207 } else {
1208 working_set.error(ParseError::AliasNotValid(alias_name_expr.span));
1209 return garbage_pipeline(working_set, spans);
1210 };
1211
1212 if spans.len() >= split_id + 3 {
1213 if let Some(mod_name) = module_name {
1214 if alias_name.as_bytes() == mod_name {
1215 working_set.error(ParseError::NamedAsModule(
1216 "alias".to_string(),
1217 alias_name,
1218 "main".to_string(),
1219 spans[split_id],
1220 ));
1221
1222 return alias_pipeline;
1223 }
1224
1225 if alias_name == "main" {
1226 working_set.error(ParseError::ExportMainAliasNotAllowed(spans[split_id]));
1227 return alias_pipeline;
1228 }
1229 }
1230
1231 let _equals = working_set.get_span_contents(spans[split_id + 1]);
1232
1233 let replacement_spans = &spans[(split_id + 2)..];
1234 let first_bytes = working_set.get_span_contents(replacement_spans[0]);
1235
1236 if first_bytes != b"if"
1237 && first_bytes != b"match"
1238 && is_math_expression_like(working_set, replacement_spans[0])
1239 {
1240 let starting_error_count = working_set.parse_errors.len();
1242 let expr = parse_expression(working_set, replacement_spans);
1243 working_set.parse_errors.truncate(starting_error_count);
1244
1245 let msg = format!("{:?}", expr.expr);
1246 let msg_parts: Vec<&str> = msg.split('(').collect();
1247
1248 working_set.error(ParseError::CantAliasExpression(
1249 msg_parts[0].to_string(),
1250 replacement_spans[0],
1251 ));
1252 return alias_pipeline;
1253 }
1254
1255 let starting_error_count = working_set.parse_errors.len();
1256 working_set.search_predecls = false;
1257
1258 let expr = parse_call(working_set, replacement_spans, replacement_spans[0]);
1259
1260 working_set.search_predecls = true;
1261
1262 if starting_error_count != working_set.parse_errors.len()
1263 && let Some(e) = working_set.parse_errors.get(starting_error_count)
1264 {
1265 if let ParseError::MissingPositional(..)
1266 | ParseError::MissingRequiredFlag(..)
1267 | ParseError::MissingFlagParam(..) = e
1268 {
1269 working_set
1270 .parse_errors
1271 .truncate(original_starting_error_count);
1272 } else {
1274 return garbage_pipeline(working_set, replacement_spans);
1275 }
1276 }
1277
1278 let (command, wrapped_call) = match expr {
1279 Expression {
1280 expr: Expr::Call(ref rhs_call),
1281 ..
1282 } => {
1283 let cmd = working_set.get_decl(rhs_call.decl_id);
1284
1285 if cmd.is_keyword()
1286 && !ALIASABLE_PARSER_KEYWORDS.contains(&cmd.name().as_bytes())
1287 {
1288 working_set.error(ParseError::CantAliasKeyword(
1289 ALIASABLE_PARSER_KEYWORDS
1290 .iter()
1291 .map(|bytes| String::from_utf8_lossy(bytes).to_string())
1292 .collect::<Vec<String>>()
1293 .join(", "),
1294 rhs_call.head,
1295 ));
1296 return alias_pipeline;
1297 }
1298
1299 (Some(cmd.clone_box()), expr)
1300 }
1301 Expression {
1302 expr: Expr::ExternalCall(..),
1303 ..
1304 } => (None, expr),
1305 _ => {
1306 working_set.error(ParseError::InternalError(
1307 "Parsed call not a call".into(),
1308 expr.span,
1309 ));
1310 return alias_pipeline;
1311 }
1312 };
1313
1314 let (description, extra_description) = match lite_command.comments.is_empty() {
1316 false => working_set.build_desc(&lite_command.comments),
1318 true => match alias_call.arguments.get(1) {
1320 Some(Argument::Positional(Expression {
1321 expr: Expr::Keyword(kw),
1322 ..
1323 })) => {
1324 let aliased = working_set.get_span_contents(kw.expr.span);
1325 (
1326 format!("Alias for `{}`", String::from_utf8_lossy(aliased)),
1327 String::new(),
1328 )
1329 }
1330 _ => ("User declared alias".into(), String::new()),
1332 },
1333 };
1334
1335 let decl = Alias {
1336 name: alias_name,
1337 command,
1338 wrapped_call,
1339 description,
1340 extra_description,
1341 };
1342
1343 working_set.add_decl(Box::new(decl));
1344 }
1345
1346 if spans.len() == 2 && working_set.get_span_contents(spans[1]).contains(&b'=') {
1348 let arg = String::from_utf8_lossy(working_set.get_span_contents(spans[1]));
1349
1350 let (name, initial_value) = arg.split_once('=').unwrap_or((&arg, ""));
1354
1355 let name = if name.is_empty() { "{name}" } else { name };
1356 let initial_value = if initial_value.is_empty() {
1357 "{initial_value}"
1358 } else {
1359 initial_value
1360 };
1361
1362 working_set.error(ParseError::IncorrectValue(
1363 "alias argument".into(),
1364 spans[1],
1365 format!("Make sure to put spaces around '=': alias {name} = {initial_value}"),
1366 ))
1367 } else if spans.len() < 4 {
1368 working_set.error(ParseError::IncorrectValue(
1369 "Incomplete alias".into(),
1370 Span::concat(&spans[..split_id]),
1371 "incomplete alias".into(),
1372 ));
1373 }
1374
1375 return alias_pipeline;
1376 }
1377
1378 working_set.error(ParseError::InternalError(
1379 "Alias statement unparsable".into(),
1380 Span::concat(spans),
1381 ));
1382
1383 garbage_pipeline(working_set, spans)
1384}
1385
1386fn warp_export_call(
1389 working_set: &mut StateWorkingSet,
1390 pipeline: &mut Pipeline,
1391 full_name: &str,
1392 spans: &[Span],
1393) -> bool {
1394 let Some(export_decl_id) = working_set.find_decl(full_name.as_bytes()) else {
1395 let error_span = spans.first().cloned().unwrap_or(Span::unknown());
1396 working_set.error(ParseError::InternalError(
1397 format!("missing '{full_name}' command"),
1398 error_span,
1399 ));
1400 return false;
1401 };
1402 match pipeline.elements.first_mut().map(|e| {
1403 e.expr.span = Span::concat(spans);
1404 &mut e.expr.expr
1405 }) {
1406 Some(Expr::Call(def_call)) => {
1407 def_call.head = Span::concat(&spans[0..=1]);
1408 def_call.decl_id = export_decl_id;
1409 return true;
1410 }
1411 Some(Expr::AttributeBlock(ab)) => {
1412 if let Expr::Call(def_call) = &mut ab.item.expr {
1413 def_call.decl_id = export_decl_id;
1414 return true;
1415 }
1416 }
1417 _ => {}
1418 };
1419 working_set.error(ParseError::InternalError(
1420 "unexpected output from parsing a definition".into(),
1421 Span::concat(&spans[1..]),
1422 ));
1423 true
1424}
1425
1426pub fn parse_export_in_block(
1428 working_set: &mut StateWorkingSet,
1429 lite_command: &LiteCommand,
1430) -> Pipeline {
1431 let parts = lite_command.command_parts();
1432 let full_name = if parts.len() > 1 {
1433 let sub = working_set.get_span_contents(parts[1]);
1434 match sub {
1435 b"alias" => "export alias",
1436 b"def" => "export def",
1437 b"extern" => "export extern",
1438 b"use" => "export use",
1439 b"module" => "export module",
1440 b"const" => "export const",
1441 _ => "export",
1442 }
1443 } else {
1444 "export"
1445 };
1446
1447 if let Some(redirection) = lite_command.redirection.as_ref() {
1448 working_set.error(redirecting_builtin_error(full_name, redirection));
1449 return garbage_pipeline(working_set, &lite_command.parts);
1450 }
1451
1452 let mut pipeline = match full_name {
1453 "export def" => parse_def(working_set, lite_command, None).0,
1455 "export extern" => parse_extern(working_set, lite_command, None),
1456 _ if lite_command.has_attributes() => parse_attribute_block(working_set, lite_command),
1458 "export alias" => parse_alias(working_set, lite_command, None),
1459 "export const" => parse_const(working_set, &lite_command.parts[1..]).0,
1460 "export use" => parse_use(working_set, lite_command, None).0,
1461 "export module" => parse_module(working_set, lite_command, None).0,
1462 _ => {
1463 if let Some(decl_id) = working_set.find_decl(full_name.as_bytes()) {
1464 let starting_error_count = working_set.parse_errors.len();
1465 let ParsedInternalCall {
1466 call,
1467 output,
1468 call_kind,
1469 } = parse_internal_call(
1470 working_set,
1471 parts[0],
1472 &parts[1..],
1473 decl_id,
1474 ArgumentParsingLevel::Full,
1475 );
1476
1477 if call_kind != CallKind::Valid {
1478 return Pipeline::from_vec(vec![Expression::new(
1479 working_set,
1480 Expr::Call(call),
1481 Span::concat(&lite_command.parts),
1482 output,
1483 )]);
1484 }
1485 working_set.parse_errors.truncate(starting_error_count);
1487 working_set.error(ParseError::UnexpectedKeyword(
1488 full_name.into(),
1489 lite_command.parts[0],
1490 ));
1491 } else {
1492 working_set.error(ParseError::UnknownState(
1493 format!("internal error: '{full_name}' declaration not found",),
1494 Span::concat(&lite_command.parts),
1495 ));
1496 };
1497 garbage_pipeline(working_set, &lite_command.parts)
1498 }
1499 };
1500
1501 warp_export_call(working_set, &mut pipeline, full_name, &lite_command.parts);
1503 pipeline
1504}
1505
1506pub fn parse_export_in_module(
1508 working_set: &mut StateWorkingSet,
1509 lite_command: &LiteCommand,
1510 module_name: &[u8],
1511 parent_module: &mut Module,
1512) -> (Pipeline, Vec<Exportable>) {
1513 let spans = lite_command.command_parts();
1514
1515 let export_span = if let Some(sp) = spans.first() {
1516 if working_set.get_span_contents(*sp) != b"export" {
1517 working_set.error(ParseError::UnknownState(
1518 "expected export statement".into(),
1519 Span::concat(spans),
1520 ));
1521 return (garbage_pipeline(working_set, spans), vec![]);
1522 }
1523
1524 *sp
1525 } else {
1526 working_set.error(ParseError::UnknownState(
1527 "got empty input for parsing export statement".into(),
1528 Span::concat(spans),
1529 ));
1530 return (garbage_pipeline(working_set, spans), vec![]);
1531 };
1532
1533 let (pipeline, exportables) = if let Some(kw_span) = spans.get(1) {
1534 let kw_name = working_set.get_span_contents(*kw_span);
1535 match kw_name {
1536 b"def" => {
1538 let (mut pipeline, cmd_result) =
1539 parse_def(working_set, lite_command, Some(module_name));
1540
1541 let mut result = vec![];
1542
1543 if let Some((decl_name, decl_id)) = cmd_result {
1544 result.push(Exportable::Decl {
1545 name: decl_name.to_vec(),
1546 id: decl_id,
1547 });
1548 }
1549
1550 if !warp_export_call(working_set, &mut pipeline, "export def", spans) {
1552 return (garbage_pipeline(working_set, spans), vec![]);
1553 }
1554
1555 (pipeline, result)
1556 }
1557 b"extern" => {
1558 let mut pipeline = parse_extern(working_set, lite_command, Some(module_name));
1559
1560 if !warp_export_call(working_set, &mut pipeline, "export extern", spans) {
1562 return (garbage_pipeline(working_set, spans), vec![]);
1563 }
1564
1565 let mut result = vec![];
1566
1567 let decl_name = match spans.get(2) {
1568 Some(span) => working_set.get_span_contents(*span),
1569 None => &[],
1570 };
1571 let decl_name = trim_quotes(decl_name);
1572
1573 if let Some(decl_id) = working_set.find_decl(decl_name) {
1574 result.push(Exportable::Decl {
1575 name: decl_name.to_vec(),
1576 id: decl_id,
1577 });
1578 } else {
1579 working_set.error(ParseError::InternalError(
1580 "failed to find added declaration".into(),
1581 Span::concat(&spans[1..]),
1582 ));
1583 }
1584
1585 (pipeline, result)
1586 }
1587 _ if lite_command.has_attributes() => {
1589 (parse_attribute_block(working_set, lite_command), vec![])
1590 }
1591 b"alias" => {
1592 let lite_command = LiteCommand {
1593 comments: lite_command.comments.clone(),
1594 parts: spans[1..].to_vec(),
1595 pipe: lite_command.pipe,
1596 redirection: lite_command.redirection.clone(),
1597 attribute_idx: vec![],
1598 };
1599 let mut pipeline = parse_alias(working_set, &lite_command, Some(module_name));
1600
1601 if !warp_export_call(working_set, &mut pipeline, "export alias", spans) {
1603 return (garbage_pipeline(working_set, spans), vec![]);
1604 }
1605
1606 let mut result = vec![];
1607
1608 let alias_name = match spans.get(2) {
1609 Some(span) => working_set.get_span_contents(*span),
1610 None => &[],
1611 };
1612 let alias_name = trim_quotes(alias_name);
1613
1614 if let Some(alias_id) = working_set.find_decl(alias_name) {
1615 result.push(Exportable::Decl {
1616 name: alias_name.to_vec(),
1617 id: alias_id,
1618 });
1619 } else {
1620 working_set.error(ParseError::InternalError(
1621 "failed to find added alias".into(),
1622 Span::concat(&spans[1..]),
1623 ));
1624 }
1625
1626 (pipeline, result)
1627 }
1628 b"use" => {
1629 let lite_command = LiteCommand {
1630 comments: lite_command.comments.clone(),
1631 parts: spans[1..].to_vec(),
1632 pipe: lite_command.pipe,
1633 redirection: lite_command.redirection.clone(),
1634 attribute_idx: vec![],
1635 };
1636 let (mut pipeline, exportables) =
1637 parse_use(working_set, &lite_command, Some(parent_module));
1638
1639 if !warp_export_call(working_set, &mut pipeline, "export use", spans) {
1641 return (garbage_pipeline(working_set, spans), vec![]);
1642 }
1643
1644 (pipeline, exportables)
1645 }
1646 b"module" => {
1647 let (mut pipeline, maybe_module_id) =
1648 parse_module(working_set, lite_command, Some(module_name));
1649
1650 if !warp_export_call(working_set, &mut pipeline, "export module", spans) {
1652 return (garbage_pipeline(working_set, spans), vec![]);
1653 }
1654
1655 let mut result = vec![];
1656
1657 if let Some(module_name_span) = spans.get(2) {
1658 let module_name = working_set.get_span_contents(*module_name_span);
1659 let module_name = trim_quotes(module_name);
1660
1661 if let Some(module_id) = maybe_module_id {
1662 result.push(Exportable::Module {
1663 name: working_set.get_module(module_id).name(),
1664 id: module_id,
1665 });
1666 } else {
1667 working_set.error(ParseError::InternalError(
1668 format!(
1669 "failed to find added module '{}'",
1670 String::from_utf8_lossy(module_name)
1671 ),
1672 Span::concat(&spans[1..]),
1673 ));
1674 }
1675 }
1676
1677 (pipeline, result)
1678 }
1679 b"const" => {
1680 let (mut pipeline, var_name_span) = parse_const(working_set, &spans[1..]);
1681
1682 if !warp_export_call(working_set, &mut pipeline, "export const", spans) {
1684 return (garbage_pipeline(working_set, spans), vec![]);
1685 }
1686
1687 let mut result = vec![];
1688
1689 if let Some(var_name_span) = var_name_span {
1690 let var_name = working_set.get_span_contents(var_name_span);
1691 let var_name = trim_quotes(var_name);
1692
1693 if let Some(var_id) = working_set.find_variable(var_name) {
1694 if let Err(err) = working_set.get_constant(var_id) {
1695 working_set.error(err);
1696 } else {
1697 result.push(Exportable::VarDecl {
1698 name: var_name.to_vec(),
1699 id: var_id,
1700 });
1701 }
1702 } else {
1703 working_set.error(ParseError::InternalError(
1704 "failed to find added variable".into(),
1705 Span::concat(&spans[1..]),
1706 ));
1707 }
1708 }
1709
1710 (pipeline, result)
1711 }
1712 _ => {
1713 working_set.error(ParseError::Expected(
1714 "def, alias, use, module, const or extern keyword",
1715 spans[1],
1716 ));
1717
1718 (garbage_pipeline(working_set, spans), vec![])
1719 }
1720 }
1721 } else {
1722 working_set.error(ParseError::MissingPositional(
1723 "def, alias, use, module, const or extern keyword".to_string(),
1724 Span::new(export_span.end, export_span.end),
1725 "def, alias, use, module, const or extern keyword".to_string(),
1726 ));
1727
1728 (garbage_pipeline(working_set, spans), vec![])
1729 };
1730
1731 (pipeline, exportables)
1732}
1733
1734pub fn parse_export_env(
1735 working_set: &mut StateWorkingSet,
1736 spans: &[Span],
1737) -> (Pipeline, Option<BlockId>) {
1738 if !spans.is_empty() && working_set.get_span_contents(spans[0]) != b"export-env" {
1739 working_set.error(ParseError::UnknownState(
1740 "internal error: Wrong call name for 'export-env' command".into(),
1741 Span::concat(spans),
1742 ));
1743 return (garbage_pipeline(working_set, spans), None);
1744 }
1745
1746 if spans.len() < 2 {
1747 working_set.error(ParseError::MissingPositional(
1748 "block".into(),
1749 Span::concat(spans),
1750 "export-env <block>".into(),
1751 ));
1752 return (garbage_pipeline(working_set, spans), None);
1753 }
1754
1755 let call = match working_set.find_decl(b"export-env") {
1756 Some(decl_id) => {
1757 let ParsedInternalCall {
1758 call,
1759 output,
1760 call_kind,
1761 } = parse_internal_call(
1762 working_set,
1763 spans[0],
1764 &[spans[1]],
1765 decl_id,
1766 ArgumentParsingLevel::Full,
1767 );
1768
1769 if call_kind != CallKind::Valid {
1770 return (
1771 Pipeline::from_vec(vec![Expression::new(
1772 working_set,
1773 Expr::Call(call),
1774 Span::concat(spans),
1775 output,
1776 )]),
1777 None,
1778 );
1779 }
1780
1781 call
1782 }
1783 None => {
1784 working_set.error(ParseError::UnknownState(
1785 "internal error: 'export-env' declaration not found".into(),
1786 Span::concat(spans),
1787 ));
1788 return (garbage_pipeline(working_set, spans), None);
1789 }
1790 };
1791
1792 let block_id = if let Some(block) = call.positional_nth(0) {
1793 if let Some(block_id) = block.as_block() {
1794 block_id
1795 } else {
1796 working_set.error(ParseError::UnknownState(
1797 "internal error: 'export-env' block is not a block".into(),
1798 block.span,
1799 ));
1800 return (garbage_pipeline(working_set, spans), None);
1801 }
1802 } else {
1803 working_set.error(ParseError::UnknownState(
1804 "internal error: 'export-env' block is missing".into(),
1805 Span::concat(spans),
1806 ));
1807 return (garbage_pipeline(working_set, spans), None);
1808 };
1809
1810 let pipeline = Pipeline::from_vec(vec![Expression::new(
1811 working_set,
1812 Expr::Call(call),
1813 Span::concat(spans),
1814 Type::Any,
1815 )]);
1816
1817 compile_block_with_id(working_set, block_id);
1825
1826 (pipeline, Some(block_id))
1827}
1828
1829fn collect_first_comments(tokens: &[Token]) -> Vec<Span> {
1830 let mut comments = vec![];
1831
1832 let mut tokens_iter = tokens.iter().peekable();
1833 while let Some(token) = tokens_iter.next() {
1834 match token.contents {
1835 TokenContents::Comment => {
1836 comments.push(token.span);
1837 }
1838 TokenContents::Eol => {
1839 if let Some(Token {
1840 contents: TokenContents::Eol,
1841 ..
1842 }) = tokens_iter.peek()
1843 && !comments.is_empty()
1844 {
1845 break;
1846 }
1847 }
1848 _ => {
1849 comments.clear();
1850 break;
1851 }
1852 }
1853 }
1854
1855 comments
1856}
1857
1858pub fn parse_module_block(
1859 working_set: &mut StateWorkingSet,
1860 span: Span,
1861 module_name: &[u8],
1862) -> (Block, Module, Vec<Span>) {
1863 working_set.enter_scope();
1864
1865 let source = working_set.get_span_contents(span);
1866
1867 let (output, err) = lex(source, span.start, &[], &[], false);
1868 if let Some(err) = err {
1869 working_set.error(err)
1870 }
1871
1872 let module_comments = collect_first_comments(&output);
1873
1874 let (output, err) = lite_parse(&output, working_set);
1875 if let Some(err) = err {
1876 working_set.error(err)
1877 }
1878
1879 for pipeline in &output.block {
1880 if pipeline.commands.len() == 1 {
1881 parse_def_predecl(working_set, pipeline.commands[0].command_parts());
1882 }
1883 }
1884
1885 let mut module = Module::from_span(module_name.to_vec(), span);
1886
1887 let mut block = Block::new_with_capacity(output.block.len());
1888 block.span = Some(span);
1889
1890 for pipeline in output.block.iter() {
1891 if pipeline.commands.len() == 1 {
1892 let command = &pipeline.commands[0];
1893
1894 let name = command
1895 .command_parts()
1896 .first()
1897 .map(|s| working_set.get_span_contents(*s))
1898 .unwrap_or(b"");
1899
1900 match name {
1901 b"def" => {
1903 block.pipelines.push(
1904 parse_def(
1905 working_set,
1906 command,
1907 None, )
1909 .0,
1910 )
1911 }
1912 b"extern" => block
1913 .pipelines
1914 .push(parse_extern(working_set, command, None)),
1915 b"export" => {
1917 let (pipe, exportables) =
1918 parse_export_in_module(working_set, command, module_name, &mut module);
1919
1920 for exportable in exportables {
1921 match exportable {
1922 Exportable::Decl { name, id } => {
1923 if &name == b"main" {
1924 if module.main.is_some() {
1925 let err_span = if !pipe.elements.is_empty() {
1926 if let Expr::Call(call) = &pipe.elements[0].expr.expr {
1927 call.head
1928 } else {
1929 pipe.elements[0].expr.span
1930 }
1931 } else {
1932 span
1933 };
1934 working_set.error(ParseError::ModuleDoubleMain(
1935 String::from_utf8_lossy(module_name).to_string(),
1936 err_span,
1937 ));
1938 } else {
1939 module.main = Some(id);
1940 }
1941 } else {
1942 module.add_decl(name, id);
1943 }
1944 }
1945 Exportable::Module { name, id } => {
1946 if &name == b"mod" {
1947 let (submodule_main, submodule_decls, submodule_submodules) = {
1948 let submodule = working_set.get_module(id);
1949 (submodule.main, submodule.decls(), submodule.submodules())
1950 };
1951
1952 for (decl_name, decl_id) in submodule_decls {
1954 module.add_decl(decl_name, decl_id);
1955 }
1956
1957 if let Some(main_decl_id) = submodule_main {
1959 if module.main.is_some() {
1960 let err_span = if !pipe.elements.is_empty() {
1961 if let Expr::Call(call) =
1962 &pipe.elements[0].expr.expr
1963 {
1964 call.head
1965 } else {
1966 pipe.elements[0].expr.span
1967 }
1968 } else {
1969 span
1970 };
1971 working_set.error(ParseError::ModuleDoubleMain(
1972 String::from_utf8_lossy(module_name).to_string(),
1973 err_span,
1974 ));
1975 } else {
1976 module.main = Some(main_decl_id);
1977 }
1978 }
1979
1980 for (submodule_name, submodule_id) in submodule_submodules {
1982 module.add_submodule(submodule_name, submodule_id);
1983 }
1984 } else {
1985 module.add_submodule(name, id);
1986 }
1987 }
1988 Exportable::VarDecl { name, id } => {
1989 module.add_variable(name, id);
1990 }
1991 }
1992 }
1993
1994 block.pipelines.push(pipe)
1995 }
1996 _ if command.has_attributes() => block
1998 .pipelines
1999 .push(parse_attribute_block(working_set, command)),
2000 b"const" => block
2001 .pipelines
2002 .push(parse_const(working_set, &command.parts).0),
2003 b"alias" => {
2004 block.pipelines.push(parse_alias(
2005 working_set,
2006 command,
2007 None, ))
2009 }
2010 b"use" => {
2011 let (pipeline, _) = parse_use(working_set, command, Some(&mut module));
2012
2013 block.pipelines.push(pipeline)
2014 }
2015 b"module" => {
2016 let (pipeline, _) = parse_module(
2017 working_set,
2018 command,
2019 None, );
2021
2022 block.pipelines.push(pipeline)
2023 }
2024 b"export-env" => {
2025 let (pipe, maybe_env_block) = parse_export_env(working_set, &command.parts);
2026
2027 if let Some(block_id) = maybe_env_block {
2028 module.add_env_block(block_id);
2029 }
2030
2031 block.pipelines.push(pipe)
2032 }
2033 _ => {
2034 working_set.error(ParseError::ExpectedKeyword(
2035 "def, const, extern, alias, use, module, export or export-env keyword"
2036 .into(),
2037 command.parts[0],
2038 ));
2039
2040 block
2041 .pipelines
2042 .push(garbage_pipeline(working_set, &command.parts))
2043 }
2044 }
2045 } else {
2046 working_set.error(ParseError::Expected("not a pipeline", span));
2047 block.pipelines.push(garbage_pipeline(working_set, &[span]))
2048 }
2049 }
2050
2051 working_set.exit_scope();
2052
2053 (block, module, module_comments)
2054}
2055
2056fn module_needs_reloading(working_set: &StateWorkingSet, module_id: ModuleId) -> bool {
2057 let module = working_set.get_module(module_id);
2058
2059 fn submodule_need_reloading(working_set: &StateWorkingSet, submodule_id: ModuleId) -> bool {
2060 let submodule = working_set.get_module(submodule_id);
2061 let submodule_changed = if let Some((file_path, file_id)) = &submodule.file {
2062 let existing_contents = working_set.get_contents_of_file(*file_id);
2063 let file_contents = file_path.read(working_set);
2064
2065 if let (Some(existing), Some(new)) = (existing_contents, file_contents) {
2066 existing != new
2067 } else {
2068 false
2069 }
2070 } else {
2071 false
2072 };
2073
2074 if submodule_changed {
2075 true
2076 } else {
2077 module_needs_reloading(working_set, submodule_id)
2078 }
2079 }
2080
2081 let export_submodule_changed = module
2082 .submodules
2083 .iter()
2084 .any(|(_, submodule_id)| submodule_need_reloading(working_set, *submodule_id));
2085
2086 if export_submodule_changed {
2087 return true;
2088 }
2089
2090 module
2091 .imported_modules
2092 .iter()
2093 .any(|submodule_id| submodule_need_reloading(working_set, *submodule_id))
2094}
2095
2096fn parse_module_file(
2100 working_set: &mut StateWorkingSet,
2101 path: ParserPath,
2102 path_span: Span,
2103 name_override: Option<String>,
2104) -> Option<ModuleId> {
2105 let module_name = if let Some(name) = name_override {
2107 name
2108 } else if let Some(stem) = path.file_stem() {
2109 stem.to_string_lossy().to_string()
2110 } else {
2111 working_set.error(ParseError::ModuleNotFound(
2112 path_span,
2113 path.path().to_string_lossy().to_string(),
2114 ));
2115 return None;
2116 };
2117
2118 let contents = if let Some(contents) = path.read(working_set) {
2120 contents
2121 } else {
2122 working_set.error(ParseError::ModuleNotFound(
2123 path_span,
2124 path.path().to_string_lossy().to_string(),
2125 ));
2126 return None;
2127 };
2128
2129 let file_id = working_set.add_file(path.path().to_string_lossy().to_string(), &contents);
2130 let new_span = working_set.get_span_for_file(file_id);
2131
2132 if let Some(module_id) = working_set.find_module_by_span(new_span)
2134 && !module_needs_reloading(working_set, module_id)
2135 {
2136 return Some(module_id);
2137 }
2138
2139 if let Err(e) = working_set.files.push(path.clone().path_buf(), path_span) {
2141 working_set.error(e);
2142 return None;
2143 }
2144
2145 let (block, mut module, module_comments) =
2147 parse_module_block(working_set, new_span, module_name.as_bytes());
2148
2149 working_set.files.pop();
2151
2152 let _ = working_set.add_block(Arc::new(block));
2153 module.file = Some((path, file_id));
2154 let module_id = working_set.add_module(&module_name, module, module_comments);
2155
2156 Some(module_id)
2157}
2158
2159pub fn parse_module_file_or_dir(
2160 working_set: &mut StateWorkingSet,
2161 path: &[u8],
2162 path_span: Span,
2163 name_override: Option<String>,
2164) -> Option<ModuleId> {
2165 let (module_path_str, err) = unescape_unquote_string(path, path_span);
2166 if let Some(err) = err {
2167 working_set.error(err);
2168 return None;
2169 }
2170
2171 #[allow(deprecated)]
2172 let cwd = working_set.get_cwd();
2173
2174 let module_path =
2175 if let Some(path) = find_in_dirs(&module_path_str, working_set, &cwd, Some(LIB_DIRS_VAR)) {
2176 path
2177 } else {
2178 working_set.error(ParseError::ModuleNotFound(path_span, module_path_str));
2179 return None;
2180 };
2181
2182 if module_path.is_dir() {
2183 if module_path.read_dir().is_none() {
2184 working_set.error(ParseError::ModuleNotFound(
2185 path_span,
2186 module_path.path().to_string_lossy().to_string(),
2187 ));
2188 return None;
2189 };
2190
2191 let module_name = if let Some(stem) = module_path.file_stem() {
2192 stem.to_string_lossy().to_string()
2193 } else {
2194 working_set.error(ParseError::ModuleNotFound(
2195 path_span,
2196 module_path.path().to_string_lossy().to_string(),
2197 ));
2198 return None;
2199 };
2200
2201 let mod_nu_path = module_path.clone().join("mod.nu");
2202
2203 if !(mod_nu_path.exists() && mod_nu_path.is_file()) {
2204 working_set.error(ParseError::ModuleMissingModNuFile(
2205 module_path.path().to_string_lossy().to_string(),
2206 path_span,
2207 ));
2208 return None;
2209 }
2210
2211 if let Some(module_id) = parse_module_file(
2212 working_set,
2213 mod_nu_path,
2214 path_span,
2215 name_override.or(Some(module_name)),
2216 ) {
2217 let module = working_set.get_module(module_id).clone();
2218
2219 let module_name = String::from_utf8_lossy(&module.name).to_string();
2220
2221 let module_comments = if let Some(comments) = working_set.get_module_comments(module_id)
2222 {
2223 comments.to_vec()
2224 } else {
2225 vec![]
2226 };
2227
2228 let new_module_id = working_set.add_module(&module_name, module, module_comments);
2229
2230 Some(new_module_id)
2231 } else {
2232 None
2233 }
2234 } else if module_path.is_file() {
2235 parse_module_file(working_set, module_path, path_span, name_override)
2236 } else {
2237 working_set.error(ParseError::ModuleNotFound(
2238 path_span,
2239 module_path.path().to_string_lossy().to_string(),
2240 ));
2241 None
2242 }
2243}
2244
2245pub fn parse_module(
2246 working_set: &mut StateWorkingSet,
2247 lite_command: &LiteCommand,
2248 module_name: Option<&[u8]>,
2249) -> (Pipeline, Option<ModuleId>) {
2250 let spans = &lite_command.parts;
2254
2255 if let Some(redirection) = lite_command.redirection.as_ref() {
2256 working_set.error(redirecting_builtin_error("module", redirection));
2257 return (garbage_pipeline(working_set, spans), None);
2258 }
2259
2260 let mut module_comments = lite_command.comments.clone();
2261
2262 let split_id = if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
2263 2
2264 } else {
2265 1
2266 };
2267
2268 let (mut call, call_span) = match working_set.find_decl(b"module") {
2269 Some(decl_id) => {
2270 let (command_spans, rest_spans) = spans.split_at(split_id);
2271
2272 let ParsedInternalCall {
2273 call,
2274 output,
2275 call_kind,
2276 } = parse_internal_call(
2277 working_set,
2278 Span::concat(command_spans),
2279 rest_spans,
2280 decl_id,
2281 ArgumentParsingLevel::FirstK { k: 1 },
2282 );
2283
2284 let call_span = Span::concat(spans);
2285 if call_kind != CallKind::Valid {
2286 return (
2287 Pipeline::from_vec(vec![Expression::new(
2288 working_set,
2289 Expr::Call(call),
2290 call_span,
2291 output,
2292 )]),
2293 None,
2294 );
2295 }
2296
2297 (call, call_span)
2298 }
2299 None => {
2300 working_set.error(ParseError::UnknownState(
2301 "internal error: 'module' or 'export module' declaration not found".into(),
2302 Span::concat(spans),
2303 ));
2304 return (garbage_pipeline(working_set, spans), None);
2305 }
2306 };
2307
2308 let (module_name_or_path, module_name_or_path_span) = if let Some(name) = call.positional_nth(0)
2309 {
2310 if let Some(s) = name.as_string() {
2311 if let Some(mod_name) = module_name
2312 && s.as_bytes() == mod_name
2313 {
2314 working_set.error(ParseError::NamedAsModule(
2315 "module".to_string(),
2316 s,
2317 "mod".to_string(),
2318 name.span,
2319 ));
2320 return (
2321 Pipeline::from_vec(vec![Expression::new(
2322 working_set,
2323 Expr::Call(call),
2324 call_span,
2325 Type::Any,
2326 )]),
2327 None,
2328 );
2329 }
2330 (s, name.span)
2331 } else {
2332 working_set.error(ParseError::UnknownState(
2333 "internal error: name not a string".into(),
2334 Span::concat(spans),
2335 ));
2336 return (garbage_pipeline(working_set, spans), None);
2337 }
2338 } else {
2339 working_set.error(ParseError::UnknownState(
2340 "internal error: missing positional".into(),
2341 Span::concat(spans),
2342 ));
2343 return (garbage_pipeline(working_set, spans), None);
2344 };
2345
2346 if spans.len() == split_id + 1 {
2347 let pipeline = Pipeline::from_vec(vec![Expression::new(
2348 working_set,
2349 Expr::Call(call),
2350 call_span,
2351 Type::Any,
2352 )]);
2353
2354 if let Some(module_id) = parse_module_file_or_dir(
2355 working_set,
2356 module_name_or_path.as_bytes(),
2357 module_name_or_path_span,
2358 None,
2359 ) {
2360 return (pipeline, Some(module_id));
2361 } else {
2362 working_set.error(ParseError::ModuleNotFound(
2363 module_name_or_path_span,
2364 module_name_or_path,
2365 ));
2366 return (pipeline, None);
2367 }
2368 }
2369
2370 if spans.len() < split_id + 2 {
2371 working_set.error(ParseError::UnknownState(
2372 "Expected structure: module <name> or module <name> <block>".into(),
2373 Span::concat(spans),
2374 ));
2375
2376 return (garbage_pipeline(working_set, spans), None);
2377 }
2378
2379 let module_name = module_name_or_path;
2380
2381 let block_expr_span = spans[split_id + 1];
2382 let block_bytes = working_set.get_span_contents(block_expr_span);
2383 let mut start = block_expr_span.start;
2384 let mut end = block_expr_span.end;
2385
2386 if block_bytes.starts_with(b"{") {
2387 start += 1;
2388 } else {
2389 working_set.error(ParseError::Expected("block", block_expr_span));
2390 return (garbage_pipeline(working_set, spans), None);
2391 }
2392
2393 if block_bytes.ends_with(b"}") {
2394 end -= 1;
2395 } else {
2396 working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
2397 }
2398
2399 let block_content_span = Span::new(start, end);
2400
2401 let (block, module, inner_comments) =
2402 parse_module_block(working_set, block_content_span, module_name.as_bytes());
2403
2404 let block_id = working_set.add_block(Arc::new(block));
2405
2406 module_comments.extend(inner_comments);
2407 let module_id = working_set.add_module(&module_name, module, module_comments);
2408
2409 let block_expr = Expression::new(
2410 working_set,
2411 Expr::Block(block_id),
2412 block_expr_span,
2413 Type::Block,
2414 );
2415
2416 if !call.set_kth_argument(1, Argument::Positional(block_expr)) {
2419 working_set.error(ParseError::InternalError(
2420 "Failed to set the block argument".into(),
2421 block_expr_span,
2422 ));
2423 }
2424
2425 (
2426 Pipeline::from_vec(vec![Expression::new(
2427 working_set,
2428 Expr::Call(call),
2429 Span::concat(spans),
2430 Type::Any,
2431 )]),
2432 Some(module_id),
2433 )
2434}
2435
2436pub fn parse_use(
2437 working_set: &mut StateWorkingSet,
2438 lite_command: &LiteCommand,
2439 parent_module: Option<&mut Module>,
2440) -> (Pipeline, Vec<Exportable>) {
2441 let spans = &lite_command.parts;
2442
2443 let (name_span, split_id) =
2444 if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
2445 (spans[1], 2)
2446 } else {
2447 (spans[0], 1)
2448 };
2449
2450 let use_call = working_set.get_span_contents(name_span).to_vec();
2451 if use_call != b"use" {
2452 working_set.error(ParseError::UnknownState(
2453 "internal error: Wrong call name for 'use' command".into(),
2454 Span::concat(spans),
2455 ));
2456 return (garbage_pipeline(working_set, spans), vec![]);
2457 }
2458
2459 if working_set.get_span_contents(name_span) != b"use" {
2460 working_set.error(ParseError::UnknownState(
2461 "internal error: Wrong call name for 'use' command".into(),
2462 Span::concat(spans),
2463 ));
2464 return (garbage_pipeline(working_set, spans), vec![]);
2465 }
2466
2467 if let Some(redirection) = lite_command.redirection.as_ref() {
2468 working_set.error(redirecting_builtin_error("use", redirection));
2469 return (garbage_pipeline(working_set, spans), vec![]);
2470 }
2471
2472 let (call, call_span, args_spans) = match working_set.find_decl(b"use") {
2473 Some(decl_id) => {
2474 let (command_spans, rest_spans) = spans.split_at(split_id);
2475
2476 let ParsedInternalCall {
2477 call,
2478 output,
2479 call_kind,
2480 } = parse_internal_call(
2481 working_set,
2482 Span::concat(command_spans),
2483 rest_spans,
2484 decl_id,
2485 ArgumentParsingLevel::Full,
2486 );
2487
2488 let call_span = Span::concat(spans);
2489 if call_kind != CallKind::Valid {
2490 return (
2491 Pipeline::from_vec(vec![Expression::new(
2492 working_set,
2493 Expr::Call(call),
2494 call_span,
2495 output,
2496 )]),
2497 vec![],
2498 );
2499 }
2500
2501 (call, call_span, rest_spans)
2502 }
2503 None => {
2504 working_set.error(ParseError::UnknownState(
2505 "internal error: 'use' declaration not found".into(),
2506 Span::concat(spans),
2507 ));
2508 return (garbage_pipeline(working_set, spans), vec![]);
2509 }
2510 };
2511
2512 let import_pattern_expr = parse_import_pattern(working_set, call.positional_iter(), args_spans);
2513
2514 let import_pattern = match &import_pattern_expr {
2515 Expression {
2516 expr: Expr::Nothing,
2517 ..
2518 } => {
2519 let mut call = call;
2520 call.set_parser_info(
2521 "noop".to_string(),
2522 Expression::new_unknown(Expr::Nothing, Span::unknown(), Type::Nothing),
2523 );
2524 return (
2525 Pipeline::from_vec(vec![Expression::new(
2526 working_set,
2527 Expr::Call(call),
2528 Span::concat(spans),
2529 Type::Any,
2530 )]),
2531 vec![],
2532 );
2533 }
2534 Expression {
2535 expr: Expr::ImportPattern(import_pattern),
2536 ..
2537 } => import_pattern.clone(),
2538 _ => {
2539 working_set.error(ParseError::UnknownState(
2540 "internal error: Import pattern positional is not import pattern".into(),
2541 import_pattern_expr.span,
2542 ));
2543 return (garbage_pipeline(working_set, spans), vec![]);
2544 }
2545 };
2546
2547 let (mut import_pattern, module, module_id) = if let Some(module_id) = import_pattern.head.id {
2548 let module = working_set.get_module(module_id).clone();
2549 (
2550 ImportPattern {
2551 head: ImportPatternHead {
2552 name: module.name.clone(),
2553 id: Some(module_id),
2554 span: import_pattern.head.span,
2555 },
2556 members: import_pattern.members,
2557 hidden: HashSet::new(),
2558 constants: vec![],
2559 },
2560 module,
2561 module_id,
2562 )
2563 } else if let Some(module_id) = parse_module_file_or_dir(
2564 working_set,
2565 &import_pattern.head.name,
2566 import_pattern.head.span,
2567 None,
2568 ) {
2569 let module = working_set.get_module(module_id).clone();
2570 (
2571 ImportPattern {
2572 head: ImportPatternHead {
2573 name: module.name.clone(),
2574 id: Some(module_id),
2575 span: import_pattern.head.span,
2576 },
2577 members: import_pattern.members,
2578 hidden: HashSet::new(),
2579 constants: vec![],
2580 },
2581 module,
2582 module_id,
2583 )
2584 } else {
2585 working_set.error(ParseError::ModuleNotFound(
2586 import_pattern.head.span,
2587 String::from_utf8_lossy(&import_pattern.head.name).to_string(),
2588 ));
2589 return (
2590 Pipeline::from_vec(vec![Expression::new(
2591 working_set,
2592 Expr::Call(call),
2593 call_span,
2594 Type::Any,
2595 )]),
2596 vec![],
2597 );
2598 };
2599
2600 let mut imported_modules = vec![];
2601 let (definitions, errors) = module.resolve_import_pattern(
2602 working_set,
2603 module_id,
2604 &import_pattern.members,
2605 None,
2606 name_span,
2607 &mut imported_modules,
2608 );
2609
2610 working_set.parse_errors.extend(errors);
2611
2612 let mut constants = vec![];
2613
2614 for (name, const_vid) in definitions.constants {
2615 constants.push((name, const_vid));
2616 }
2617
2618 for (name, const_val) in definitions.constant_values {
2619 let const_var_id =
2620 working_set.add_variable(name.clone(), name_span, const_val.get_type(), false);
2621 working_set.set_variable_const_val(const_var_id, const_val);
2622 constants.push((name, const_var_id));
2623 }
2624
2625 let exportables = definitions
2626 .decls
2627 .iter()
2628 .map(|(name, decl_id)| Exportable::Decl {
2629 name: name.clone(),
2630 id: *decl_id,
2631 })
2632 .chain(
2633 definitions
2634 .modules
2635 .iter()
2636 .map(|(name, module_id)| Exportable::Module {
2637 name: name.clone(),
2638 id: *module_id,
2639 }),
2640 )
2641 .chain(
2642 constants
2643 .iter()
2644 .map(|(name, variable_id)| Exportable::VarDecl {
2645 name: name.clone(),
2646 id: *variable_id,
2647 }),
2648 )
2649 .collect();
2650
2651 import_pattern.constants = constants.iter().map(|(_, id)| *id).collect();
2652
2653 if let Some(m) = parent_module {
2654 m.track_imported_modules(&imported_modules)
2655 }
2656 working_set.use_decls(definitions.decls);
2658 working_set.use_modules(definitions.modules);
2659 working_set.use_variables(constants);
2660
2661 let import_pattern_expr = Expression::new(
2663 working_set,
2664 Expr::ImportPattern(Box::new(import_pattern)),
2665 Span::concat(args_spans),
2666 Type::Any,
2667 );
2668
2669 let mut call = call;
2670 call.set_parser_info("import_pattern".to_string(), import_pattern_expr);
2671
2672 (
2673 Pipeline::from_vec(vec![Expression::new(
2674 working_set,
2675 Expr::Call(call),
2676 Span::concat(spans),
2677 Type::Any,
2678 )]),
2679 exportables,
2680 )
2681}
2682
2683pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline {
2684 let spans = &lite_command.parts;
2685
2686 if working_set.get_span_contents(spans[0]) != b"hide" {
2687 working_set.error(ParseError::UnknownState(
2688 "internal error: Wrong call name for 'hide' command".into(),
2689 Span::concat(spans),
2690 ));
2691 return garbage_pipeline(working_set, spans);
2692 }
2693 if let Some(redirection) = lite_command.redirection.as_ref() {
2694 working_set.error(redirecting_builtin_error("hide", redirection));
2695 return garbage_pipeline(working_set, spans);
2696 }
2697
2698 let (call, args_spans) = match working_set.find_decl(b"hide") {
2699 Some(decl_id) => {
2700 let ParsedInternalCall {
2701 call,
2702 output,
2703 call_kind,
2704 } = parse_internal_call(
2705 working_set,
2706 spans[0],
2707 &spans[1..],
2708 decl_id,
2709 ArgumentParsingLevel::Full,
2710 );
2711
2712 if call_kind != CallKind::Valid {
2713 return Pipeline::from_vec(vec![Expression::new(
2714 working_set,
2715 Expr::Call(call),
2716 Span::concat(spans),
2717 output,
2718 )]);
2719 }
2720
2721 (call, &spans[1..])
2722 }
2723 None => {
2724 working_set.error(ParseError::UnknownState(
2725 "internal error: 'hide' declaration not found".into(),
2726 Span::concat(spans),
2727 ));
2728 return garbage_pipeline(working_set, spans);
2729 }
2730 };
2731
2732 let import_pattern_expr = parse_import_pattern(working_set, call.positional_iter(), args_spans);
2733
2734 let import_pattern = if let Expression {
2735 expr: Expr::ImportPattern(import_pattern),
2736 ..
2737 } = &import_pattern_expr
2738 {
2739 import_pattern.clone()
2740 } else {
2741 working_set.error(ParseError::UnknownState(
2742 "internal error: Import pattern positional is not import pattern".into(),
2743 import_pattern_expr.span,
2744 ));
2745 return garbage_pipeline(working_set, spans);
2746 };
2747
2748 let bytes = working_set.get_span_contents(spans[0]);
2749
2750 if bytes == b"hide" && spans.len() >= 2 {
2751 for span in spans[1..].iter() {
2752 parse_string(working_set, *span);
2753 }
2754
2755 let (is_module, module) =
2757 if let Some(module_id) = working_set.find_module(&import_pattern.head.name) {
2758 (true, working_set.get_module(module_id).clone())
2759 } else if import_pattern.members.is_empty() {
2760 if let Some(id) = working_set.find_decl(&import_pattern.head.name) {
2762 let mut module = Module::new(b"tmp".to_vec());
2764 module.add_decl(import_pattern.head.name.clone(), id);
2765
2766 (false, module)
2767 } else {
2768 (false, Module::new(b"tmp".to_vec()))
2770 }
2771 } else {
2772 working_set.error(ParseError::ModuleNotFound(
2773 spans[1],
2774 String::from_utf8_lossy(&import_pattern.head.name).to_string(),
2775 ));
2776 return garbage_pipeline(working_set, spans);
2777 };
2778
2779 let decls_to_hide = if import_pattern.members.is_empty() {
2781 if is_module {
2782 module.decl_names_with_head(&import_pattern.head.name)
2783 } else {
2784 module.decl_names()
2785 }
2786 } else {
2787 match &import_pattern.members[0] {
2788 ImportPatternMember::Glob { .. } => module.decl_names(),
2789 ImportPatternMember::Name { name, span } => {
2790 let mut decls = vec![];
2791
2792 if name == b"main" {
2793 if module.main.is_some() {
2794 decls.push(import_pattern.head.name.clone());
2795 } else {
2796 working_set.error(ParseError::ExportNotFound(*span));
2797 }
2798 } else if let Some(item) =
2799 module.decl_name_with_head(name, &import_pattern.head.name)
2800 {
2801 decls.push(item);
2802 } else {
2803 working_set.error(ParseError::ExportNotFound(*span));
2804 }
2805
2806 decls
2807 }
2808 ImportPatternMember::List { names } => {
2809 let mut decls = vec![];
2810
2811 for (name, span) in names {
2812 if name == b"main" {
2813 if module.main.is_some() {
2814 decls.push(import_pattern.head.name.clone());
2815 } else {
2816 working_set.error(ParseError::ExportNotFound(*span));
2817 break;
2818 }
2819 } else if let Some(item) =
2820 module.decl_name_with_head(name, &import_pattern.head.name)
2821 {
2822 decls.push(item);
2823 } else {
2824 working_set.error(ParseError::ExportNotFound(*span));
2825 break;
2826 }
2827 }
2828
2829 decls
2830 }
2831 }
2832 };
2833
2834 let import_pattern = {
2835 let decls: HashSet<Vec<u8>> = decls_to_hide.iter().cloned().collect();
2836
2837 import_pattern.with_hidden(decls)
2838 };
2839
2840 working_set.hide_decls(&decls_to_hide);
2843
2844 let import_pattern_expr = Expression::new(
2846 working_set,
2847 Expr::ImportPattern(Box::new(import_pattern)),
2848 Span::concat(args_spans),
2849 Type::Any,
2850 );
2851
2852 let mut call = call;
2853 call.set_parser_info("import_pattern".to_string(), import_pattern_expr);
2854
2855 Pipeline::from_vec(vec![Expression::new(
2856 working_set,
2857 Expr::Call(call),
2858 Span::concat(spans),
2859 Type::Any,
2860 )])
2861 } else {
2862 working_set.error(ParseError::UnknownState(
2863 "Expected structure: hide <name>".into(),
2864 Span::concat(spans),
2865 ));
2866 garbage_pipeline(working_set, spans)
2867 }
2868}
2869
2870pub fn parse_overlay_new(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
2871 let call_span = call.span();
2872
2873 let (overlay_name, _) = if let Some(expr) = call.positional_nth(0) {
2874 match eval_constant(working_set, expr) {
2875 Ok(val) => match val.coerce_into_string() {
2876 Ok(s) => (s, expr.span),
2877 Err(err) => {
2878 working_set.error(err.wrap(working_set, call_span));
2879 return garbage_pipeline(working_set, &[call_span]);
2880 }
2881 },
2882 Err(err) => {
2883 working_set.error(err.wrap(working_set, call_span));
2884 return garbage_pipeline(working_set, &[call_span]);
2885 }
2886 }
2887 } else {
2888 working_set.error(ParseError::UnknownState(
2889 "internal error: Missing required positional after call parsing".into(),
2890 call_span,
2891 ));
2892 return garbage_pipeline(working_set, &[call_span]);
2893 };
2894
2895 let pipeline = Pipeline::from_vec(vec![Expression::new(
2896 working_set,
2897 Expr::Call(call),
2898 call_span,
2899 Type::Any,
2900 )]);
2901
2902 let module_id = working_set.add_module(
2903 &overlay_name,
2904 Module::new(overlay_name.as_bytes().to_vec()),
2905 vec![],
2906 );
2907
2908 working_set.add_overlay(
2909 overlay_name.as_bytes().to_vec(),
2910 module_id,
2911 ResolvedImportPattern::new(vec![], vec![], vec![], vec![]),
2912 false,
2913 );
2914
2915 pipeline
2916}
2917
2918pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
2919 let call_span = call.span();
2920
2921 let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) {
2922 match eval_constant(working_set, expr) {
2923 Ok(Value::Nothing { .. }) => {
2924 let mut call = call;
2925 call.set_parser_info(
2926 "noop".to_string(),
2927 Expression::new_unknown(Expr::Bool(true), Span::unknown(), Type::Bool),
2928 );
2929 return Pipeline::from_vec(vec![Expression::new(
2930 working_set,
2931 Expr::Call(call),
2932 call_span,
2933 Type::Any,
2934 )]);
2935 }
2936 Ok(val) => match val.coerce_into_string() {
2937 Ok(s) => (s, expr.span),
2938 Err(err) => {
2939 working_set.error(err.wrap(working_set, call_span));
2940 return garbage_pipeline(working_set, &[call_span]);
2941 }
2942 },
2943 Err(err) => {
2944 working_set.error(err.wrap(working_set, call_span));
2945 return garbage_pipeline(working_set, &[call_span]);
2946 }
2947 }
2948 } else {
2949 working_set.error(ParseError::UnknownState(
2950 "internal error: Missing required positional after call parsing".into(),
2951 call_span,
2952 ));
2953 return garbage_pipeline(working_set, &[call_span]);
2954 };
2955
2956 let new_name = if let Some(kw_expression) = call.positional_nth(1) {
2957 if let Some(new_name_expression) = kw_expression.as_keyword() {
2958 match eval_constant(working_set, new_name_expression) {
2959 Ok(val) => match val.coerce_into_string() {
2960 Ok(s) => Some(Spanned {
2961 item: s,
2962 span: new_name_expression.span,
2963 }),
2964 Err(err) => {
2965 working_set.error(err.wrap(working_set, call_span));
2966 return garbage_pipeline(working_set, &[call_span]);
2967 }
2968 },
2969 Err(err) => {
2970 working_set.error(err.wrap(working_set, call_span));
2971 return garbage_pipeline(working_set, &[call_span]);
2972 }
2973 }
2974 } else {
2975 working_set.error(ParseError::ExpectedKeyword(
2976 "as keyword".to_string(),
2977 kw_expression.span,
2978 ));
2979 return garbage_pipeline(working_set, &[call_span]);
2980 }
2981 } else {
2982 None
2983 };
2984
2985 let Ok(has_prefix) = has_flag_const(working_set, &call, "prefix") else {
2986 return garbage_pipeline(working_set, &[call_span]);
2987 };
2988 let Ok(do_reload) = has_flag_const(working_set, &call, "reload") else {
2989 return garbage_pipeline(working_set, &[call_span]);
2990 };
2991
2992 let pipeline = Pipeline::from_vec(vec![Expression::new(
2993 working_set,
2994 Expr::Call(call.clone()),
2995 call_span,
2996 Type::Any,
2997 )]);
2998
2999 let (final_overlay_name, origin_module, origin_module_id, is_module_updated) =
3000 if let Some(overlay_frame) = working_set.find_overlay(overlay_name.as_bytes()) {
3001 if has_prefix && !overlay_frame.prefixed {
3005 working_set.error(ParseError::OverlayPrefixMismatch(
3006 overlay_name,
3007 "without".to_string(),
3008 overlay_name_span,
3009 ));
3010 return pipeline;
3011 }
3012
3013 if !has_prefix && overlay_frame.prefixed {
3014 working_set.error(ParseError::OverlayPrefixMismatch(
3015 overlay_name,
3016 "with".to_string(),
3017 overlay_name_span,
3018 ));
3019 return pipeline;
3020 }
3021
3022 if let Some(new_name) = new_name
3023 && new_name.item != overlay_name
3024 {
3025 working_set.error(ParseError::CantAddOverlayHelp(
3026 format!(
3027 "Cannot add overlay as '{}' because it already exists under the name '{}'",
3028 new_name.item, overlay_name
3029 ),
3030 new_name.span,
3031 ));
3032 return pipeline;
3033 }
3034
3035 let module_id = overlay_frame.origin;
3036
3037 if let Some(new_module_id) = working_set.find_module(overlay_name.as_bytes()) {
3038 if !do_reload && (module_id == new_module_id) {
3039 (
3040 overlay_name,
3041 Module::new(working_set.get_module(module_id).name.clone()),
3042 module_id,
3043 false,
3044 )
3045 } else {
3046 (
3048 overlay_name,
3049 working_set.get_module(new_module_id).clone(),
3050 new_module_id,
3051 true,
3052 )
3053 }
3054 } else {
3055 let module_name = overlay_name.as_bytes().to_vec();
3056 (overlay_name, Module::new(module_name), module_id, true)
3057 }
3058 } else {
3059 if let Some(module_id) =
3061 working_set.find_module(overlay_name.as_bytes())
3063 {
3064 (
3065 new_name.map(|spanned| spanned.item).unwrap_or(overlay_name),
3066 working_set.get_module(module_id).clone(),
3067 module_id,
3068 true,
3069 )
3070 } else if let Some(module_id) = parse_module_file_or_dir(
3071 working_set,
3072 overlay_name.as_bytes(),
3073 overlay_name_span,
3074 new_name.as_ref().map(|spanned| spanned.item.clone()),
3075 ) {
3076 let new_module = working_set.get_module(module_id).clone();
3078 (
3079 new_name
3080 .map(|spanned| spanned.item)
3081 .unwrap_or_else(|| String::from_utf8_lossy(&new_module.name).to_string()),
3082 new_module,
3083 module_id,
3084 true,
3085 )
3086 } else {
3087 working_set.error(ParseError::ModuleOrOverlayNotFound(overlay_name_span));
3088 return pipeline;
3089 }
3090 };
3091
3092 let (definitions, errors) = if is_module_updated {
3093 if has_prefix {
3094 origin_module.resolve_import_pattern(
3095 working_set,
3096 origin_module_id,
3097 &[],
3098 Some(final_overlay_name.as_bytes()),
3099 call.head,
3100 &mut vec![],
3101 )
3102 } else {
3103 origin_module.resolve_import_pattern(
3104 working_set,
3105 origin_module_id,
3106 &[ImportPatternMember::Glob {
3107 span: overlay_name_span,
3108 }],
3109 Some(final_overlay_name.as_bytes()),
3110 call.head,
3111 &mut vec![],
3112 )
3113 }
3114 } else {
3115 (
3116 ResolvedImportPattern::new(vec![], vec![], vec![], vec![]),
3117 vec![],
3118 )
3119 };
3120
3121 if errors.is_empty() {
3122 working_set.add_overlay(
3123 final_overlay_name.as_bytes().to_vec(),
3124 origin_module_id,
3125 definitions,
3126 has_prefix,
3127 );
3128 } else {
3129 working_set.parse_errors.extend(errors);
3130 }
3131
3132 let mut call = call;
3134 call.set_parser_info(
3135 "overlay_expr".to_string(),
3136 Expression::new(
3137 working_set,
3138 Expr::Overlay(if is_module_updated {
3139 Some(origin_module_id)
3140 } else {
3141 None
3142 }),
3143 overlay_name_span,
3144 Type::Any,
3145 ),
3146 );
3147
3148 Pipeline::from_vec(vec![Expression::new(
3149 working_set,
3150 Expr::Call(call),
3151 call_span,
3152 Type::Any,
3153 )])
3154}
3155
3156pub fn parse_overlay_hide(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
3157 let call_span = call.span();
3158
3159 let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_nth(0) {
3160 match eval_constant(working_set, expr) {
3161 Ok(val) => match val.coerce_into_string() {
3162 Ok(s) => (s, expr.span),
3163 Err(err) => {
3164 working_set.error(err.wrap(working_set, call_span));
3165 return garbage_pipeline(working_set, &[call_span]);
3166 }
3167 },
3168 Err(err) => {
3169 working_set.error(err.wrap(working_set, call_span));
3170 return garbage_pipeline(working_set, &[call_span]);
3171 }
3172 }
3173 } else {
3174 (
3175 String::from_utf8_lossy(working_set.last_overlay_name()).to_string(),
3176 call_span,
3177 )
3178 };
3179
3180 let Ok(keep_custom) = has_flag_const(working_set, &call, "keep-custom") else {
3181 return garbage_pipeline(working_set, &[call_span]);
3182 };
3183
3184 let pipeline = Pipeline::from_vec(vec![Expression::new(
3185 working_set,
3186 Expr::Call(call),
3187 call_span,
3188 Type::Any,
3189 )]);
3190
3191 if overlay_name == DEFAULT_OVERLAY_NAME {
3192 working_set.error(ParseError::CantHideDefaultOverlay(
3193 overlay_name,
3194 overlay_name_span,
3195 ));
3196
3197 return pipeline;
3198 }
3199
3200 if !working_set
3201 .unique_overlay_names()
3202 .contains(&overlay_name.as_bytes())
3203 {
3204 working_set.error(ParseError::ActiveOverlayNotFound(overlay_name_span));
3205 return pipeline;
3206 }
3207
3208 if working_set.num_overlays() < 2 {
3209 working_set.error(ParseError::CantRemoveLastOverlay(overlay_name_span));
3210 return pipeline;
3211 }
3212
3213 working_set.remove_overlay(overlay_name.as_bytes(), keep_custom);
3214
3215 pipeline
3216}
3217
3218pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline {
3219 trace!("parsing: let");
3220
3221 if let Some(decl_id) = working_set.find_decl(b"let") {
3227 if spans.len() >= 4 {
3228 for span in spans.iter().enumerate() {
3231 let item = working_set.get_span_contents(*span.1);
3232 if item == b"=" && spans.len() > (span.0 + 1) && span.0 > 1 {
3235 let (tokens, parse_error) = lex(
3236 working_set.get_span_contents(Span::concat(&spans[(span.0 + 1)..])),
3237 spans[span.0 + 1].start,
3238 &[],
3239 &[],
3240 false,
3241 );
3242
3243 if let Some(parse_error) = parse_error {
3244 working_set.error(parse_error)
3245 }
3246
3247 let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
3248 let rvalue_block = parse_block(working_set, &tokens, rvalue_span, false, true);
3249
3250 let output_type = rvalue_block.output_type();
3251
3252 let block_id = working_set.add_block(Arc::new(rvalue_block));
3253
3254 let rvalue = Expression::new(
3255 working_set,
3256 Expr::Block(block_id),
3257 rvalue_span,
3258 output_type,
3259 );
3260
3261 let mut idx = 0;
3262 let (lvalue, explicit_type) =
3263 parse_var_with_opt_type(working_set, &spans[1..(span.0)], &mut idx, false);
3264 if idx + 1 < span.0 - 1 {
3266 working_set.error(ParseError::ExtraTokens(spans[idx + 2]));
3267 }
3268
3269 let var_name =
3270 String::from_utf8_lossy(working_set.get_span_contents(lvalue.span))
3271 .trim_start_matches('$')
3272 .to_string();
3273
3274 if RESERVED_VARIABLE_NAMES.contains(&var_name.as_str()) {
3275 working_set.error(ParseError::NameIsBuiltinVar(var_name, lvalue.span))
3276 }
3277
3278 let var_id = lvalue.as_var();
3279 let rhs_type = rvalue.ty.clone();
3280
3281 if let Some(explicit_type) = &explicit_type
3282 && !type_compatible(explicit_type, &rhs_type)
3283 {
3284 working_set.error(ParseError::TypeMismatch(
3285 explicit_type.clone(),
3286 rhs_type.clone(),
3287 Span::concat(&spans[(span.0 + 1)..]),
3288 ));
3289 }
3290
3291 if let Some(var_id) = var_id
3292 && explicit_type.is_none()
3293 {
3294 working_set.set_variable_type(var_id, rhs_type);
3295 }
3296
3297 let call = Box::new(Call {
3298 decl_id,
3299 head: spans[0],
3300 arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
3301 parser_info: HashMap::new(),
3302 });
3303
3304 return Pipeline::from_vec(vec![Expression::new(
3305 working_set,
3306 Expr::Call(call),
3307 Span::concat(spans),
3308 Type::Any,
3309 )]);
3310 }
3311 }
3312 }
3313 let ParsedInternalCall { call, output, .. } = parse_internal_call(
3314 working_set,
3315 spans[0],
3316 &spans[1..],
3317 decl_id,
3318 ArgumentParsingLevel::Full,
3319 );
3320
3321 return Pipeline::from_vec(vec![Expression::new(
3322 working_set,
3323 Expr::Call(call),
3324 Span::concat(spans),
3325 output,
3326 )]);
3327 } else {
3328 working_set.error(ParseError::UnknownState(
3329 "internal error: let or const statements not found in core language".into(),
3330 Span::concat(spans),
3331 ))
3332 }
3333
3334 working_set.error(ParseError::UnknownState(
3335 "internal error: let or const statement unparsable".into(),
3336 Span::concat(spans),
3337 ));
3338
3339 garbage_pipeline(working_set, spans)
3340}
3341
3342pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> (Pipeline, Option<Span>) {
3344 trace!("parsing: const");
3345
3346 if let Some(decl_id) = working_set.find_decl(b"const") {
3352 if spans.len() >= 4 {
3353 for span in spans.iter().enumerate() {
3356 let item = working_set.get_span_contents(*span.1);
3357 if item == b"=" && spans.len() > (span.0 + 1) && span.0 > 1 {
3359 let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
3361
3362 let (rvalue_tokens, rvalue_error) = lex(
3363 working_set.get_span_contents(rvalue_span),
3364 rvalue_span.start,
3365 &[],
3366 &[],
3367 false,
3368 );
3369 working_set.parse_errors.extend(rvalue_error);
3370
3371 trace!("parsing: const right-hand side subexpression");
3372 let rvalue_block =
3373 parse_block(working_set, &rvalue_tokens, rvalue_span, false, true);
3374 let rvalue_ty = rvalue_block.output_type();
3375 let rvalue_block_id = working_set.add_block(Arc::new(rvalue_block));
3376 let rvalue = Expression::new(
3377 working_set,
3378 Expr::Subexpression(rvalue_block_id),
3379 rvalue_span,
3380 rvalue_ty,
3381 );
3382
3383 let mut idx = 0;
3384
3385 let (lvalue, explicit_type) =
3386 parse_var_with_opt_type(working_set, &spans[1..(span.0)], &mut idx, false);
3387 if idx + 1 < span.0 - 1 {
3389 working_set.error(ParseError::ExtraTokens(spans[idx + 2]));
3390 }
3391
3392 let var_name =
3393 String::from_utf8_lossy(working_set.get_span_contents(lvalue.span))
3394 .trim_start_matches('$')
3395 .to_string();
3396
3397 if RESERVED_VARIABLE_NAMES.contains(&var_name.as_str()) {
3398 working_set.error(ParseError::NameIsBuiltinVar(var_name, lvalue.span))
3399 }
3400
3401 let var_id = lvalue.as_var();
3402 let rhs_type = rvalue.ty.clone();
3403
3404 if let Some(explicit_type) = &explicit_type
3405 && !type_compatible(explicit_type, &rhs_type)
3406 {
3407 working_set.error(ParseError::TypeMismatch(
3408 explicit_type.clone(),
3409 rhs_type.clone(),
3410 Span::concat(&spans[(span.0 + 1)..]),
3411 ));
3412 }
3413
3414 if let Some(var_id) = var_id {
3415 if explicit_type.is_none() {
3416 working_set.set_variable_type(var_id, rhs_type);
3417 }
3418
3419 match eval_constant(working_set, &rvalue) {
3420 Ok(mut value) => {
3421 let mut const_type = value.get_type();
3424
3425 if let Some(explicit_type) = &explicit_type {
3426 if !type_compatible(explicit_type, &const_type) {
3427 working_set.error(ParseError::TypeMismatch(
3428 explicit_type.clone(),
3429 const_type.clone(),
3430 Span::concat(&spans[(span.0 + 1)..]),
3431 ));
3432 }
3433 let val_span = value.span();
3434
3435 match value {
3438 Value::String { val, .. }
3439 if explicit_type == &Type::Glob =>
3440 {
3441 value = Value::glob(val, false, val_span);
3442 const_type = value.get_type();
3443 }
3444 _ => {}
3445 }
3446 }
3447
3448 working_set.set_variable_type(var_id, const_type);
3449
3450 working_set.set_variable_const_val(var_id, value);
3452 }
3453 Err(err) => working_set.error(err.wrap(working_set, rvalue.span)),
3454 }
3455 }
3456
3457 let call = Box::new(Call {
3458 decl_id,
3459 head: spans[0],
3460 arguments: vec![
3461 Argument::Positional(lvalue.clone()),
3462 Argument::Positional(rvalue),
3463 ],
3464 parser_info: HashMap::new(),
3465 });
3466
3467 return (
3468 Pipeline::from_vec(vec![Expression::new(
3469 working_set,
3470 Expr::Call(call),
3471 Span::concat(spans),
3472 Type::Any,
3473 )]),
3474 Some(lvalue.span),
3475 );
3476 }
3477 }
3478 }
3479 let ParsedInternalCall { call, output, .. } = parse_internal_call(
3480 working_set,
3481 spans[0],
3482 &spans[1..],
3483 decl_id,
3484 ArgumentParsingLevel::Full,
3485 );
3486
3487 return (
3488 Pipeline::from_vec(vec![Expression::new(
3489 working_set,
3490 Expr::Call(call),
3491 Span::concat(spans),
3492 output,
3493 )]),
3494 None,
3495 );
3496 } else {
3497 working_set.error(ParseError::UnknownState(
3498 "internal error: let or const statements not found in core language".into(),
3499 Span::concat(spans),
3500 ))
3501 }
3502
3503 working_set.error(ParseError::UnknownState(
3504 "internal error: let or const statement unparsable".into(),
3505 Span::concat(spans),
3506 ));
3507
3508 (garbage_pipeline(working_set, spans), None)
3509}
3510
3511pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline {
3512 trace!("parsing: mut");
3513
3514 if let Some(decl_id) = working_set.find_decl(b"mut") {
3520 if spans.len() >= 4 {
3521 for span in spans.iter().enumerate() {
3524 let item = working_set.get_span_contents(*span.1);
3525 if item == b"=" && spans.len() > (span.0 + 1) && span.0 > 1 {
3527 let (tokens, parse_error) = lex(
3528 working_set.get_span_contents(Span::concat(&spans[(span.0 + 1)..])),
3529 spans[span.0 + 1].start,
3530 &[],
3531 &[],
3532 false,
3533 );
3534
3535 if let Some(parse_error) = parse_error {
3536 working_set.error(parse_error);
3537 }
3538
3539 let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
3540 let rvalue_block = parse_block(working_set, &tokens, rvalue_span, false, true);
3541
3542 let output_type = rvalue_block.output_type();
3543
3544 let block_id = working_set.add_block(Arc::new(rvalue_block));
3545
3546 let rvalue = Expression::new(
3547 working_set,
3548 Expr::Block(block_id),
3549 rvalue_span,
3550 output_type,
3551 );
3552
3553 let mut idx = 0;
3554
3555 let (lvalue, explicit_type) =
3556 parse_var_with_opt_type(working_set, &spans[1..(span.0)], &mut idx, true);
3557 if idx + 1 < span.0 - 1 {
3559 working_set.error(ParseError::ExtraTokens(spans[idx + 2]));
3560 }
3561
3562 let var_name =
3563 String::from_utf8_lossy(working_set.get_span_contents(lvalue.span))
3564 .trim_start_matches('$')
3565 .to_string();
3566
3567 if RESERVED_VARIABLE_NAMES.contains(&var_name.as_str()) {
3568 working_set.error(ParseError::NameIsBuiltinVar(var_name, lvalue.span))
3569 }
3570
3571 let var_id = lvalue.as_var();
3572 let rhs_type = rvalue.ty.clone();
3573
3574 if let Some(explicit_type) = &explicit_type
3575 && !type_compatible(explicit_type, &rhs_type)
3576 {
3577 working_set.error(ParseError::TypeMismatch(
3578 explicit_type.clone(),
3579 rhs_type.clone(),
3580 Span::concat(&spans[(span.0 + 1)..]),
3581 ));
3582 }
3583
3584 if let Some(var_id) = var_id
3585 && explicit_type.is_none()
3586 {
3587 working_set.set_variable_type(var_id, rhs_type);
3588 }
3589
3590 let call = Box::new(Call {
3591 decl_id,
3592 head: spans[0],
3593 arguments: vec![Argument::Positional(lvalue), Argument::Positional(rvalue)],
3594 parser_info: HashMap::new(),
3595 });
3596
3597 return Pipeline::from_vec(vec![Expression::new(
3598 working_set,
3599 Expr::Call(call),
3600 Span::concat(spans),
3601 Type::Any,
3602 )]);
3603 }
3604 }
3605 }
3606 let ParsedInternalCall { call, output, .. } = parse_internal_call(
3607 working_set,
3608 spans[0],
3609 &spans[1..],
3610 decl_id,
3611 ArgumentParsingLevel::Full,
3612 );
3613
3614 return Pipeline::from_vec(vec![Expression::new(
3615 working_set,
3616 Expr::Call(call),
3617 Span::concat(spans),
3618 output,
3619 )]);
3620 } else {
3621 working_set.error(ParseError::UnknownState(
3622 "internal error: let or const statements not found in core language".into(),
3623 Span::concat(spans),
3624 ))
3625 }
3626
3627 working_set.error(ParseError::UnknownState(
3628 "internal error: let or const statement unparsable".into(),
3629 Span::concat(spans),
3630 ));
3631
3632 garbage_pipeline(working_set, spans)
3633}
3634
3635pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline {
3636 trace!("parsing source");
3637 let spans = &lite_command.parts;
3638 let name = working_set.get_span_contents(spans[0]);
3639
3640 if name == b"source" || name == b"source-env" {
3641 if let Some(redirection) = lite_command.redirection.as_ref() {
3642 let name = if name == b"source" {
3643 "source"
3644 } else {
3645 "source-env"
3646 };
3647 working_set.error(redirecting_builtin_error(name, redirection));
3648 return garbage_pipeline(working_set, spans);
3649 }
3650
3651 let scoped = name == b"source-env";
3652
3653 if let Some(decl_id) = working_set.find_decl(name) {
3654 #[allow(deprecated)]
3655 let cwd = working_set.get_cwd();
3656
3657 let ParsedInternalCall {
3660 call,
3661 output,
3662 call_kind,
3663 } = parse_internal_call(
3664 working_set,
3665 spans[0],
3666 &spans[1..],
3667 decl_id,
3668 ArgumentParsingLevel::Full,
3669 );
3670
3671 if call_kind == CallKind::Help {
3672 return Pipeline::from_vec(vec![Expression::new(
3673 working_set,
3674 Expr::Call(call),
3675 Span::concat(spans),
3676 output,
3677 )]);
3678 }
3679
3680 if let Some(expr) = call.positional_nth(0) {
3682 let val = match eval_constant(working_set, expr) {
3683 Ok(val) => val,
3684 Err(err) => {
3685 working_set.error(err.wrap(working_set, Span::concat(&spans[1..])));
3686 return Pipeline::from_vec(vec![Expression::new(
3687 working_set,
3688 Expr::Call(call),
3689 Span::concat(&spans[1..]),
3690 Type::Any,
3691 )]);
3692 }
3693 };
3694
3695 if val.is_nothing() {
3696 let mut call = call;
3697 call.set_parser_info(
3698 "noop".to_string(),
3699 Expression::new_unknown(Expr::Nothing, Span::unknown(), Type::Nothing),
3700 );
3701 return Pipeline::from_vec(vec![Expression::new(
3702 working_set,
3703 Expr::Call(call),
3704 Span::concat(spans),
3705 Type::Any,
3706 )]);
3707 }
3708
3709 let filename = match val.coerce_into_string() {
3710 Ok(s) => s,
3711 Err(err) => {
3712 working_set.error(err.wrap(working_set, Span::concat(&spans[1..])));
3713 return Pipeline::from_vec(vec![Expression::new(
3714 working_set,
3715 Expr::Call(call),
3716 Span::concat(&spans[1..]),
3717 Type::Any,
3718 )]);
3719 }
3720 };
3721
3722 if let Some(path) = find_in_dirs(&filename, working_set, &cwd, Some(LIB_DIRS_VAR)) {
3723 if let Some(contents) = path.read(working_set) {
3724 if let Err(e) = working_set.files.push(path.clone().path_buf(), spans[1]) {
3726 working_set.error(e);
3727 return garbage_pipeline(working_set, spans);
3728 }
3729
3730 let mut block = parse(
3733 working_set,
3734 Some(&path.path().to_string_lossy()),
3735 &contents,
3736 scoped,
3737 );
3738 if block.ir_block.is_none() {
3739 let block_mut = Arc::make_mut(&mut block);
3740 compile_block(working_set, block_mut);
3741 }
3742
3743 working_set.files.pop();
3745
3746 let block_id = working_set.add_block(block);
3748
3749 let mut call_with_block = call;
3750
3751 call_with_block.set_parser_info(
3754 "block_id".to_string(),
3755 Expression::new(
3756 working_set,
3757 Expr::Int(block_id.get() as i64),
3758 spans[1],
3759 Type::Any,
3760 ),
3761 );
3762
3763 call_with_block.set_parser_info(
3765 "block_id_name".to_string(),
3766 Expression::new(
3767 working_set,
3768 Expr::Filepath(path.path_buf().display().to_string(), false),
3769 spans[1],
3770 Type::String,
3771 ),
3772 );
3773
3774 return Pipeline::from_vec(vec![Expression::new(
3775 working_set,
3776 Expr::Call(call_with_block),
3777 Span::concat(spans),
3778 Type::Any,
3779 )]);
3780 }
3781 } else {
3782 working_set.error(ParseError::SourcedFileNotFound(filename, spans[1]));
3783 }
3784 }
3785 return Pipeline::from_vec(vec![Expression::new(
3786 working_set,
3787 Expr::Call(call),
3788 Span::concat(spans),
3789 Type::Any,
3790 )]);
3791 }
3792 }
3793 working_set.error(ParseError::UnknownState(
3794 "internal error: source statement unparsable".into(),
3795 Span::concat(spans),
3796 ));
3797 garbage_pipeline(working_set, spans)
3798}
3799
3800pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
3801 trace!("parsing: where");
3802
3803 if !spans.is_empty() && working_set.get_span_contents(spans[0]) != b"where" {
3804 working_set.error(ParseError::UnknownState(
3805 "internal error: Wrong call name for 'where' command".into(),
3806 Span::concat(spans),
3807 ));
3808 return garbage(working_set, Span::concat(spans));
3809 }
3810
3811 if spans.len() < 2 {
3812 working_set.error(ParseError::MissingPositional(
3813 "row condition".into(),
3814 Span::concat(spans),
3815 "where <row_condition>".into(),
3816 ));
3817 return garbage(working_set, Span::concat(spans));
3818 }
3819
3820 let call = match working_set.find_decl(b"where") {
3821 Some(decl_id) => {
3822 let ParsedInternalCall {
3823 call,
3824 output,
3825 call_kind,
3826 } = parse_internal_call(
3827 working_set,
3828 spans[0],
3829 &spans[1..],
3830 decl_id,
3831 ArgumentParsingLevel::Full,
3832 );
3833
3834 if call_kind != CallKind::Valid {
3835 return Expression::new(working_set, Expr::Call(call), Span::concat(spans), output);
3836 }
3837
3838 call
3839 }
3840 None => {
3841 working_set.error(ParseError::UnknownState(
3842 "internal error: 'where' declaration not found".into(),
3843 Span::concat(spans),
3844 ));
3845 return garbage(working_set, Span::concat(spans));
3846 }
3847 };
3848
3849 Expression::new(
3850 working_set,
3851 Expr::Call(call),
3852 Span::concat(spans),
3853 Type::Any,
3854 )
3855}
3856
3857pub fn parse_where(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline {
3858 let expr = parse_where_expr(working_set, &lite_command.parts);
3859 let redirection = lite_command
3860 .redirection
3861 .as_ref()
3862 .map(|r| parse_redirection(working_set, r));
3863
3864 let element = PipelineElement {
3865 pipe: None,
3866 expr,
3867 redirection,
3868 };
3869
3870 Pipeline {
3871 elements: vec![element],
3872 }
3873}
3874
3875#[cfg(feature = "plugin")]
3876pub fn parse_plugin_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
3877 use nu_protocol::{FromValue, PluginRegistryFile};
3878
3879 #[allow(deprecated)]
3880 let cwd = working_set.get_cwd();
3881
3882 if let Err(err) = (|| {
3883 let name = call
3884 .positional_nth(0)
3885 .map(|expr| {
3886 eval_constant(working_set, expr)
3887 .and_then(Spanned::<String>::from_value)
3888 .map_err(|err| err.wrap(working_set, call.head))
3889 })
3890 .expect("required positional should have been checked")?;
3891
3892 let plugin_config = call
3893 .named_iter()
3894 .find(|(arg_name, _, _)| arg_name.item == "plugin-config")
3895 .map(|(_, _, expr)| {
3896 let expr = expr
3897 .as_ref()
3898 .expect("--plugin-config arg should have been checked already");
3899 eval_constant(working_set, expr)
3900 .and_then(Spanned::<String>::from_value)
3901 .map_err(|err| err.wrap(working_set, call.head))
3902 })
3903 .transpose()?;
3904
3905 let filename_query = {
3907 let path = nu_path::expand_path_with(&name.item, &cwd, true);
3908 path.to_str()
3909 .and_then(|path_str| {
3910 find_in_dirs(path_str, working_set, &cwd, Some("NU_PLUGIN_DIRS"))
3911 })
3912 .map(|parser_path| parser_path.path_buf())
3913 .unwrap_or(path)
3914 };
3915
3916 let plugin_config_path = if let Some(custom_path) = &plugin_config {
3919 find_in_dirs(&custom_path.item, working_set, &cwd, None).ok_or_else(|| {
3920 ParseError::FileNotFound(custom_path.item.clone(), custom_path.span)
3921 })?
3922 } else {
3923 ParserPath::RealPath(
3924 working_set
3925 .permanent_state
3926 .plugin_path
3927 .as_ref()
3928 .ok_or_else(|| ParseError::LabeledErrorWithHelp {
3929 error: "Plugin registry file not set".into(),
3930 label: "can't load plugin without registry file".into(),
3931 span: call.head,
3932 help:
3933 "pass --plugin-config to `plugin use` when $nu.plugin-path is not set"
3934 .into(),
3935 })?
3936 .to_owned(),
3937 )
3938 };
3939
3940 let file = plugin_config_path.open(working_set).map_err(|err| {
3941 ParseError::LabeledError(
3942 "Plugin registry file can't be opened".into(),
3943 err.to_string(),
3944 plugin_config.as_ref().map(|p| p.span).unwrap_or(call.head),
3945 )
3946 })?;
3947
3948 let contents = PluginRegistryFile::read_from(file, Some(call.head))
3950 .map_err(|err| err.wrap(working_set, call.head))?;
3951
3952 let plugin_item = contents
3953 .plugins
3954 .iter()
3955 .find(|plugin| plugin.name == name.item || plugin.filename == filename_query)
3956 .ok_or_else(|| ParseError::PluginNotFound {
3957 name: name.item.clone(),
3958 name_span: name.span,
3959 plugin_config_span: plugin_config.as_ref().map(|p| p.span),
3960 })?;
3961
3962 nu_plugin_engine::load_plugin_registry_item(working_set, plugin_item, Some(call.head))
3964 .map_err(|err| err.wrap(working_set, call.head))?;
3965
3966 Ok(())
3967 })() {
3968 working_set.error(err);
3969 }
3970
3971 let call_span = call.span();
3972
3973 Pipeline::from_vec(vec![Expression::new(
3974 working_set,
3975 Expr::Call(call),
3976 call_span,
3977 Type::Nothing,
3978 )])
3979}
3980
3981pub fn find_dirs_var(working_set: &StateWorkingSet, var_name: &str) -> Option<VarId> {
3982 working_set
3983 .find_variable(format!("${var_name}").as_bytes())
3984 .filter(|var_id| working_set.get_variable(*var_id).const_val.is_some())
3985}
3986
3987pub fn find_in_dirs(
4001 filename: &str,
4002 working_set: &StateWorkingSet,
4003 cwd: &str,
4004 dirs_var_name: Option<&str>,
4005) -> Option<ParserPath> {
4006 if is_windows_device_path(Path::new(&filename)) {
4007 return Some(ParserPath::RealPath(filename.into()));
4008 }
4009
4010 pub fn find_in_dirs_with_id(
4011 filename: &str,
4012 working_set: &StateWorkingSet,
4013 cwd: &str,
4014 dirs_var_name: Option<&str>,
4015 ) -> Option<ParserPath> {
4016 let actual_cwd = working_set
4018 .files
4019 .current_working_directory()
4020 .unwrap_or(Path::new(cwd));
4021
4022 if let Some(virtual_path) = working_set.find_virtual_path(filename) {
4024 return Some(ParserPath::from_virtual_path(
4025 working_set,
4026 filename,
4027 virtual_path,
4028 ));
4029 } else {
4030 let abs_virtual_filename = actual_cwd.join(filename);
4031 let abs_virtual_filename = abs_virtual_filename.to_string_lossy();
4032
4033 if let Some(virtual_path) = working_set.find_virtual_path(&abs_virtual_filename) {
4034 return Some(ParserPath::from_virtual_path(
4035 working_set,
4036 &abs_virtual_filename,
4037 virtual_path,
4038 ));
4039 }
4040 }
4041
4042 if let Ok(p) = canonicalize_with(filename, actual_cwd) {
4044 return Some(ParserPath::RealPath(p));
4045 }
4046
4047 let path = Path::new(filename);
4049 if !path.is_relative() {
4050 return None;
4051 }
4052
4053 dirs_var_name
4055 .as_ref()
4056 .and_then(|dirs_var_name| find_dirs_var(working_set, dirs_var_name))
4057 .map(|var_id| working_set.get_variable(var_id))?
4058 .const_val
4059 .as_ref()?
4060 .as_list()
4061 .ok()?
4062 .iter()
4063 .map(|lib_dir| -> Option<PathBuf> {
4064 let dir = lib_dir.to_path().ok()?;
4065 let dir_abs = canonicalize_with(dir, actual_cwd).ok()?;
4066 canonicalize_with(filename, dir_abs).ok()
4067 })
4068 .find(Option::is_some)
4069 .flatten()
4070 .map(ParserPath::RealPath)
4071 }
4072
4073 pub fn find_in_dirs_old(
4076 filename: &str,
4077 working_set: &StateWorkingSet,
4078 cwd: &str,
4079 dirs_env: Option<&str>,
4080 ) -> Option<PathBuf> {
4081 let actual_cwd = working_set
4083 .files
4084 .current_working_directory()
4085 .unwrap_or(Path::new(cwd));
4086
4087 if let Ok(p) = canonicalize_with(filename, actual_cwd) {
4088 Some(p)
4089 } else {
4090 let path = Path::new(filename);
4091
4092 if path.is_relative() {
4093 if let Some(lib_dirs) =
4094 dirs_env.and_then(|dirs_env| working_set.get_env_var(dirs_env))
4095 {
4096 if let Ok(dirs) = lib_dirs.as_list() {
4097 for lib_dir in dirs {
4098 if let Ok(dir) = lib_dir.to_path() {
4099 if let Ok(dir_abs) = canonicalize_with(dir, actual_cwd)
4101 && let Ok(path) = canonicalize_with(filename, dir_abs)
4102 {
4103 return Some(path);
4104 }
4105 }
4106 }
4107
4108 None
4109 } else {
4110 None
4111 }
4112 } else {
4113 None
4114 }
4115 } else {
4116 None
4117 }
4118 }
4119 }
4120
4121 find_in_dirs_with_id(filename, working_set, cwd, dirs_var_name).or_else(|| {
4122 find_in_dirs_old(filename, working_set, cwd, dirs_var_name).map(ParserPath::RealPath)
4123 })
4124}
4125
4126fn detect_params_in_name(
4127 working_set: &StateWorkingSet,
4128 name_span: Span,
4129 decl_id: DeclId,
4130) -> Option<ParseError> {
4131 let name = working_set.get_span_contents(name_span);
4132 for (offset, char) in name.iter().enumerate() {
4133 if *char == b'[' || *char == b'(' {
4134 return Some(ParseError::LabeledErrorWithHelp {
4135 error: "no space between name and parameters".into(),
4136 label: "expected space".into(),
4137 help: format!(
4138 "consider adding a space between the `{}` command's name and its parameters",
4139 working_set.get_decl(decl_id).name()
4140 ),
4141 span: Span::new(offset + name_span.start - 1, offset + name_span.start - 1),
4142 });
4143 }
4144 }
4145
4146 None
4147}
4148
4149fn has_flag_const(working_set: &mut StateWorkingSet, call: &Call, name: &str) -> Result<bool, ()> {
4151 call.has_flag_const(working_set, name).map_err(|err| {
4152 working_set.error(err.wrap(working_set, call.span()));
4153 })
4154}