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