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