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 working_set.error(ParseError::Unclosed("}", Span::new(end, end)));
1010 }
1011
1012 let block_content_span = Span::new(start, end);
1013
1014 let (block, module, inner_comments) =
1015 parse_module_block(working_set, block_content_span, module_name.as_bytes());
1016
1017 let block_id = working_set.add_block(Arc::new(block));
1018
1019 module_comments.extend(inner_comments);
1020 let module_id = working_set.add_module(&module_name, module, module_comments);
1021
1022 let block_expr = Expression::new(
1023 working_set,
1024 Expr::Block(block_id),
1025 block_expr_span,
1026 Type::Block,
1027 );
1028
1029 if !call.set_kth_argument(1, Argument::Positional(block_expr)) {
1030 working_set.error(ParseError::InternalError(
1031 "Failed to set the block argument".into(),
1032 block_expr_span,
1033 ));
1034 }
1035
1036 (
1037 Pipeline::from_vec(vec![Expression::new(
1038 working_set,
1039 Expr::Call(call),
1040 Span::concat(spans),
1041 Type::Any,
1042 )]),
1043 Some(module_id),
1044 )
1045}
1046
1047pub fn parse_use(
1048 working_set: &mut StateWorkingSet,
1049 lite_command: &LiteCommand,
1050 parent_module: Option<&mut Module>,
1051) -> (Pipeline, Vec<Exportable>) {
1052 let spans = &lite_command.parts;
1053
1054 let (name_span, split_id) =
1055 if spans.len() > 1 && working_set.get_span_contents(spans[0]) == b"export" {
1056 (spans[1], 2)
1057 } else {
1058 (spans[0], 1)
1059 };
1060
1061 let use_call = working_set.get_span_contents(name_span).to_vec();
1062 if use_call != b"use" {
1063 working_set.error(ParseError::UnknownState(
1064 "internal error: Wrong call name for 'use' command".into(),
1065 Span::concat(spans),
1066 ));
1067 return (garbage_pipeline(working_set, spans), vec![]);
1068 }
1069
1070 if working_set.get_span_contents(name_span) != b"use" {
1071 working_set.error(ParseError::UnknownState(
1072 "internal error: Wrong call name for 'use' command".into(),
1073 Span::concat(spans),
1074 ));
1075 return (garbage_pipeline(working_set, spans), vec![]);
1076 }
1077
1078 if let Some(redirection) = lite_command.redirection.as_ref() {
1079 working_set.error(redirecting_builtin_error("use", redirection));
1080 return (garbage_pipeline(working_set, spans), vec![]);
1081 }
1082
1083 let (call, call_span, args_spans) = match working_set.find_decl(b"use") {
1084 Some(decl_id) => {
1085 let (command_spans, rest_spans) = spans.split_at(split_id);
1086
1087 let ParsedInternalCall {
1088 call,
1089 output,
1090 call_kind,
1091 } = parse_internal_call(
1092 working_set,
1093 Span::concat(command_spans),
1094 rest_spans,
1095 decl_id,
1096 ArgumentParsingLevel::Full,
1097 None,
1098 );
1099
1100 let call_span = Span::concat(spans);
1101 if call_kind != CallKind::Valid {
1102 return (
1103 Pipeline::from_vec(vec![Expression::new(
1104 working_set,
1105 Expr::Call(call),
1106 call_span,
1107 output,
1108 )]),
1109 vec![],
1110 );
1111 }
1112
1113 (call, call_span, rest_spans)
1114 }
1115 None => {
1116 working_set.error(ParseError::UnknownState(
1117 "internal error: 'use' declaration not found".into(),
1118 Span::concat(spans),
1119 ));
1120 return (garbage_pipeline(working_set, spans), vec![]);
1121 }
1122 };
1123
1124 let import_pattern_expr = parse_import_pattern(working_set, call.positional_iter(), args_spans);
1125
1126 let import_pattern = match &import_pattern_expr {
1127 Expression {
1128 expr: Expr::Nothing,
1129 ..
1130 } => {
1131 let mut call = call;
1132 call.set_parser_info(
1133 "noop".to_string(),
1134 Expression::new_unknown(Expr::Nothing, Span::unknown(), Type::Nothing),
1135 );
1136 return (
1137 Pipeline::from_vec(vec![Expression::new(
1138 working_set,
1139 Expr::Call(call),
1140 Span::concat(spans),
1141 Type::Any,
1142 )]),
1143 vec![],
1144 );
1145 }
1146 Expression {
1147 expr: Expr::ImportPattern(import_pattern),
1148 ..
1149 } => import_pattern.clone(),
1150 _ => {
1151 working_set.error(ParseError::UnknownState(
1152 "internal error: Import pattern positional is not import pattern".into(),
1153 import_pattern_expr.span,
1154 ));
1155 return (garbage_pipeline(working_set, spans), vec![]);
1156 }
1157 };
1158
1159 let (mut import_pattern, module, module_id) = if let Some(module_id) = import_pattern.head.id {
1160 let module = working_set.get_module(module_id).clone();
1161 (
1162 ImportPattern {
1163 head: ImportPatternHead {
1164 name: module.name.clone(),
1165 id: Some(module_id),
1166 span: import_pattern.head.span,
1167 },
1168 members: import_pattern.members,
1169 hidden: HashSet::new(),
1170 constants: vec![],
1171 },
1172 module,
1173 module_id,
1174 )
1175 } else if let Some(module_id) = parse_module_file_or_dir(
1176 working_set,
1177 &import_pattern.head.name,
1178 import_pattern.head.span,
1179 None,
1180 ) {
1181 let module = working_set.get_module(module_id).clone();
1182 (
1183 ImportPattern {
1184 head: ImportPatternHead {
1185 name: module.name.clone(),
1186 id: Some(module_id),
1187 span: import_pattern.head.span,
1188 },
1189 members: import_pattern.members,
1190 hidden: HashSet::new(),
1191 constants: vec![],
1192 },
1193 module,
1194 module_id,
1195 )
1196 } else {
1197 working_set.error(ParseError::ModuleNotFound(
1198 import_pattern.head.span,
1199 String::from_utf8_lossy(&import_pattern.head.name).to_string(),
1200 ));
1201 return (
1202 Pipeline::from_vec(vec![Expression::new(
1203 working_set,
1204 Expr::Call(call),
1205 call_span,
1206 Type::Any,
1207 )]),
1208 vec![],
1209 );
1210 };
1211
1212 let mut imported_modules = vec![];
1213 let (definitions, errors) = module.resolve_import_pattern(
1214 working_set,
1215 module_id,
1216 &import_pattern.members,
1217 None,
1218 name_span,
1219 &mut imported_modules,
1220 );
1221
1222 working_set.parse_errors.extend(errors);
1223
1224 let mut constants = vec![];
1225
1226 for (name, const_vid) in definitions.constants {
1227 constants.push((name, const_vid));
1228 }
1229
1230 for (name, const_val) in definitions.constant_values {
1231 let const_var_id =
1232 working_set.add_variable(name.clone(), name_span, const_val.get_type(), false);
1233 working_set.set_variable_const_val(const_var_id, const_val);
1234 constants.push((name, const_var_id));
1235 }
1236
1237 let exportables = definitions
1238 .decls
1239 .iter()
1240 .map(|(name, decl_id)| Exportable::Decl {
1241 name: name.clone(),
1242 id: *decl_id,
1243 })
1244 .chain(
1245 definitions
1246 .modules
1247 .iter()
1248 .map(|(name, module_id)| Exportable::Module {
1249 name: name.clone(),
1250 id: *module_id,
1251 }),
1252 )
1253 .chain(
1254 constants
1255 .iter()
1256 .map(|(name, variable_id)| Exportable::VarDecl {
1257 name: name.clone(),
1258 id: *variable_id,
1259 }),
1260 )
1261 .collect();
1262
1263 import_pattern.constants = constants.iter().map(|(_, id)| *id).collect();
1264
1265 if let Some(m) = parent_module {
1266 m.track_imported_modules(&imported_modules)
1267 }
1268 working_set.use_decls(definitions.decls);
1269 working_set.use_modules(definitions.modules);
1270 working_set.use_variables(constants);
1271
1272 let import_pattern_expr = Expression::new(
1273 working_set,
1274 Expr::ImportPattern(Box::new(import_pattern)),
1275 Span::concat(args_spans),
1276 Type::Any,
1277 );
1278
1279 let mut call = call;
1280 call.set_parser_info("import_pattern".to_string(), import_pattern_expr);
1281
1282 (
1283 Pipeline::from_vec(vec![Expression::new(
1284 working_set,
1285 Expr::Call(call),
1286 Span::concat(spans),
1287 Type::Any,
1288 )]),
1289 exportables,
1290 )
1291}
1292
1293pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline {
1294 let spans = &lite_command.parts;
1295
1296 if working_set.get_span_contents(spans[0]) != b"hide" {
1297 working_set.error(ParseError::UnknownState(
1298 "internal error: Wrong call name for 'hide' command".into(),
1299 Span::concat(spans),
1300 ));
1301 return garbage_pipeline(working_set, spans);
1302 }
1303 if let Some(redirection) = lite_command.redirection.as_ref() {
1304 working_set.error(redirecting_builtin_error("hide", redirection));
1305 return garbage_pipeline(working_set, spans);
1306 }
1307
1308 let (call, args_spans) = match working_set.find_decl(b"hide") {
1309 Some(decl_id) => {
1310 let ParsedInternalCall {
1311 call,
1312 output,
1313 call_kind,
1314 } = parse_internal_call(
1315 working_set,
1316 spans[0],
1317 &spans[1..],
1318 decl_id,
1319 ArgumentParsingLevel::Full,
1320 None,
1321 );
1322
1323 if call_kind != CallKind::Valid {
1324 return Pipeline::from_vec(vec![Expression::new(
1325 working_set,
1326 Expr::Call(call),
1327 Span::concat(spans),
1328 output,
1329 )]);
1330 }
1331
1332 (call, &spans[1..])
1333 }
1334 None => {
1335 working_set.error(ParseError::UnknownState(
1336 "internal error: 'hide' declaration not found".into(),
1337 Span::concat(spans),
1338 ));
1339 return garbage_pipeline(working_set, spans);
1340 }
1341 };
1342
1343 let import_pattern_expr = parse_import_pattern(working_set, call.positional_iter(), args_spans);
1344
1345 let import_pattern = if let Expression {
1346 expr: Expr::ImportPattern(import_pattern),
1347 ..
1348 } = &import_pattern_expr
1349 {
1350 import_pattern.clone()
1351 } else {
1352 working_set.error(ParseError::UnknownState(
1353 "internal error: Import pattern positional is not import pattern".into(),
1354 import_pattern_expr.span,
1355 ));
1356 return garbage_pipeline(working_set, spans);
1357 };
1358
1359 let bytes = working_set.get_span_contents(spans[0]);
1360
1361 if bytes == b"hide" && spans.len() >= 2 {
1362 for span in spans[1..].iter() {
1363 parse_string(working_set, *span);
1364 }
1365
1366 let (is_module, module) =
1367 if let Some(module_id) = working_set.find_module(&import_pattern.head.name) {
1368 (true, working_set.get_module(module_id).clone())
1369 } else if import_pattern.members.is_empty() {
1370 if let Some(id) = working_set.find_decl(&import_pattern.head.name) {
1371 let mut module = Module::new(b"tmp".to_vec());
1372 module.add_decl(import_pattern.head.name.clone(), id);
1373
1374 (false, module)
1375 } else {
1376 (false, Module::new(b"tmp".to_vec()))
1377 }
1378 } else {
1379 working_set.error(ParseError::ModuleNotFound(
1380 spans[1],
1381 String::from_utf8_lossy(&import_pattern.head.name).to_string(),
1382 ));
1383 return garbage_pipeline(working_set, spans);
1384 };
1385
1386 let decls_to_hide = if import_pattern.members.is_empty() {
1387 if is_module {
1388 module.decl_names_with_head(&import_pattern.head.name)
1389 } else {
1390 module.decl_names()
1391 }
1392 } else {
1393 match &import_pattern.members[0] {
1394 ImportPatternMember::Glob { .. } => module.decl_names(),
1395 ImportPatternMember::Name { name, span } => {
1396 let mut decls = vec![];
1397
1398 if name == b"main" {
1399 if module.main.is_some() {
1400 decls.push(import_pattern.head.name.clone());
1401 } else {
1402 working_set.error(ParseError::ExportNotFound(*span));
1403 }
1404 } else if let Some(item) =
1405 module.decl_name_with_head(name, &import_pattern.head.name)
1406 {
1407 decls.push(item);
1408 } else {
1409 working_set.error(ParseError::ExportNotFound(*span));
1410 }
1411
1412 decls
1413 }
1414 ImportPatternMember::List { names } => {
1415 let mut decls = vec![];
1416
1417 for (name, span) in names {
1418 if name == b"main" {
1419 if module.main.is_some() {
1420 decls.push(import_pattern.head.name.clone());
1421 } else {
1422 working_set.error(ParseError::ExportNotFound(*span));
1423 break;
1424 }
1425 } else if let Some(item) =
1426 module.decl_name_with_head(name, &import_pattern.head.name)
1427 {
1428 decls.push(item);
1429 } else {
1430 working_set.error(ParseError::ExportNotFound(*span));
1431 break;
1432 }
1433 }
1434
1435 decls
1436 }
1437 }
1438 };
1439
1440 let import_pattern = {
1441 let decls: HashSet<Vec<u8>> = decls_to_hide.iter().cloned().collect();
1442
1443 import_pattern.with_hidden(decls)
1444 };
1445
1446 working_set.hide_decls(&decls_to_hide);
1447
1448 let import_pattern_expr = Expression::new(
1449 working_set,
1450 Expr::ImportPattern(Box::new(import_pattern)),
1451 Span::concat(args_spans),
1452 Type::Any,
1453 );
1454
1455 let mut call = call;
1456 call.set_parser_info("import_pattern".to_string(), import_pattern_expr);
1457
1458 Pipeline::from_vec(vec![Expression::new(
1459 working_set,
1460 Expr::Call(call),
1461 Span::concat(spans),
1462 Type::Any,
1463 )])
1464 } else {
1465 working_set.error(ParseError::UnknownState(
1466 "Expected structure: hide <name>".into(),
1467 Span::concat(spans),
1468 ));
1469 garbage_pipeline(working_set, spans)
1470 }
1471}
1472
1473pub fn parse_overlay_new(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
1474 let call_span = call.span();
1475
1476 let Some(expr) = call.positional_iter().next() else {
1477 working_set.error(ParseError::UnknownState(
1478 "internal error: Missing required positional after call parsing".into(),
1479 call_span,
1480 ));
1481 return garbage_pipeline(working_set, &[call_span]);
1482 };
1483
1484 let (overlay_name, _) =
1485 match eval_constant(working_set, expr).and_then(|v| v.coerce_into_string()) {
1486 Ok(s) => (s, expr.span),
1487 Err(err) => {
1488 working_set.error(err.wrap(working_set, call_span));
1489 return garbage_pipeline(working_set, &[call_span]);
1490 }
1491 };
1492
1493 let pipeline = Pipeline::from_vec(vec![Expression::new(
1494 working_set,
1495 Expr::Call(call),
1496 call_span,
1497 Type::Any,
1498 )]);
1499
1500 let module_id = working_set.add_module(
1501 &overlay_name,
1502 Module::new(overlay_name.as_bytes().to_vec()),
1503 vec![],
1504 );
1505
1506 working_set.add_overlay(
1507 overlay_name.as_bytes().to_vec(),
1508 module_id,
1509 nu_protocol::ResolvedImportPattern::new(vec![], vec![], vec![], vec![]),
1510 false,
1511 );
1512
1513 pipeline
1514}
1515
1516pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
1517 let call_span = call.span();
1518
1519 let (overlay_name_expr, as_name_expr) = {
1520 let mut iter = call.positional_iter();
1521 (iter.next(), iter.next())
1522 };
1523
1524 let Some(overlay_name_expr) = overlay_name_expr else {
1525 working_set.error(ParseError::UnknownState(
1526 "internal error: Missing required positional after call parsing".into(),
1527 call_span,
1528 ));
1529 return garbage_pipeline(working_set, &[call_span]);
1530 };
1531
1532 let (overlay_name, overlay_name_span) = match eval_constant(working_set, overlay_name_expr) {
1533 Ok(nu_protocol::Value::Nothing { .. }) => {
1534 let mut call = call;
1535 call.set_parser_info(
1536 "noop".to_string(),
1537 Expression::new_unknown(Expr::Bool(true), Span::unknown(), Type::Bool),
1538 );
1539 return Pipeline::from_vec(vec![Expression::new(
1540 working_set,
1541 Expr::Call(call),
1542 call_span,
1543 Type::Any,
1544 )]);
1545 }
1546 result => match result.and_then(|v| v.coerce_into_string()) {
1547 Ok(s) => (s, overlay_name_expr.span),
1548 Err(err) => {
1549 working_set.error(err.wrap(working_set, call_span));
1550 return garbage_pipeline(working_set, &[call_span]);
1551 }
1552 },
1553 };
1554
1555 let new_name = if let Some(as_name_expr) = as_name_expr {
1556 let Some((b"as", new_name_expression)) = as_name_expr.as_keyword_with_name() else {
1557 working_set.error(ParseError::ExpectedKeyword(
1558 "as keyword".to_string(),
1559 as_name_expr.span,
1560 ));
1561 return garbage_pipeline(working_set, &[call_span]);
1562 };
1563
1564 match eval_constant(working_set, new_name_expression).and_then(|v| v.coerce_into_string()) {
1565 Ok(s) => Some(nu_protocol::Spanned {
1566 item: s,
1567 span: new_name_expression.span,
1568 }),
1569 Err(err) => {
1570 working_set.error(err.wrap(working_set, call_span));
1571 return garbage_pipeline(working_set, &[call_span]);
1572 }
1573 }
1574 } else {
1575 None
1576 };
1577
1578 let Ok(has_prefix) = has_flag_const(working_set, &call, "prefix") else {
1579 return garbage_pipeline(working_set, &[call_span]);
1580 };
1581 let Ok(do_reload) = has_flag_const(working_set, &call, "reload") else {
1582 return garbage_pipeline(working_set, &[call_span]);
1583 };
1584
1585 let pipeline = Pipeline::from_vec(vec![Expression::new(
1586 working_set,
1587 Expr::Call(call.clone()),
1588 call_span,
1589 Type::Any,
1590 )]);
1591
1592 let (final_overlay_name, origin_module, origin_module_id, is_module_updated) =
1593 if let Some(overlay_frame) = working_set.find_overlay(overlay_name.as_bytes()) {
1594 if has_prefix && !overlay_frame.prefixed {
1595 working_set.error(ParseError::OverlayPrefixMismatch(
1596 overlay_name,
1597 "without".to_string(),
1598 overlay_name_span,
1599 ));
1600 return pipeline;
1601 }
1602
1603 if !has_prefix && overlay_frame.prefixed {
1604 working_set.error(ParseError::OverlayPrefixMismatch(
1605 overlay_name,
1606 "with".to_string(),
1607 overlay_name_span,
1608 ));
1609 return pipeline;
1610 }
1611
1612 if let Some(new_name) = new_name
1613 && new_name.item != overlay_name
1614 {
1615 working_set.error(ParseError::CantAddOverlayHelp(
1616 format!(
1617 "Cannot add overlay as '{}' because it already exists under the name '{}'",
1618 new_name.item, overlay_name
1619 ),
1620 new_name.span,
1621 ));
1622 return pipeline;
1623 }
1624
1625 let module_id = overlay_frame.origin;
1626
1627 if let Some(new_module_id) = working_set.find_module(overlay_name.as_bytes()) {
1628 if !do_reload && (module_id == new_module_id) {
1629 (
1630 overlay_name,
1631 Module::new(working_set.get_module(module_id).name.clone()),
1632 module_id,
1633 false,
1634 )
1635 } else {
1636 (
1637 overlay_name,
1638 working_set.get_module(new_module_id).clone(),
1639 new_module_id,
1640 true,
1641 )
1642 }
1643 } else {
1644 let module_name = overlay_name.as_bytes().to_vec();
1645 (overlay_name, Module::new(module_name), module_id, true)
1646 }
1647 } else {
1648 if let Some(module_id) = working_set.find_module(overlay_name.as_bytes()) {
1649 (
1650 new_name.map(|spanned| spanned.item).unwrap_or(overlay_name),
1651 working_set.get_module(module_id).clone(),
1652 module_id,
1653 true,
1654 )
1655 } else if let Some(module_id) = parse_module_file_or_dir(
1656 working_set,
1657 overlay_name.as_bytes(),
1658 overlay_name_span,
1659 new_name.as_ref().map(|spanned| spanned.item.clone()),
1660 ) {
1661 let new_module = working_set.get_module(module_id).clone();
1662 (
1663 new_name
1664 .map(|spanned| spanned.item)
1665 .unwrap_or_else(|| String::from_utf8_lossy(&new_module.name).to_string()),
1666 new_module,
1667 module_id,
1668 true,
1669 )
1670 } else {
1671 working_set.error(ParseError::ModuleOrOverlayNotFound(overlay_name_span));
1672 return pipeline;
1673 }
1674 };
1675
1676 let (definitions, errors) = if is_module_updated {
1677 if has_prefix {
1678 origin_module.resolve_import_pattern(
1679 working_set,
1680 origin_module_id,
1681 &[],
1682 Some(final_overlay_name.as_bytes()),
1683 call.head,
1684 &mut vec![],
1685 )
1686 } else {
1687 origin_module.resolve_import_pattern(
1688 working_set,
1689 origin_module_id,
1690 &[ImportPatternMember::Glob {
1691 span: overlay_name_span,
1692 }],
1693 Some(final_overlay_name.as_bytes()),
1694 call.head,
1695 &mut vec![],
1696 )
1697 }
1698 } else {
1699 (
1700 nu_protocol::ResolvedImportPattern::new(vec![], vec![], vec![], vec![]),
1701 vec![],
1702 )
1703 };
1704
1705 if errors.is_empty() {
1706 working_set.add_overlay(
1707 final_overlay_name.as_bytes().to_vec(),
1708 origin_module_id,
1709 definitions,
1710 has_prefix,
1711 );
1712 } else {
1713 working_set.parse_errors.extend(errors);
1714 }
1715
1716 let mut call = call;
1717 call.set_parser_info(
1718 "overlay_expr".to_string(),
1719 Expression::new(
1720 working_set,
1721 Expr::Overlay(if is_module_updated {
1722 Some(origin_module_id)
1723 } else {
1724 None
1725 }),
1726 overlay_name_span,
1727 Type::Any,
1728 ),
1729 );
1730
1731 Pipeline::from_vec(vec![Expression::new(
1732 working_set,
1733 Expr::Call(call),
1734 call_span,
1735 Type::Any,
1736 )])
1737}
1738
1739pub fn parse_overlay_hide(working_set: &mut StateWorkingSet, call: Box<Call>) -> Pipeline {
1740 let call_span = call.span();
1741
1742 let (overlay_name, overlay_name_span) = if let Some(expr) = call.positional_iter().next() {
1743 match eval_constant(working_set, expr) {
1744 Ok(val) => match val.coerce_into_string() {
1745 Ok(s) => (s, expr.span),
1746 Err(err) => {
1747 working_set.error(err.wrap(working_set, call_span));
1748 return garbage_pipeline(working_set, &[call_span]);
1749 }
1750 },
1751 Err(err) => {
1752 working_set.error(err.wrap(working_set, call_span));
1753 return garbage_pipeline(working_set, &[call_span]);
1754 }
1755 }
1756 } else {
1757 (
1758 String::from_utf8_lossy(working_set.last_overlay_name()).to_string(),
1759 call_span,
1760 )
1761 };
1762
1763 let Ok(keep_custom) = has_flag_const(working_set, &call, "keep-custom") else {
1764 return garbage_pipeline(working_set, &[call_span]);
1765 };
1766
1767 let pipeline = Pipeline::from_vec(vec![Expression::new(
1768 working_set,
1769 Expr::Call(call),
1770 call_span,
1771 Type::Any,
1772 )]);
1773
1774 if overlay_name == nu_protocol::engine::DEFAULT_OVERLAY_NAME {
1775 working_set.error(ParseError::CantHideDefaultOverlay(
1776 overlay_name,
1777 overlay_name_span,
1778 ));
1779
1780 return pipeline;
1781 }
1782
1783 if !working_set
1784 .unique_overlay_names()
1785 .contains(&overlay_name.as_bytes())
1786 {
1787 working_set.error(ParseError::ActiveOverlayNotFound(overlay_name_span));
1788 return pipeline;
1789 }
1790
1791 if working_set.num_overlays() < 2 {
1792 working_set.error(ParseError::CantRemoveLastOverlay(overlay_name_span));
1793 return pipeline;
1794 }
1795
1796 working_set.remove_overlay(overlay_name.as_bytes(), keep_custom);
1797
1798 pipeline
1799}