1use crate::{
2 Token, TokenContents,
3 exportable::Exportable,
4 lex,
5 lite_parser::{LiteCommand, lite_parse},
6 parse_helpers::{garbage_pipeline, trim_quotes},
7 parse_pipelines::redirecting_builtin_error,
8 parser::{
9 ArgumentParsingLevel, CallKind, ParsedInternalCall, compile_block_with_id,
10 parse_import_pattern, parse_internal_call, parse_string,
11 },
12 unescape_unquote_string,
13};
14
15use crate::parse_alias::parse_alias;
16use crate::parse_bindings::parse_const;
17use crate::parse_def::{
18 has_flag_const, parse_attribute_block, parse_def, parse_def_predecl, parse_extern,
19};
20
21use nu_protocol::{
22 BlockId, Module, ModuleId, ParseError, Span, Type,
23 ast::{
24 Argument, Block, Call, Expr, Expression, ImportPattern, ImportPatternHead,
25 ImportPatternMember, Pipeline,
26 },
27 engine::StateWorkingSet,
28 eval_const::eval_constant,
29};
30use std::{collections::HashSet, sync::Arc};
31
32use nu_protocol::parser_path::ParserPath;
33
34fn warp_export_call(
35 working_set: &mut StateWorkingSet,
36 pipeline: &mut Pipeline,
37 full_name: &str,
38 spans: &[Span],
39) -> bool {
40 let Some(export_decl_id) = working_set.find_decl(full_name.as_bytes()) else {
41 let error_span = spans.first().cloned().unwrap_or(Span::unknown());
42 working_set.error(ParseError::InternalError(
43 format!("missing '{full_name}' command"),
44 error_span,
45 ));
46 return false;
47 };
48 match pipeline.elements.first_mut().map(|e| {
49 e.expr.span = Span::concat(spans);
50 &mut e.expr.expr
51 }) {
52 Some(Expr::Call(def_call)) => {
53 def_call.head = Span::concat(&spans[0..=1]);
54 def_call.decl_id = export_decl_id;
55 return true;
56 }
57 Some(Expr::AttributeBlock(ab)) => {
58 if let Expr::Call(def_call) = &mut ab.item.expr {
59 def_call.decl_id = export_decl_id;
60 return true;
61 }
62 }
63 _ => {}
64 };
65 working_set.error(ParseError::InternalError(
66 "unexpected output from parsing a definition".into(),
67 Span::concat(&spans[1..]),
68 ));
69 true
70}
71
72pub fn parse_export_in_block(
73 working_set: &mut StateWorkingSet,
74 lite_command: &LiteCommand,
75) -> Pipeline {
76 let parts = lite_command.command_parts();
77 let full_name = if parts.len() > 1 {
78 let sub = working_set.get_span_contents(parts[1]);
79 match sub {
80 b"alias" => "export alias",
81 b"def" => "export def",
82 b"extern" => "export extern",
83 b"use" => "export use",
84 b"module" => "export module",
85 b"const" => "export const",
86 _ => "export",
87 }
88 } else {
89 "export"
90 };
91
92 if let Some(redirection) = lite_command.redirection.as_ref() {
93 working_set.error(redirecting_builtin_error(full_name, redirection));
94 return garbage_pipeline(working_set, &lite_command.parts);
95 }
96
97 let mut pipeline = match full_name {
98 "export def" => parse_def(working_set, lite_command, None).0,
99 "export extern" => parse_extern(working_set, lite_command, None),
100 _ if lite_command.has_attributes() => parse_attribute_block(working_set, lite_command),
101 "export alias" => parse_alias(working_set, lite_command, None),
102 "export const" => parse_const(working_set, &lite_command.parts[1..]).0,
103 "export use" => parse_use(working_set, lite_command, None).0,
104 "export module" => parse_module(working_set, lite_command, None).0,
105 _ => {
106 if let Some(decl_id) = working_set.find_decl(full_name.as_bytes()) {
107 let starting_error_count = working_set.parse_errors.len();
108 let ParsedInternalCall {
109 call,
110 output,
111 call_kind,
112 } = parse_internal_call(
113 working_set,
114 parts[0],
115 &parts[1..],
116 decl_id,
117 ArgumentParsingLevel::Full,
118 None,
119 );
120
121 if call_kind != CallKind::Valid {
122 return Pipeline::from_vec(vec![Expression::new(
123 working_set,
124 Expr::Call(call),
125 Span::concat(&lite_command.parts),
126 output,
127 )]);
128 }
129 working_set.parse_errors.truncate(starting_error_count);
130 working_set.error(ParseError::UnexpectedKeyword(
131 full_name.into(),
132 lite_command.parts[0],
133 ));
134 } else {
135 working_set.error(ParseError::UnknownState(
136 format!("internal error: '{full_name}' declaration not found",),
137 Span::concat(&lite_command.parts),
138 ));
139 };
140 garbage_pipeline(working_set, &lite_command.parts)
141 }
142 };
143
144 warp_export_call(working_set, &mut pipeline, full_name, &lite_command.parts);
145 pipeline
146}
147
148pub fn parse_export_in_module(
149 working_set: &mut StateWorkingSet,
150 lite_command: &LiteCommand,
151 module_name: &[u8],
152 parent_module: &mut Module,
153) -> (Pipeline, Vec<Exportable>) {
154 let spans = lite_command.command_parts();
155
156 let export_span = if let Some(sp) = spans.first() {
157 if working_set.get_span_contents(*sp) != b"export" {
158 working_set.error(ParseError::UnknownState(
159 "expected export statement".into(),
160 Span::concat(spans),
161 ));
162 return (garbage_pipeline(working_set, spans), vec![]);
163 }
164
165 *sp
166 } else {
167 working_set.error(ParseError::UnknownState(
168 "got empty input for parsing export statement".into(),
169 Span::concat(spans),
170 ));
171 return (garbage_pipeline(working_set, spans), vec![]);
172 };
173
174 let (pipeline, exportables) = if let Some(kw_span) = spans.get(1) {
175 let kw_name = working_set.get_span_contents(*kw_span);
176 match kw_name {
177 b"def" => {
178 let (mut pipeline, cmd_result) =
179 parse_def(working_set, lite_command, Some(module_name));
180
181 let mut result = vec![];
182
183 if let Some((decl_name, decl_id)) = cmd_result {
184 result.push(Exportable::Decl {
185 name: decl_name.to_vec(),
186 id: decl_id,
187 });
188 }
189
190 if !warp_export_call(working_set, &mut pipeline, "export def", spans) {
191 return (garbage_pipeline(working_set, spans), vec![]);
192 }
193
194 (pipeline, result)
195 }
196 b"extern" => {
197 let mut pipeline = parse_extern(working_set, lite_command, Some(module_name));
198
199 if !warp_export_call(working_set, &mut pipeline, "export extern", spans) {
200 return (garbage_pipeline(working_set, spans), vec![]);
201 }
202
203 let mut result = vec![];
204
205 let decl_name = match spans.get(2) {
206 Some(span) => working_set.get_span_contents(*span),
207 None => &[],
208 };
209 let decl_name = trim_quotes(decl_name);
210
211 if let Some(decl_id) = working_set.find_decl(decl_name) {
212 result.push(Exportable::Decl {
213 name: decl_name.to_vec(),
214 id: decl_id,
215 });
216 } else {
217 working_set.error(ParseError::InternalError(
218 "failed to find added declaration".into(),
219 Span::concat(&spans[1..]),
220 ));
221 }
222
223 (pipeline, result)
224 }
225 _ if lite_command.has_attributes() => {
226 (parse_attribute_block(working_set, lite_command), vec![])
227 }
228 b"alias" => {
229 let lite_command = LiteCommand {
230 comments: lite_command.comments.clone(),
231 parts: spans[1..].to_vec(),
232 pipe: lite_command.pipe,
233 redirection: lite_command.redirection.clone(),
234 attribute_idx: vec![],
235 };
236 let mut pipeline = parse_alias(working_set, &lite_command, Some(module_name));
237
238 if !warp_export_call(working_set, &mut pipeline, "export alias", spans) {
239 return (garbage_pipeline(working_set, spans), vec![]);
240 }
241
242 let mut result = vec![];
243
244 let alias_name = match spans.get(2) {
245 Some(span) => working_set.get_span_contents(*span),
246 None => &[],
247 };
248 let alias_name = trim_quotes(alias_name);
249
250 if let Some(alias_id) = working_set.find_decl(alias_name) {
251 result.push(Exportable::Decl {
252 name: alias_name.to_vec(),
253 id: alias_id,
254 });
255 } else {
256 working_set.error(ParseError::InternalError(
257 "failed to find added alias".into(),
258 Span::concat(&spans[1..]),
259 ));
260 }
261
262 (pipeline, result)
263 }
264 b"use" => {
265 let lite_command = LiteCommand {
266 comments: lite_command.comments.clone(),
267 parts: spans[1..].to_vec(),
268 pipe: lite_command.pipe,
269 redirection: lite_command.redirection.clone(),
270 attribute_idx: vec![],
271 };
272 let (mut pipeline, exportables) =
273 parse_use(working_set, &lite_command, Some(parent_module));
274
275 if !warp_export_call(working_set, &mut pipeline, "export use", spans) {
276 return (garbage_pipeline(working_set, spans), vec![]);
277 }
278
279 (pipeline, exportables)
280 }
281 b"module" => {
282 let (mut pipeline, maybe_module_id) =
283 parse_module(working_set, lite_command, Some(module_name));
284
285 if !warp_export_call(working_set, &mut pipeline, "export module", spans) {
286 return (garbage_pipeline(working_set, spans), vec![]);
287 }
288
289 let mut result = vec![];
290
291 if let Some(module_name_span) = spans.get(2) {
292 let module_name = working_set.get_span_contents(*module_name_span);
293 let module_name = trim_quotes(module_name);
294
295 if let Some(module_id) = maybe_module_id {
296 result.push(Exportable::Module {
297 name: working_set.get_module(module_id).name(),
298 id: module_id,
299 });
300 } else {
301 working_set.error(ParseError::InternalError(
302 format!(
303 "failed to find added module '{}'",
304 String::from_utf8_lossy(module_name)
305 ),
306 Span::concat(&spans[1..]),
307 ));
308 }
309 }
310
311 (pipeline, result)
312 }
313 b"const" => {
314 let (mut pipeline, var_name_span) = parse_const(working_set, &spans[1..]);
315
316 if !warp_export_call(working_set, &mut pipeline, "export const", spans) {
317 return (garbage_pipeline(working_set, spans), vec![]);
318 }
319
320 let mut result = vec![];
321
322 if let Some(var_name_span) = var_name_span {
323 let var_name = working_set.get_span_contents(var_name_span);
324 let var_name = trim_quotes(var_name);
325
326 if let Some(var_id) = working_set.find_variable(var_name) {
327 if let Err(err) = working_set.get_constant(var_id) {
328 working_set.error(err);
329 } else {
330 result.push(Exportable::VarDecl {
331 name: var_name.to_vec(),
332 id: var_id,
333 });
334 }
335 } else {
336 working_set.error(ParseError::InternalError(
337 "failed to find added variable".into(),
338 Span::concat(&spans[1..]),
339 ));
340 }
341 }
342
343 (pipeline, result)
344 }
345 _ => {
346 working_set.error(ParseError::Expected(
347 "def, alias, use, module, const or extern keyword",
348 spans[1],
349 ));
350
351 (garbage_pipeline(working_set, spans), vec![])
352 }
353 }
354 } else {
355 working_set.error(ParseError::MissingPositional(
356 "def, alias, use, module, const or extern keyword".to_string(),
357 Span::new(export_span.end, export_span.end),
358 "def, alias, use, module, const or extern keyword".to_string(),
359 ));
360
361 (garbage_pipeline(working_set, spans), vec![])
362 };
363
364 (pipeline, exportables)
365}
366
367pub fn parse_export_env(
368 working_set: &mut StateWorkingSet,
369 spans: &[Span],
370) -> (Pipeline, Option<BlockId>) {
371 if !spans.is_empty() && working_set.get_span_contents(spans[0]) != b"export-env" {
372 working_set.error(ParseError::UnknownState(
373 "internal error: Wrong call name for 'export-env' command".into(),
374 Span::concat(spans),
375 ));
376 return (garbage_pipeline(working_set, spans), None);
377 }
378
379 if spans.len() < 2 {
380 working_set.error(ParseError::MissingPositional(
381 "block".into(),
382 Span::concat(spans),
383 "export-env <block>".into(),
384 ));
385 return (garbage_pipeline(working_set, spans), None);
386 }
387
388 let call = match working_set.find_decl(b"export-env") {
389 Some(decl_id) => {
390 let ParsedInternalCall {
391 call,
392 output,
393 call_kind,
394 } = parse_internal_call(
395 working_set,
396 spans[0],
397 &[spans[1]],
398 decl_id,
399 ArgumentParsingLevel::Full,
400 None,
401 );
402
403 if call_kind != CallKind::Valid {
404 return (
405 Pipeline::from_vec(vec![Expression::new(
406 working_set,
407 Expr::Call(call),
408 Span::concat(spans),
409 output,
410 )]),
411 None,
412 );
413 }
414
415 call
416 }
417 None => {
418 working_set.error(ParseError::UnknownState(
419 "internal error: 'export-env' declaration not found".into(),
420 Span::concat(spans),
421 ));
422 return (garbage_pipeline(working_set, spans), None);
423 }
424 };
425
426 let block_id = if let Some(block) = call.positional_iter().next() {
427 if let Some(block_id) = block.as_block() {
428 block_id
429 } else {
430 working_set.error(ParseError::UnknownState(
431 "internal error: 'export-env' block is not a block".into(),
432 block.span,
433 ));
434 return (garbage_pipeline(working_set, spans), None);
435 }
436 } else {
437 working_set.error(ParseError::UnknownState(
438 "internal error: 'export-env' block is missing".into(),
439 Span::concat(spans),
440 ));
441 return (garbage_pipeline(working_set, spans), None);
442 };
443
444 let pipeline = Pipeline::from_vec(vec![Expression::new(
445 working_set,
446 Expr::Call(call),
447 Span::concat(spans),
448 Type::Any,
449 )]);
450
451 compile_block_with_id(working_set, block_id);
452
453 (pipeline, Some(block_id))
454}
455
456fn collect_first_comments(working_set: &StateWorkingSet, tokens: &[Token]) -> Vec<Span> {
457 let mut comments = vec![];
458
459 let mut tokens_iter = tokens.iter().peekable();
460 while let Some(token) = tokens_iter.next() {
461 match token.contents {
462 TokenContents::Comment => {
463 let comment = working_set.get_span_contents(token.span);
464
465 if comments.is_empty() && comment.starts_with(b"#!") {
466 continue;
467 }
468
469 comments.push(token.span);
470 }
471 TokenContents::Eol => {
472 if let Some(Token {
473 contents: TokenContents::Eol,
474 ..
475 }) = tokens_iter.peek()
476 && !comments.is_empty()
477 {
478 break;
479 }
480 }
481 _ => {
482 comments.clear();
483 break;
484 }
485 }
486 }
487
488 comments
489}
490
491pub fn parse_module_block(
492 working_set: &mut StateWorkingSet,
493 span: Span,
494 module_name: &[u8],
495) -> (Block, Module, Vec<Span>) {
496 working_set.enter_scope();
497
498 let source = working_set.get_span_contents(span);
499
500 let (output, err) = lex(source, span.start, &[], &[], false);
501 if let Some(err) = err {
502 working_set.error(err)
503 }
504
505 let module_comments = collect_first_comments(working_set, &output);
506
507 let (output, err) = lite_parse(&output, working_set);
508 if let Some(err) = err {
509 working_set.error(err)
510 }
511
512 for pipeline in &output.block {
513 if pipeline.commands.len() == 1 {
514 parse_def_predecl(working_set, pipeline.commands[0].command_parts());
515 }
516 }
517
518 let mut module = Module::from_span(module_name.to_vec(), span);
519
520 let mut block = Block::new_with_capacity(output.block.len());
521 block.span = Some(span);
522
523 for pipeline in output.block.iter() {
524 if pipeline.commands.len() == 1 {
525 let command = &pipeline.commands[0];
526
527 let name = command
528 .command_parts()
529 .first()
530 .map(|s| working_set.get_span_contents(*s))
531 .unwrap_or(b"");
532
533 match name {
534 b"def" => block
535 .pipelines
536 .push(parse_def(working_set, command, None).0),
537 b"extern" => block
538 .pipelines
539 .push(parse_extern(working_set, command, None)),
540 b"export" => {
541 let (pipe, exportables) =
542 parse_export_in_module(working_set, command, module_name, &mut module);
543
544 for exportable in exportables {
545 match exportable {
546 Exportable::Decl { name, id } => {
547 if &name == b"main" {
548 if module.main.is_some() {
549 let err_span = if !pipe.elements.is_empty() {
550 if let Expr::Call(call) = &pipe.elements[0].expr.expr {
551 call.head
552 } else {
553 pipe.elements[0].expr.span
554 }
555 } else {
556 span
557 };
558 working_set.error(ParseError::ModuleDoubleMain(
559 String::from_utf8_lossy(module_name).to_string(),
560 err_span,
561 ));
562 } else {
563 module.main = Some(id);
564 }
565 } else {
566 module.add_decl(name, id);
567 }
568 }
569 Exportable::Module { name, id } => {
570 if &name == b"mod" {
571 let (submodule_main, submodule_decls, submodule_submodules) = {
572 let submodule = working_set.get_module(id);
573 (submodule.main, submodule.decls(), submodule.submodules())
574 };
575
576 for (decl_name, decl_id) in submodule_decls {
577 module.add_decl(decl_name, decl_id);
578 }
579
580 if let Some(main_decl_id) = submodule_main {
581 if module.main.is_some() {
582 let err_span = if !pipe.elements.is_empty() {
583 if let Expr::Call(call) =
584 &pipe.elements[0].expr.expr
585 {
586 call.head
587 } else {
588 pipe.elements[0].expr.span
589 }
590 } else {
591 span
592 };
593 working_set.error(ParseError::ModuleDoubleMain(
594 String::from_utf8_lossy(module_name).to_string(),
595 err_span,
596 ));
597 } else {
598 module.main = Some(main_decl_id);
599 }
600 }
601
602 for (submodule_name, submodule_id) in submodule_submodules {
603 module.add_submodule(submodule_name, submodule_id);
604 }
605 } else {
606 module.add_submodule(name, id);
607 }
608 }
609 Exportable::VarDecl { name, id } => {
610 module.add_variable(name, id);
611 }
612 }
613 }
614
615 block.pipelines.push(pipe)
616 }
617 _ if command.has_attributes() => block
618 .pipelines
619 .push(parse_attribute_block(working_set, command)),
620 b"const" => block
621 .pipelines
622 .push(parse_const(working_set, &command.parts).0),
623 b"alias" => block
624 .pipelines
625 .push(parse_alias(working_set, command, None)),
626 b"use" => {
627 let (pipeline, _) = parse_use(working_set, command, Some(&mut module));
628
629 block.pipelines.push(pipeline)
630 }
631 b"module" => {
632 let (pipeline, _) = parse_module(working_set, command, None);
633
634 block.pipelines.push(pipeline)
635 }
636 b"export-env" => {
637 let (pipe, maybe_env_block) = parse_export_env(working_set, &command.parts);
638
639 if let Some(block_id) = maybe_env_block {
640 module.add_env_block(block_id);
641 }
642
643 block.pipelines.push(pipe)
644 }
645 _ => {
646 working_set.error(ParseError::ExpectedKeyword(
647 "def, const, extern, alias, use, module, export or export-env keyword"
648 .into(),
649 command.parts[0],
650 ));
651
652 block
653 .pipelines
654 .push(garbage_pipeline(working_set, &command.parts))
655 }
656 }
657 } else {
658 working_set.error(ParseError::Expected("not a pipeline", span));
659 block.pipelines.push(garbage_pipeline(working_set, &[span]))
660 }
661 }
662
663 working_set.exit_scope();
664
665 (block, module, module_comments)
666}
667
668fn module_needs_reloading(working_set: &StateWorkingSet, module_id: ModuleId) -> bool {
669 let module = working_set.get_module(module_id);
670
671 fn submodule_need_reloading(working_set: &StateWorkingSet, submodule_id: ModuleId) -> bool {
672 let submodule = working_set.get_module(submodule_id);
673 let submodule_changed = if let Some((file_path, file_id)) = &submodule.file {
674 let existing_contents = working_set.get_contents_of_file(*file_id);
675 let file_contents = file_path.read(working_set);
676
677 if let (Some(existing), Some(new)) = (existing_contents, file_contents) {
678 existing != new
679 } else {
680 false
681 }
682 } else {
683 false
684 };
685
686 if submodule_changed {
687 true
688 } else {
689 module_needs_reloading(working_set, submodule_id)
690 }
691 }
692
693 let export_submodule_changed = module
694 .submodules
695 .iter()
696 .any(|(_, submodule_id)| submodule_need_reloading(working_set, *submodule_id));
697
698 if export_submodule_changed {
699 return true;
700 }
701
702 module
703 .imported_modules
704 .iter()
705 .any(|submodule_id| submodule_need_reloading(working_set, *submodule_id))
706}
707
708fn parse_module_file(
709 working_set: &mut StateWorkingSet,
710 path: ParserPath,
711 path_span: Span,
712 name_override: Option<String>,
713) -> Option<ModuleId> {
714 let module_name = if let Some(name) = name_override {
715 name
716 } else if let Some(stem) = path.file_stem() {
717 stem.to_string_lossy().to_string()
718 } else {
719 working_set.error(ParseError::ModuleNotFound(
720 path_span,
721 path.path().to_string_lossy().to_string(),
722 ));
723 return None;
724 };
725
726 let contents = if let Some(contents) = path.read(working_set) {
727 contents
728 } else {
729 working_set.error(ParseError::ModuleNotFound(
730 path_span,
731 path.path().to_string_lossy().to_string(),
732 ));
733 return None;
734 };
735
736 let file_id = working_set.add_file(&path.path().to_string_lossy(), &contents);
737 let new_span = working_set.get_span_for_file(file_id);
738
739 if let Some(module_id) = working_set.find_module_by_span(new_span)
740 && !module_needs_reloading(working_set, module_id)
741 {
742 return Some(module_id);
743 }
744
745 if let Err(e) = working_set.files.push(path.clone().path_buf(), path_span) {
746 working_set.error(e);
747 return None;
748 }
749
750 let (block, mut module, module_comments) =
751 parse_module_block(working_set, new_span, module_name.as_bytes());
752
753 working_set.files.pop();
754
755 let _ = working_set.add_block(Arc::new(block));
756 module.file = Some((path, file_id));
757 let module_id = working_set.add_module(&module_name, module, module_comments);
758
759 Some(module_id)
760}
761
762fn find_in_dirs(
763 filename: &str,
764 working_set: &StateWorkingSet,
765 cwd: &str,
766 dirs_var_name: Option<&str>,
767) -> Option<ParserPath> {
768 crate::parse_source::find_in_dirs(filename, working_set, cwd, dirs_var_name)
769}
770
771pub fn parse_module_file_or_dir(
772 working_set: &mut StateWorkingSet,
773 path: &[u8],
774 path_span: Span,
775 name_override: Option<String>,
776) -> Option<ModuleId> {
777 let (module_path_str, err) = unescape_unquote_string(path, path_span);
778 if let Some(err) = err {
779 working_set.error(err);
780 return None;
781 }
782
783 #[allow(deprecated)]
784 let cwd = working_set.get_cwd();
785
786 let module_path = if let Some(path) = find_in_dirs(
787 &module_path_str,
788 working_set,
789 &cwd,
790 Some(crate::parse_source::LIB_DIRS_VAR),
791 ) {
792 path
793 } else {
794 working_set.error(ParseError::ModuleNotFound(path_span, module_path_str));
795 return None;
796 };
797
798 if module_path.is_dir() {
799 if module_path.read_dir().is_none() {
800 working_set.error(ParseError::ModuleNotFound(
801 path_span,
802 module_path.path().to_string_lossy().to_string(),
803 ));
804 return None;
805 };
806
807 let module_name = if let Some(stem) = module_path.file_stem() {
808 stem.to_string_lossy().to_string()
809 } else {
810 working_set.error(ParseError::ModuleNotFound(
811 path_span,
812 module_path.path().to_string_lossy().to_string(),
813 ));
814 return None;
815 };
816
817 let mod_nu_path = module_path
818 .clone()
819 .join("mod.nu")
820 .normalize_slashes_forward();
821
822 if !(mod_nu_path.exists() && mod_nu_path.is_file()) {
823 working_set.error(ParseError::ModuleMissingModNuFile(
824 module_path.path().to_string_lossy().to_string(),
825 path_span,
826 ));
827 return None;
828 }
829
830 if let Some(module_id) = parse_module_file(
831 working_set,
832 mod_nu_path,
833 path_span,
834 name_override.or(Some(module_name)),
835 ) {
836 let module = working_set.get_module(module_id).clone();
837
838 let module_name = String::from_utf8_lossy(&module.name).to_string();
839
840 let module_comments = if let Some(comments) = working_set.get_module_comments(module_id)
841 {
842 comments.to_vec()
843 } else {
844 vec![]
845 };
846
847 let new_module_id = working_set.add_module(&module_name, module, module_comments);
848
849 Some(new_module_id)
850 } else {
851 None
852 }
853 } else if module_path.is_file() {
854 parse_module_file(working_set, module_path, path_span, name_override)
855 } else {
856 working_set.error(ParseError::ModuleNotFound(
857 path_span,
858 module_path.path().to_string_lossy().to_string(),
859 ));
860 None
861 }
862}
863
864pub fn parse_module(
865 working_set: &mut StateWorkingSet,
866 lite_command: &LiteCommand,
867 module_name: Option<&[u8]>,
868) -> (Pipeline, Option<ModuleId>) {
869 let spans = &lite_command.parts;
870
871 if let Some(redirection) = lite_command.redirection.as_ref() {
872 working_set.error(redirecting_builtin_error("module", redirection));
873 return (garbage_pipeline(working_set, spans), None);
874 }
875
876 let mut module_comments = lite_command.comments.clone();
877
878 let split_id = if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
879 2
880 } else {
881 1
882 };
883
884 let (mut call, call_span) = match working_set.find_decl(b"module") {
885 Some(decl_id) => {
886 let (command_spans, rest_spans) = spans.split_at(split_id);
887
888 let ParsedInternalCall {
889 call,
890 output,
891 call_kind,
892 } = parse_internal_call(
893 working_set,
894 Span::concat(command_spans),
895 rest_spans,
896 decl_id,
897 ArgumentParsingLevel::FirstK { k: 1 },
898 None,
899 );
900
901 let call_span = Span::concat(spans);
902 if call_kind != CallKind::Valid {
903 return (
904 Pipeline::from_vec(vec![Expression::new(
905 working_set,
906 Expr::Call(call),
907 call_span,
908 output,
909 )]),
910 None,
911 );
912 }
913
914 (call, call_span)
915 }
916 None => {
917 working_set.error(ParseError::UnknownState(
918 "internal error: 'module' or 'export module' declaration not found".into(),
919 Span::concat(spans),
920 ));
921 return (garbage_pipeline(working_set, spans), None);
922 }
923 };
924
925 let Some(name_expr) = call.positional_iter().next() else {
926 working_set.error(ParseError::UnknownState(
927 "internal error: missing positional".into(),
928 Span::concat(spans),
929 ));
930 return (garbage_pipeline(working_set, spans), None);
931 };
932 let Some(name) = name_expr.as_string() else {
933 working_set.error(ParseError::UnknownState(
934 "internal error: name not a string".into(),
935 Span::concat(spans),
936 ));
937 return (garbage_pipeline(working_set, spans), None);
938 };
939
940 if module_name.is_some_and(|mod_name| mod_name == name.as_bytes()) {
941 working_set.error(ParseError::NamedAsModule(
942 "module".to_string(),
943 name,
944 "mod".to_string(),
945 name_expr.span,
946 ));
947 return (
948 Pipeline::from_vec(vec![Expression::new(
949 working_set,
950 Expr::Call(call),
951 call_span,
952 Type::Any,
953 )]),
954 None,
955 );
956 }
957 let (module_name_or_path, module_name_or_path_span) = (name, name_expr.span);
958
959 if spans.len() == split_id + 1 {
960 let pipeline = Pipeline::from_vec(vec![Expression::new(
961 working_set,
962 Expr::Call(call),
963 call_span,
964 Type::Any,
965 )]);
966
967 if let Some(module_id) = parse_module_file_or_dir(
968 working_set,
969 module_name_or_path.as_bytes(),
970 module_name_or_path_span,
971 None,
972 ) {
973 return (pipeline, Some(module_id));
974 } else {
975 working_set.error(ParseError::ModuleNotFound(
976 module_name_or_path_span,
977 module_name_or_path,
978 ));
979 return (pipeline, None);
980 }
981 }
982
983 if spans.len() < split_id + 2 {
984 working_set.error(ParseError::UnknownState(
985 "Expected structure: module <name> or module <name> <block>".into(),
986 Span::concat(spans),
987 ));
988
989 return (garbage_pipeline(working_set, spans), None);
990 }
991
992 let module_name = module_name_or_path;
993
994 let block_expr_span = spans[split_id + 1];
995 let block_bytes = working_set.get_span_contents(block_expr_span);
996 let mut start = block_expr_span.start;
997 let mut end = block_expr_span.end;
998
999 if block_bytes.starts_with(b"{") {
1000 start += 1;
1001 } else {
1002 working_set.error(ParseError::Expected("block", block_expr_span));
1003 return (garbage_pipeline(working_set, spans), None);
1004 }
1005
1006 if block_bytes.ends_with(b"}") {
1007 end -= 1;
1008 } else {
1009 let open = Span::new(
1010 block_expr_span.start,
1011 block_expr_span
1012 .start
1013 .saturating_add(1)
1014 .min(block_expr_span.end),
1015 );
1016 working_set.error(ParseError::unclosed("}", open, Span::new(end, end)));
1017 }
1018
1019 let block_content_span = Span::new(start, end);
1020
1021 let (block, module, inner_comments) =
1022 parse_module_block(working_set, block_content_span, module_name.as_bytes());
1023
1024 let block_id = working_set.add_block(Arc::new(block));
1025
1026 module_comments.extend(inner_comments);
1027 let module_id = working_set.add_module(&module_name, module, module_comments);
1028
1029 let block_expr = Expression::new(
1030 working_set,
1031 Expr::Block(block_id),
1032 block_expr_span,
1033 Type::Block,
1034 );
1035
1036 if !call.set_kth_argument(1, Argument::Positional(block_expr)) {
1037 working_set.error(ParseError::InternalError(
1038 "Failed to set the block argument".into(),
1039 block_expr_span,
1040 ));
1041 }
1042
1043 (
1044 Pipeline::from_vec(vec![Expression::new(
1045 working_set,
1046 Expr::Call(call),
1047 Span::concat(spans),
1048 Type::Any,
1049 )]),
1050 Some(module_id),
1051 )
1052}
1053
1054fn check_main_keyword_shadow(
1060 working_set: &mut StateWorkingSet,
1061 has_main: bool,
1062 name: &[u8],
1063 span: Span,
1064) -> bool {
1065 if has_main && crate::parse_keywords::is_parser_keyword(name) {
1066 working_set.error(ParseError::KeywordShadowModuleMain(
1067 String::from_utf8_lossy(name).to_string(),
1068 span,
1069 ));
1070 true
1071 } else {
1072 false
1073 }
1074}
1075
1076pub fn parse_use(
1077 working_set: &mut StateWorkingSet,
1078 lite_command: &LiteCommand,
1079 parent_module: Option<&mut Module>,
1080) -> (Pipeline, Vec<Exportable>) {
1081 let spans = &lite_command.parts;
1082
1083 let (name_span, split_id) =
1084 if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
1085 (spans[1], 2)
1086 } else {
1087 (spans[0], 1)
1088 };
1089
1090 let use_call = working_set.get_span_contents(name_span).to_vec();
1091 if use_call != b"use" {
1092 working_set.error(ParseError::UnknownState(
1093 "internal error: Wrong call name for 'use' command".into(),
1094 Span::concat(spans),
1095 ));
1096 return (garbage_pipeline(working_set, spans), vec![]);
1097 }
1098
1099 if working_set.get_span_contents(name_span) != b"use" {
1100 working_set.error(ParseError::UnknownState(
1101 "internal error: Wrong call name for 'use' command".into(),
1102 Span::concat(spans),
1103 ));
1104 return (garbage_pipeline(working_set, spans), vec![]);
1105 }
1106
1107 if let Some(redirection) = lite_command.redirection.as_ref() {
1108 working_set.error(redirecting_builtin_error("use", redirection));
1109 return (garbage_pipeline(working_set, spans), vec![]);
1110 }
1111
1112 let (call, call_span, args_spans) = match working_set.find_decl(b"use") {
1113 Some(decl_id) => {
1114 let (command_spans, rest_spans) = spans.split_at(split_id);
1115
1116 let ParsedInternalCall {
1117 call,
1118 output,
1119 call_kind,
1120 } = parse_internal_call(
1121 working_set,
1122 Span::concat(command_spans),
1123 rest_spans,
1124 decl_id,
1125 ArgumentParsingLevel::Full,
1126 None,
1127 );
1128
1129 let call_span = Span::concat(spans);
1130 if call_kind != CallKind::Valid {
1131 return (
1132 Pipeline::from_vec(vec![Expression::new(
1133 working_set,
1134 Expr::Call(call),
1135 call_span,
1136 output,
1137 )]),
1138 vec![],
1139 );
1140 }
1141
1142 (call, call_span, rest_spans)
1143 }
1144 None => {
1145 working_set.error(ParseError::UnknownState(
1146 "internal error: 'use' declaration not found".into(),
1147 Span::concat(spans),
1148 ));
1149 return (garbage_pipeline(working_set, spans), vec![]);
1150 }
1151 };
1152
1153 let import_pattern_expr = parse_import_pattern(working_set, call.positional_iter(), args_spans);
1154
1155 let import_pattern = match &import_pattern_expr {
1156 Expression {
1157 expr: Expr::Nothing,
1158 ..
1159 } => {
1160 let mut call = call;
1161 call.set_parser_info(
1162 "noop".to_string(),
1163 Expression::new_unknown(Expr::Nothing, Span::unknown(), Type::Nothing),
1164 );
1165 return (
1166 Pipeline::from_vec(vec![Expression::new(
1167 working_set,
1168 Expr::Call(call),
1169 Span::concat(spans),
1170 Type::Any,
1171 )]),
1172 vec![],
1173 );
1174 }
1175 Expression {
1176 expr: Expr::ImportPattern(import_pattern),
1177 ..
1178 } => import_pattern.clone(),
1179 _ => {
1180 working_set.error(ParseError::UnknownState(
1181 "internal error: Import pattern positional is not import pattern".into(),
1182 import_pattern_expr.span,
1183 ));
1184 return (garbage_pipeline(working_set, spans), vec![]);
1185 }
1186 };
1187
1188 let (mut import_pattern, module, module_id) = if let Some(module_id) = import_pattern.head.id {
1189 let module = working_set.get_module(module_id).clone();
1190 (
1191 ImportPattern {
1192 head: ImportPatternHead {
1193 name: module.name.clone(),
1194 id: Some(module_id),
1195 span: import_pattern.head.span,
1196 },
1197 members: import_pattern.members,
1198 hidden: HashSet::new(),
1199 constants: vec![],
1200 },
1201 module,
1202 module_id,
1203 )
1204 } else if let Some(module_id) = parse_module_file_or_dir(
1205 working_set,
1206 &import_pattern.head.name,
1207 import_pattern.head.span,
1208 None,
1209 ) {
1210 let module = working_set.get_module(module_id).clone();
1211 (
1212 ImportPattern {
1213 head: ImportPatternHead {
1214 name: module.name.clone(),
1215 id: Some(module_id),
1216 span: import_pattern.head.span,
1217 },
1218 members: import_pattern.members,
1219 hidden: HashSet::new(),
1220 constants: vec![],
1221 },
1222 module,
1223 module_id,
1224 )
1225 } else {
1226 working_set.error(ParseError::ModuleNotFound(
1227 import_pattern.head.span,
1228 String::from_utf8_lossy(&import_pattern.head.name).to_string(),
1229 ));
1230 return (
1231 Pipeline::from_vec(vec![Expression::new(
1232 working_set,
1233 Expr::Call(call),
1234 call_span,
1235 Type::Any,
1236 )]),
1237 vec![],
1238 );
1239 };
1240
1241 if check_main_keyword_shadow(
1242 working_set,
1243 module.main.is_some(),
1244 &module.name,
1245 import_pattern.head.span,
1246 ) {
1247 return (garbage_pipeline(working_set, &[call_span]), vec![]);
1248 }
1249
1250 let mut imported_modules = vec![];
1251 let (definitions, errors) = module.resolve_import_pattern(
1252 working_set,
1253 module_id,
1254 &import_pattern.members,
1255 None,
1256 name_span,
1257 &mut imported_modules,
1258 );
1259
1260 working_set.parse_errors.extend(errors);
1261
1262 let mut constants = vec![];
1263
1264 for (name, const_vid) in definitions.constants {
1265 constants.push((name, const_vid));
1266 }
1267
1268 for (name, const_val) in definitions.constant_values {
1269 let const_var_id =
1270 working_set.add_variable(name.clone(), name_span, const_val.get_type(), false);
1271 working_set.set_variable_const_val(const_var_id, const_val);
1272 constants.push((name, const_var_id));
1273 }
1274
1275 let exportables = definitions
1276 .decls
1277 .iter()
1278 .map(|(name, decl_id)| Exportable::Decl {
1279 name: name.clone(),
1280 id: *decl_id,
1281 })
1282 .chain(
1283 definitions
1284 .modules
1285 .iter()
1286 .map(|(name, module_id)| Exportable::Module {
1287 name: name.clone(),
1288 id: *module_id,
1289 }),
1290 )
1291 .chain(
1292 constants
1293 .iter()
1294 .map(|(name, variable_id)| Exportable::VarDecl {
1295 name: name.clone(),
1296 id: *variable_id,
1297 }),
1298 )
1299 .collect();
1300
1301 import_pattern.constants = constants.iter().map(|(_, id)| *id).collect();
1302
1303 if let Some(m) = parent_module {
1304 m.track_imported_modules(&imported_modules)
1305 }
1306 working_set.use_decls(definitions.decls);
1307 working_set.use_modules(definitions.modules);
1308 working_set.use_variables(constants);
1309
1310 let import_pattern_expr = Expression::new(
1311 working_set,
1312 Expr::ImportPattern(Box::new(import_pattern)),
1313 Span::concat(args_spans),
1314 Type::Any,
1315 );
1316
1317 let mut call = call;
1318 call.set_parser_info("import_pattern".to_string(), import_pattern_expr);
1319
1320 (
1321 Pipeline::from_vec(vec![Expression::new(
1322 working_set,
1323 Expr::Call(call),
1324 Span::concat(spans),
1325 Type::Any,
1326 )]),
1327 exportables,
1328 )
1329}
1330
1331pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline {
1332 let spans = &lite_command.parts;
1333
1334 if working_set.get_span_contents(spans[0]) != b"hide" {
1335 working_set.error(ParseError::UnknownState(
1336 "internal error: Wrong call name for 'hide' command".into(),
1337 Span::concat(spans),
1338 ));
1339 return garbage_pipeline(working_set, spans);
1340 }
1341 if let Some(redirection) = lite_command.redirection.as_ref() {
1342 working_set.error(redirecting_builtin_error("hide", redirection));
1343 return garbage_pipeline(working_set, spans);
1344 }
1345
1346 let (call, args_spans) = match working_set.find_decl(b"hide") {
1347 Some(decl_id) => {
1348 let ParsedInternalCall {
1349 call,
1350 output,
1351 call_kind,
1352 } = parse_internal_call(
1353 working_set,
1354 spans[0],
1355 &spans[1..],
1356 decl_id,
1357 ArgumentParsingLevel::Full,
1358 None,
1359 );
1360
1361 if call_kind != CallKind::Valid {
1362 return Pipeline::from_vec(vec![Expression::new(
1363 working_set,
1364 Expr::Call(call),
1365 Span::concat(spans),
1366 output,
1367 )]);
1368 }
1369
1370 (call, &spans[1..])
1371 }
1372 None => {
1373 working_set.error(ParseError::UnknownState(
1374 "internal error: 'hide' declaration not found".into(),
1375 Span::concat(spans),
1376 ));
1377 return garbage_pipeline(working_set, spans);
1378 }
1379 };
1380
1381 let import_pattern_expr = parse_import_pattern(working_set, call.positional_iter(), args_spans);
1382
1383 let import_pattern = if let Expression {
1384 expr: Expr::ImportPattern(import_pattern),
1385 ..
1386 } = &import_pattern_expr
1387 {
1388 import_pattern.clone()
1389 } else {
1390 working_set.error(ParseError::UnknownState(
1391 "internal error: Import pattern positional is not import pattern".into(),
1392 import_pattern_expr.span,
1393 ));
1394 return garbage_pipeline(working_set, spans);
1395 };
1396
1397 let bytes = working_set.get_span_contents(spans[0]);
1398
1399 if bytes == b"hide" && spans.len() >= 2 {
1400 for span in spans[1..].iter() {
1401 parse_string(working_set, *span);
1402 }
1403
1404 let (is_module, module) =
1405 if let Some(module_id) = working_set.find_module(&import_pattern.head.name) {
1406 (true, working_set.get_module(module_id).clone())
1407 } else if import_pattern.members.is_empty() {
1408 if let Some(id) = working_set.find_decl(&import_pattern.head.name) {
1409 let mut module = Module::new(b"tmp".to_vec());
1410 module.add_decl(import_pattern.head.name.clone(), id);
1411
1412 (false, module)
1413 } else {
1414 (false, Module::new(b"tmp".to_vec()))
1415 }
1416 } else {
1417 working_set.error(ParseError::ModuleNotFound(
1418 spans[1],
1419 String::from_utf8_lossy(&import_pattern.head.name).to_string(),
1420 ));
1421 return garbage_pipeline(working_set, spans);
1422 };
1423
1424 let decls_to_hide = if import_pattern.members.is_empty() {
1425 if is_module {
1426 module.decl_names_with_head(&import_pattern.head.name)
1427 } else {
1428 module.decl_names()
1429 }
1430 } else {
1431 match &import_pattern.members[0] {
1432 ImportPatternMember::Glob { .. } => module.decl_names(),
1433 ImportPatternMember::Name { name, span } => {
1434 let mut decls = vec![];
1435
1436 if name == b"main" {
1437 if module.main.is_some() {
1438 decls.push(import_pattern.head.name.clone());
1439 } else {
1440 working_set.error(ParseError::ExportNotFound(*span));
1441 }
1442 } else if let Some(item) =
1443 module.decl_name_with_head(name, &import_pattern.head.name)
1444 {
1445 decls.push(item);
1446 } else {
1447 working_set.error(ParseError::ExportNotFound(*span));
1448 }
1449
1450 decls
1451 }
1452 ImportPatternMember::List { names } => {
1453 let mut decls = vec![];
1454
1455 for (name, span) in names {
1456 if name == b"main" {
1457 if module.main.is_some() {
1458 decls.push(import_pattern.head.name.clone());
1459 } else {
1460 working_set.error(ParseError::ExportNotFound(*span));
1461 break;
1462 }
1463 } else if let Some(item) =
1464 module.decl_name_with_head(name, &import_pattern.head.name)
1465 {
1466 decls.push(item);
1467 } else {
1468 working_set.error(ParseError::ExportNotFound(*span));
1469 break;
1470 }
1471 }
1472
1473 decls
1474 }
1475 }
1476 };
1477
1478 let import_pattern = {
1479 let decls: HashSet<Vec<u8>> = decls_to_hide.iter().cloned().collect();
1480
1481 import_pattern.with_hidden(decls)
1482 };
1483
1484 working_set.hide_decls(&decls_to_hide);
1485
1486 let import_pattern_expr = Expression::new(
1487 working_set,
1488 Expr::ImportPattern(Box::new(import_pattern)),
1489 Span::concat(args_spans),
1490 Type::Any,
1491 );
1492
1493 let mut call = call;
1494 call.set_parser_info("import_pattern".to_string(), import_pattern_expr);
1495
1496 Pipeline::from_vec(vec![Expression::new(
1497 working_set,
1498 Expr::Call(call),
1499 Span::concat(spans),
1500 Type::Any,
1501 )])
1502 } else {
1503 working_set.error(ParseError::UnknownState(
1504 "Expected structure: hide <name>".into(),
1505 Span::concat(spans),
1506 ));
1507 garbage_pipeline(working_set, spans)
1508 }
1509}
1510
1511pub fn parse_overlay_new(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
1512 let call_span = call.span();
1513
1514 let Some(expr) = call.positional_iter().next() else {
1515 working_set.error(ParseError::UnknownState(
1516 "internal error: Missing required positional after call parsing".into(),
1517 call_span,
1518 ));
1519 return garbage_pipeline(working_set, &[call_span]);
1520 };
1521
1522 let (overlay_name, _) =
1523 match eval_constant(working_set, expr).and_then(|v| v.coerce_into_string()) {
1524 Ok(s) => (s, expr.span),
1525 Err(err) => {
1526 working_set.error(err.wrap(working_set, call_span));
1527 return garbage_pipeline(working_set, &[call_span]);
1528 }
1529 };
1530
1531 let pipeline = Pipeline::from_vec(vec![Expression::new(
1532 working_set,
1533 Expr::Call(call),
1534 call_span,
1535 Type::Any,
1536 )]);
1537
1538 let module_id = working_set.add_module(
1539 &overlay_name,
1540 Module::new(overlay_name.as_bytes().to_vec()),
1541 vec![],
1542 );
1543
1544 working_set.add_overlay(
1545 overlay_name.as_bytes().to_vec(),
1546 module_id,
1547 nu_protocol::ResolvedImportPattern::new(vec![], vec![], vec![], vec![]),
1548 false,
1549 );
1550
1551 pipeline
1552}
1553
1554pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
1555 let call_span = call.span();
1556
1557 let (overlay_name_expr, as_name_expr) = {
1558 let mut iter = call.positional_iter();
1559 (iter.next(), iter.next())
1560 };
1561
1562 let Some(overlay_name_expr) = overlay_name_expr else {
1563 working_set.error(ParseError::UnknownState(
1564 "internal error: Missing required positional after call parsing".into(),
1565 call_span,
1566 ));
1567 return garbage_pipeline(working_set, &[call_span]);
1568 };
1569
1570 let (overlay_name, overlay_name_span) = match eval_constant(working_set, overlay_name_expr) {
1571 Ok(nu_protocol::Value::Nothing { .. }) => {
1572 let mut call = call;
1573 call.set_parser_info(
1574 "noop".to_string(),
1575 Expression::new_unknown(Expr::Bool(true), Span::unknown(), Type::Bool),
1576 );
1577 return Pipeline::from_vec(vec![Expression::new(
1578 working_set,
1579 Expr::Call(call),
1580 call_span,
1581 Type::Any,
1582 )]);
1583 }
1584 result => match result.and_then(|v| v.coerce_into_string()) {
1585 Ok(s) => (s, overlay_name_expr.span),
1586 Err(err) => {
1587 working_set.error(err.wrap(working_set, call_span));
1588 return garbage_pipeline(working_set, &[call_span]);
1589 }
1590 },
1591 };
1592
1593 let new_name = if let Some(as_name_expr) = as_name_expr {
1594 let Some((b"as", new_name_expression)) = as_name_expr.as_keyword_with_name() else {
1595 working_set.error(ParseError::ExpectedKeyword(
1596 "as keyword".to_string(),
1597 as_name_expr.span,
1598 ));
1599 return garbage_pipeline(working_set, &[call_span]);
1600 };
1601
1602 match eval_constant(working_set, new_name_expression).and_then(|v| v.coerce_into_string()) {
1603 Ok(s) => Some(nu_protocol::Spanned {
1604 item: s,
1605 span: new_name_expression.span,
1606 }),
1607 Err(err) => {
1608 working_set.error(err.wrap(working_set, call_span));
1609 return garbage_pipeline(working_set, &[call_span]);
1610 }
1611 }
1612 } else {
1613 None
1614 };
1615
1616 let Ok(has_prefix) = has_flag_const(working_set, &call, "prefix") else {
1617 return garbage_pipeline(working_set, &[call_span]);
1618 };
1619 let Ok(do_reload) = has_flag_const(working_set, &call, "reload") else {
1620 return garbage_pipeline(working_set, &[call_span]);
1621 };
1622
1623 let pipeline = Pipeline::from_vec(vec![Expression::new(
1624 working_set,
1625 Expr::Call(call.clone()),
1626 call_span,
1627 Type::Any,
1628 )]);
1629
1630 let (final_overlay_name, origin_module, origin_module_id, is_module_updated) =
1631 if let Some(overlay_frame) = working_set.find_overlay(overlay_name.as_bytes()) {
1632 if has_prefix && !overlay_frame.prefixed {
1633 working_set.error(ParseError::OverlayPrefixMismatch(
1634 overlay_name,
1635 "without".to_string(),
1636 overlay_name_span,
1637 ));
1638 return pipeline;
1639 }
1640
1641 if !has_prefix && overlay_frame.prefixed {
1642 working_set.error(ParseError::OverlayPrefixMismatch(
1643 overlay_name,
1644 "with".to_string(),
1645 overlay_name_span,
1646 ));
1647 return pipeline;
1648 }
1649
1650 if let Some(new_name) = new_name
1651 && new_name.item != overlay_name
1652 {
1653 working_set.error(ParseError::CantAddOverlayHelp(
1654 format!(
1655 "Cannot add overlay as '{}' because it already exists under the name '{}'",
1656 new_name.item, overlay_name
1657 ),
1658 new_name.span,
1659 ));
1660 return pipeline;
1661 }
1662
1663 let module_id = overlay_frame.origin;
1664
1665 if let Some(new_module_id) = working_set.find_module(overlay_name.as_bytes()) {
1666 if !do_reload && (module_id == new_module_id) {
1667 (
1668 overlay_name,
1669 Module::new(working_set.get_module(module_id).name.clone()),
1670 module_id,
1671 false,
1672 )
1673 } else {
1674 (
1675 overlay_name,
1676 working_set.get_module(new_module_id).clone(),
1677 new_module_id,
1678 true,
1679 )
1680 }
1681 } else {
1682 let module_name = overlay_name.as_bytes().to_vec();
1683 (overlay_name, Module::new(module_name), module_id, true)
1684 }
1685 } else {
1686 if let Some(module_id) = working_set.find_module(overlay_name.as_bytes()) {
1687 (
1688 new_name.map(|spanned| spanned.item).unwrap_or(overlay_name),
1689 working_set.get_module(module_id).clone(),
1690 module_id,
1691 true,
1692 )
1693 } else if let Some(module_id) = parse_module_file_or_dir(
1694 working_set,
1695 overlay_name.as_bytes(),
1696 overlay_name_span,
1697 new_name.as_ref().map(|spanned| spanned.item.clone()),
1698 ) {
1699 let new_module = working_set.get_module(module_id).clone();
1700 (
1701 new_name
1702 .map(|spanned| spanned.item)
1703 .unwrap_or_else(|| String::from_utf8_lossy(&new_module.name).to_string()),
1704 new_module,
1705 module_id,
1706 true,
1707 )
1708 } else {
1709 working_set.error(ParseError::ModuleOrOverlayNotFound(overlay_name_span));
1710 return pipeline;
1711 }
1712 };
1713
1714 if check_main_keyword_shadow(
1715 working_set,
1716 origin_module.main.is_some(),
1717 final_overlay_name.as_bytes(),
1718 overlay_name_span,
1719 ) {
1720 return pipeline;
1721 }
1722
1723 let (definitions, errors) = if is_module_updated {
1724 if has_prefix {
1725 origin_module.resolve_import_pattern(
1726 working_set,
1727 origin_module_id,
1728 &[],
1729 Some(final_overlay_name.as_bytes()),
1730 call.head,
1731 &mut vec![],
1732 )
1733 } else {
1734 origin_module.resolve_import_pattern(
1735 working_set,
1736 origin_module_id,
1737 &[ImportPatternMember::Glob {
1738 span: overlay_name_span,
1739 }],
1740 Some(final_overlay_name.as_bytes()),
1741 call.head,
1742 &mut vec![],
1743 )
1744 }
1745 } else {
1746 (
1747 nu_protocol::ResolvedImportPattern::new(vec![], vec![], vec![], vec![]),
1748 vec![],
1749 )
1750 };
1751
1752 if errors.is_empty() {
1753 working_set.add_overlay(
1754 final_overlay_name.as_bytes().to_vec(),
1755 origin_module_id,
1756 definitions,
1757 has_prefix,
1758 );
1759 } else {
1760 working_set.parse_errors.extend(errors);
1761 }
1762
1763 let mut call = call;
1764 call.set_parser_info(
1765 "overlay_expr".to_string(),
1766 Expression::new(
1767 working_set,
1768 Expr::Overlay(if is_module_updated {
1769 Some(origin_module_id)
1770 } else {
1771 None
1772 }),
1773 overlay_name_span,
1774 Type::Any,
1775 ),
1776 );
1777
1778 Pipeline::from_vec(vec![Expression::new(
1779 working_set,
1780 Expr::Call(call),
1781 call_span,
1782 Type::Any,
1783 )])
1784}
1785
1786pub fn parse_overlay_hide(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
1787 let call_span = call.span();
1788
1789 let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_iter().next() {
1790 match eval_constant(working_set, expr) {
1791 Ok(val) => match val.coerce_into_string() {
1792 Ok(s) => (s, expr.span),
1793 Err(err) => {
1794 working_set.error(err.wrap(working_set, call_span));
1795 return garbage_pipeline(working_set, &[call_span]);
1796 }
1797 },
1798 Err(err) => {
1799 working_set.error(err.wrap(working_set, call_span));
1800 return garbage_pipeline(working_set, &[call_span]);
1801 }
1802 }
1803 } else {
1804 (
1805 String::from_utf8_lossy(working_set.last_overlay_name()).to_string(),
1806 call_span,
1807 )
1808 };
1809
1810 let Ok(keep_custom) = has_flag_const(working_set, &call, "keep-custom") else {
1811 return garbage_pipeline(working_set, &[call_span]);
1812 };
1813
1814 let pipeline = Pipeline::from_vec(vec![Expression::new(
1815 working_set,
1816 Expr::Call(call),
1817 call_span,
1818 Type::Any,
1819 )]);
1820
1821 if overlay_name == nu_protocol::engine::DEFAULT_OVERLAY_NAME {
1822 working_set.error(ParseError::CantHideDefaultOverlay(
1823 overlay_name,
1824 overlay_name_span,
1825 ));
1826
1827 return pipeline;
1828 }
1829
1830 if !working_set
1831 .unique_overlay_names()
1832 .contains(&overlay_name.as_bytes())
1833 {
1834 working_set.error(ParseError::ActiveOverlayNotFound(overlay_name_span));
1835 return pipeline;
1836 }
1837
1838 if working_set.num_overlays() < 2 {
1839 working_set.error(ParseError::CantRemoveLastOverlay(overlay_name_span));
1840 return pipeline;
1841 }
1842
1843 working_set.remove_overlay(overlay_name.as_bytes(), keep_custom);
1844
1845 pipeline
1846}