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