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