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