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