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