Skip to main content

nu_parser/
parse_module.rs

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}