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