1#![allow(clippy::byte_char_slices)]
2
3use crate::{
4 lex::{is_assignment_operator, lex, lex_n_tokens, lex_signature, LexState},
5 lite_parser::{lite_parse, LiteCommand, LitePipeline, LiteRedirection, LiteRedirectionTarget},
6 parse_keywords::*,
7 parse_patterns::parse_pattern,
8 parse_shape_specs::{parse_shape_name, parse_type, ShapeDescriptorUse},
9 type_check::{self, check_range_types, math_result_type, type_compatible},
10 Token, TokenContents,
11};
12use itertools::Itertools;
13use log::trace;
14use nu_engine::DIR_VAR_PARSER_INFO;
15use nu_protocol::{
16 ast::*, engine::StateWorkingSet, eval_const::eval_constant, BlockId, DeclId, DidYouMean,
17 FilesizeUnit, Flag, ParseError, PositionalArg, ShellError, Signature, Span, Spanned,
18 SyntaxShape, Type, Value, VarId, ENV_VARIABLE_ID, IN_VARIABLE_ID,
19};
20use std::{
21 collections::{HashMap, HashSet},
22 num::ParseIntError,
23 str,
24 sync::Arc,
25};
26
27pub fn garbage(working_set: &mut StateWorkingSet, span: Span) -> Expression {
28 Expression::garbage(working_set, span)
29}
30
31pub fn garbage_pipeline(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline {
32 Pipeline::from_vec(vec![garbage(working_set, Span::concat(spans))])
33}
34
35fn is_identifier_byte(b: u8) -> bool {
36 b != b'.'
37 && b != b'['
38 && b != b'('
39 && b != b'{'
40 && b != b'+'
41 && b != b'-'
42 && b != b'*'
43 && b != b'^'
44 && b != b'/'
45 && b != b'='
46 && b != b'!'
47 && b != b'<'
48 && b != b'>'
49 && b != b'&'
50 && b != b'|'
51}
52
53pub fn is_math_expression_like(working_set: &mut StateWorkingSet, span: Span) -> bool {
54 let bytes = working_set.get_span_contents(span);
55 if bytes.is_empty() {
56 return false;
57 }
58
59 if bytes == b"true"
60 || bytes == b"false"
61 || bytes == b"null"
62 || bytes == b"not"
63 || bytes == b"if"
64 || bytes == b"match"
65 {
66 return true;
67 }
68
69 let b = bytes[0];
70
71 if bytes.starts_with(b"r#") {
73 return true;
74 }
75
76 if b == b'(' || b == b'{' || b == b'[' || b == b'$' || b == b'"' || b == b'\'' || b == b'-' {
77 return true;
78 }
79
80 let starting_error_count = working_set.parse_errors.len();
81
82 parse_number(working_set, span);
84 if working_set.parse_errors.len() == starting_error_count {
85 return true;
86 }
87 working_set.parse_errors.truncate(starting_error_count);
88
89 parse_filesize(working_set, span);
91 if working_set.parse_errors.len() == starting_error_count {
92 return true;
93 }
94 working_set.parse_errors.truncate(starting_error_count);
95
96 parse_duration(working_set, span);
97 if working_set.parse_errors.len() == starting_error_count {
98 return true;
99 }
100 working_set.parse_errors.truncate(starting_error_count);
101
102 parse_datetime(working_set, span);
103 if working_set.parse_errors.len() == starting_error_count {
104 return true;
105 }
106 working_set.parse_errors.truncate(starting_error_count);
107
108 parse_binary(working_set, span);
109 if working_set.parse_errors.len() == starting_error_count {
110 return true;
111 }
112 working_set.parse_errors.truncate(starting_error_count);
113
114 let is_range = parse_range(working_set, span).is_some();
115 working_set.parse_errors.truncate(starting_error_count);
116 is_range
117}
118
119fn is_identifier(bytes: &[u8]) -> bool {
120 bytes.iter().all(|x| is_identifier_byte(*x))
121}
122
123pub fn is_variable(bytes: &[u8]) -> bool {
124 if bytes.len() > 1 && bytes[0] == b'$' {
125 is_identifier(&bytes[1..])
126 } else {
127 is_identifier(bytes)
128 }
129}
130
131pub fn trim_quotes(bytes: &[u8]) -> &[u8] {
132 if (bytes.starts_with(b"\"") && bytes.ends_with(b"\"") && bytes.len() > 1)
133 || (bytes.starts_with(b"\'") && bytes.ends_with(b"\'") && bytes.len() > 1)
134 || (bytes.starts_with(b"`") && bytes.ends_with(b"`") && bytes.len() > 1)
135 {
136 &bytes[1..(bytes.len() - 1)]
137 } else {
138 bytes
139 }
140}
141
142pub fn trim_quotes_str(s: &str) -> &str {
143 if (s.starts_with('"') && s.ends_with('"') && s.len() > 1)
144 || (s.starts_with('\'') && s.ends_with('\'') && s.len() > 1)
145 || (s.starts_with('`') && s.ends_with('`') && s.len() > 1)
146 {
147 &s[1..(s.len() - 1)]
148 } else {
149 s
150 }
151}
152
153pub(crate) fn check_call(
154 working_set: &mut StateWorkingSet,
155 command: Span,
156 sig: &Signature,
157 call: &Call,
158) {
159 if call.named_iter().any(|(n, _, _)| n.item == "help") {
161 return;
162 }
163
164 if call.positional_len() < sig.required_positional.len() {
165 for argument in &sig.required_positional {
169 let found = call.positional_iter().fold(false, |ac, expr| {
170 if argument.shape.to_type() == expr.ty || argument.shape == SyntaxShape::Any {
171 true
172 } else {
173 ac
174 }
175 });
176 if !found {
177 if let Some(last) = call.positional_iter().last() {
178 working_set.error(ParseError::MissingPositional(
179 argument.name.clone(),
180 Span::new(last.span.end, last.span.end),
181 sig.call_signature(),
182 ));
183 return;
184 } else {
185 working_set.error(ParseError::MissingPositional(
186 argument.name.clone(),
187 Span::new(command.end, command.end),
188 sig.call_signature(),
189 ));
190 return;
191 }
192 }
193 }
194
195 let missing = &sig.required_positional[call.positional_len()];
196 if let Some(last) = call.positional_iter().last() {
197 working_set.error(ParseError::MissingPositional(
198 missing.name.clone(),
199 Span::new(last.span.end, last.span.end),
200 sig.call_signature(),
201 ))
202 } else {
203 working_set.error(ParseError::MissingPositional(
204 missing.name.clone(),
205 Span::new(command.end, command.end),
206 sig.call_signature(),
207 ))
208 }
209 } else {
210 for req_flag in sig.named.iter().filter(|x| x.required) {
211 if call.named_iter().all(|(n, _, _)| n.item != req_flag.long) {
212 working_set.error(ParseError::MissingRequiredFlag(
213 req_flag.long.clone(),
214 command,
215 ));
216 }
217 }
218 }
219}
220
221fn parse_unknown_arg(
224 working_set: &mut StateWorkingSet,
225 span: Span,
226 signature: &Signature,
227) -> Expression {
228 let shape = signature
229 .rest_positional
230 .as_ref()
231 .map(|arg| arg.shape.clone())
232 .unwrap_or(SyntaxShape::Any);
233
234 parse_value(working_set, span, &shape)
235}
236
237fn parse_external_string(working_set: &mut StateWorkingSet, span: Span) -> Expression {
247 let contents = working_set.get_span_contents(span);
248
249 if contents.starts_with(b"r#") {
250 parse_raw_string(working_set, span)
251 } else if contents
252 .iter()
253 .any(|b| matches!(b, b'"' | b'\'' | b'(' | b')' | b'`'))
254 {
255 enum State {
256 Bare {
257 from: usize,
258 },
259 BackTickQuote {
260 from: usize,
261 },
262 Quote {
263 from: usize,
264 quote_char: u8,
265 escaped: bool,
266 },
267 }
268 let make_span = |from: usize, index: usize| Span {
274 start: span.start + from,
275 end: span.start + index,
276 };
277 let mut spans = vec![];
278 let mut state = State::Bare { from: 0 };
279 let mut index = 0;
280 while index < contents.len() {
281 let ch = contents[index];
282 match &mut state {
283 State::Bare { from } => match ch {
284 b'"' | b'\'' => {
285 if index != *from {
287 spans.push(make_span(*from, index));
288 }
289 state = State::Quote {
291 from: index,
292 quote_char: ch,
293 escaped: false,
294 };
295 }
296 b'$' => {
297 if let Some("e_char @ (b'"' | b'\'')) = contents.get(index + 1) {
298 if index != *from {
300 spans.push(make_span(*from, index));
301 }
302 state = State::Quote {
303 from: index,
304 quote_char,
305 escaped: false,
306 };
307 index += 2;
309 continue;
310 }
311 }
312 b'`' => {
313 if index != *from {
314 spans.push(make_span(*from, index))
315 }
316 state = State::BackTickQuote { from: index }
317 }
318 _ => (),
320 },
321 State::Quote {
322 from,
323 quote_char,
324 escaped,
325 } => match ch {
326 ch if ch == *quote_char && !*escaped => {
327 spans.push(make_span(*from, index + 1));
329 state = State::Bare { from: index + 1 };
331 }
332 b'\\' if !*escaped && *quote_char == b'"' => {
333 *escaped = true;
335 }
336 _ => {
337 *escaped = false;
338 }
339 },
340 State::BackTickQuote { from } => {
341 if ch == b'`' {
342 spans.push(make_span(*from, index + 1));
343 state = State::Bare { from: index + 1 };
344 }
345 }
346 }
347 index += 1;
348 }
349
350 match state {
352 State::Bare { from }
353 | State::Quote { from, .. }
354 | State::BackTickQuote { from, .. } => {
355 if from < contents.len() {
356 spans.push(make_span(from, contents.len()));
357 }
358 }
359 }
360
361 if log::log_enabled!(log::Level::Trace) {
363 let contents = spans
364 .iter()
365 .map(|span| String::from_utf8_lossy(working_set.get_span_contents(*span)))
366 .collect::<Vec<_>>();
367
368 trace!("parsing: external string, parts: {contents:?}")
369 }
370
371 let quoted =
373 (contents.len() >= 3 && contents.starts_with(b"$\"") && contents.ends_with(b"\""))
374 || is_quoted(contents);
375
376 let exprs: Vec<Expression> = spans
378 .into_iter()
379 .map(|span| parse_string(working_set, span))
380 .collect();
381
382 if exprs
383 .iter()
384 .all(|expr| matches!(expr.expr, Expr::String(..)))
385 {
386 let string = exprs
388 .into_iter()
389 .map(|expr| {
390 let Expr::String(contents) = expr.expr else {
391 unreachable!("already checked that this was a String")
392 };
393 contents
394 })
395 .collect::<String>();
396 if quoted {
397 Expression::new(working_set, Expr::String(string), span, Type::String)
398 } else {
399 Expression::new(
400 working_set,
401 Expr::GlobPattern(string, false),
402 span,
403 Type::Glob,
404 )
405 }
406 } else {
407 let exprs = exprs
409 .into_iter()
410 .flat_map(|expr| match expr.expr {
411 Expr::StringInterpolation(subexprs) => subexprs,
412 _ => vec![expr],
413 })
414 .collect();
415 if quoted {
418 Expression::new(
419 working_set,
420 Expr::StringInterpolation(exprs),
421 span,
422 Type::String,
423 )
424 } else {
425 Expression::new(
426 working_set,
427 Expr::GlobInterpolation(exprs, false),
428 span,
429 Type::Glob,
430 )
431 }
432 }
433 } else {
434 parse_glob_pattern(working_set, span)
435 }
436}
437
438fn parse_external_arg(working_set: &mut StateWorkingSet, span: Span) -> ExternalArgument {
439 let contents = working_set.get_span_contents(span);
440
441 if contents.len() > 3
442 && contents.starts_with(b"...")
443 && (contents[3] == b'$' || contents[3] == b'[' || contents[3] == b'(')
444 {
445 ExternalArgument::Spread(parse_value(
446 working_set,
447 Span::new(span.start + 3, span.end),
448 &SyntaxShape::List(Box::new(SyntaxShape::Any)),
449 ))
450 } else {
451 ExternalArgument::Regular(parse_regular_external_arg(working_set, span))
452 }
453}
454
455fn parse_regular_external_arg(working_set: &mut StateWorkingSet, span: Span) -> Expression {
456 let contents = working_set.get_span_contents(span);
457
458 if contents.starts_with(b"$") || contents.starts_with(b"(") {
459 parse_dollar_expr(working_set, span)
460 } else if contents.starts_with(b"[") {
461 parse_list_expression(working_set, span, &SyntaxShape::Any)
462 } else {
463 parse_external_string(working_set, span)
464 }
465}
466
467pub fn parse_external_call(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
468 trace!("parse external");
469
470 let head_contents = working_set.get_span_contents(spans[0]);
471
472 let head_span = if head_contents.starts_with(b"^") {
473 Span::new(spans[0].start + 1, spans[0].end)
474 } else {
475 spans[0]
476 };
477
478 let head_contents = working_set.get_span_contents(head_span).to_vec();
479
480 let head = if head_contents.starts_with(b"$") || head_contents.starts_with(b"(") {
481 let arg = parse_expression(working_set, &[head_span]);
483 Box::new(arg)
484 } else {
485 Box::new(parse_external_string(working_set, head_span))
486 };
487
488 let args = spans[1..]
489 .iter()
490 .map(|&span| parse_external_arg(working_set, span))
491 .collect();
492
493 Expression::new(
494 working_set,
495 Expr::ExternalCall(head, args),
496 Span::concat(spans),
497 Type::Any,
498 )
499}
500
501fn ensure_flag_arg_type(
502 working_set: &mut StateWorkingSet,
503 arg_name: String,
504 arg: Expression,
505 arg_shape: &SyntaxShape,
506 long_name_span: Span,
507) -> (Spanned<String>, Expression) {
508 if !type_compatible(&arg.ty, &arg_shape.to_type()) {
509 working_set.error(ParseError::TypeMismatch(
510 arg_shape.to_type(),
511 arg.ty,
512 arg.span,
513 ));
514 (
515 Spanned {
516 item: arg_name,
517 span: long_name_span,
518 },
519 Expression::garbage(working_set, arg.span),
520 )
521 } else {
522 (
523 Spanned {
524 item: arg_name,
525 span: long_name_span,
526 },
527 arg,
528 )
529 }
530}
531
532fn parse_long_flag(
533 working_set: &mut StateWorkingSet,
534 spans: &[Span],
535 spans_idx: &mut usize,
536 sig: &Signature,
537) -> (Option<Spanned<String>>, Option<Expression>) {
538 let arg_span = spans[*spans_idx];
539 let arg_contents = working_set.get_span_contents(arg_span);
540
541 if arg_contents.starts_with(b"--") {
542 let split: Vec<_> = arg_contents.split(|x| *x == b'=').collect();
544 let long_name = String::from_utf8(split[0].into());
545 if let Ok(long_name) = long_name {
546 let long_name = long_name[2..].to_string();
547 if let Some(flag) = sig.get_long_flag(&long_name) {
548 if let Some(arg_shape) = &flag.arg {
549 if split.len() > 1 {
550 let long_name_len = long_name.len();
552 let mut span = arg_span;
553 span.start += long_name_len + 3; let arg = parse_value(working_set, span, arg_shape);
556 let (arg_name, val_expression) = ensure_flag_arg_type(
557 working_set,
558 long_name,
559 arg,
560 arg_shape,
561 Span::new(arg_span.start, arg_span.start + long_name_len + 2),
562 );
563 (Some(arg_name), Some(val_expression))
564 } else if let Some(arg) = spans.get(*spans_idx + 1) {
565 let arg = parse_value(working_set, *arg, arg_shape);
566
567 *spans_idx += 1;
568 let (arg_name, val_expression) =
569 ensure_flag_arg_type(working_set, long_name, arg, arg_shape, arg_span);
570 (Some(arg_name), Some(val_expression))
571 } else {
572 working_set.error(ParseError::MissingFlagParam(
573 arg_shape.to_string(),
574 arg_span,
575 ));
576 (
577 Some(Spanned {
578 item: long_name,
579 span: arg_span,
580 }),
581 None,
582 )
583 }
584 } else {
585 if split.len() > 1 {
588 let long_name_len = long_name.len();
590 let mut span = arg_span;
591 span.start += long_name_len + 3; let arg = parse_value(working_set, span, &SyntaxShape::Boolean);
594
595 let (arg_name, val_expression) = ensure_flag_arg_type(
596 working_set,
597 long_name,
598 arg,
599 &SyntaxShape::Boolean,
600 Span::new(arg_span.start, arg_span.start + long_name_len + 2),
601 );
602 (Some(arg_name), Some(val_expression))
603 } else {
604 (
605 Some(Spanned {
606 item: long_name,
607 span: arg_span,
608 }),
609 None,
610 )
611 }
612 }
613 } else {
614 working_set.error(ParseError::UnknownFlag(
615 sig.name.clone(),
616 long_name.clone(),
617 arg_span,
618 sig.clone().formatted_flags(),
619 ));
620 (
621 Some(Spanned {
622 item: long_name.clone(),
623 span: arg_span,
624 }),
625 None,
626 )
627 }
628 } else {
629 working_set.error(ParseError::NonUtf8(arg_span));
630 (
631 Some(Spanned {
632 item: "--".into(),
633 span: arg_span,
634 }),
635 None,
636 )
637 }
638 } else {
639 (None, None)
640 }
641}
642
643fn parse_short_flags(
644 working_set: &mut StateWorkingSet,
645 spans: &[Span],
646 spans_idx: &mut usize,
647 positional_idx: usize,
648 sig: &Signature,
649) -> Option<Vec<Flag>> {
650 let arg_span = spans[*spans_idx];
651
652 let arg_contents = working_set.get_span_contents(arg_span);
653
654 if let Ok(arg_contents_uft8_ref) = str::from_utf8(arg_contents) {
655 if arg_contents_uft8_ref.starts_with('-') && arg_contents_uft8_ref.len() > 1 {
656 let short_flags = &arg_contents_uft8_ref[1..];
657 let num_chars = short_flags.chars().count();
658 let mut found_short_flags = vec![];
659 let mut unmatched_short_flags = vec![];
660 for (offset, short_flag) in short_flags.char_indices() {
661 let short_flag_span = Span::new(
662 arg_span.start + 1 + offset,
663 arg_span.start + 1 + offset + short_flag.len_utf8(),
664 );
665 if let Some(flag) = sig.get_short_flag(short_flag) {
666 if flag.arg.is_some() && offset < num_chars - 1 {
668 working_set
669 .error(ParseError::OnlyLastFlagInBatchCanTakeArg(short_flag_span));
670 break;
671 }
672 found_short_flags.push(flag);
673 } else {
674 unmatched_short_flags.push(short_flag_span);
675 }
676 }
677
678 if found_short_flags.is_empty()
679 && matches!(
681 sig.get_positional(positional_idx),
682 Some(PositionalArg {
683 shape: SyntaxShape::Int | SyntaxShape::Number | SyntaxShape::Float,
684 ..
685 })
686 )
687 && String::from_utf8_lossy(working_set.get_span_contents(arg_span))
688 .parse::<f64>()
689 .is_ok()
690 {
691 return None;
692 } else if let Some(first) = unmatched_short_flags.first() {
693 let contents = working_set.get_span_contents(*first);
694 working_set.error(ParseError::UnknownFlag(
695 sig.name.clone(),
696 format!("-{}", String::from_utf8_lossy(contents)),
697 *first,
698 sig.clone().formatted_flags(),
699 ));
700 }
701
702 Some(found_short_flags)
703 } else {
704 None
705 }
706 } else {
707 working_set.error(ParseError::NonUtf8(arg_span));
708 None
709 }
710}
711
712fn first_kw_idx(
713 working_set: &StateWorkingSet,
714 signature: &Signature,
715 spans: &[Span],
716 spans_idx: usize,
717 positional_idx: usize,
718) -> (Option<usize>, usize) {
719 for idx in (positional_idx + 1)..signature.num_positionals() {
720 if let Some(PositionalArg {
721 shape: SyntaxShape::Keyword(kw, ..),
722 ..
723 }) = signature.get_positional(idx)
724 {
725 for (span_idx, &span) in spans.iter().enumerate().skip(spans_idx) {
726 let contents = working_set.get_span_contents(span);
727
728 if contents == kw {
729 return (Some(idx), span_idx);
730 }
731 }
732 }
733 }
734 (None, spans.len())
735}
736
737fn calculate_end_span(
738 working_set: &StateWorkingSet,
739 signature: &Signature,
740 spans: &[Span],
741 spans_idx: usize,
742 positional_idx: usize,
743) -> usize {
744 if signature.rest_positional.is_some() {
745 spans.len()
746 } else {
747 let (kw_pos, kw_idx) =
748 first_kw_idx(working_set, signature, spans, spans_idx, positional_idx);
749
750 if let Some(kw_pos) = kw_pos {
751 let positionals_between = kw_pos - positional_idx - 1;
756 if positionals_between >= (kw_idx - spans_idx) {
757 kw_idx
758 } else {
759 kw_idx - positionals_between
760 }
761 } else {
762 let remaining_spans = spans.len() - (spans_idx + 1);
765 let remaining_positional = signature
767 .required_positional
768 .len()
769 .saturating_sub(positional_idx + 1);
770 let extra_spans = remaining_spans.saturating_sub(remaining_positional);
772 spans_idx + 1 + extra_spans
773 }
774 }
775}
776
777fn parse_oneof(
778 working_set: &mut StateWorkingSet,
779 spans: &[Span],
780 spans_idx: &mut usize,
781 possible_shapes: &Vec<SyntaxShape>,
782 multispan: bool,
783) -> Expression {
784 let starting_spans_idx = *spans_idx;
785 let mut best_guess = None;
786 let mut best_guess_errors = Vec::new();
787 let mut max_first_error_offset = 0;
788 let mut propagate_error = false;
789 for shape in possible_shapes {
790 let starting_error_count = working_set.parse_errors.len();
791 *spans_idx = starting_spans_idx;
792 let value = match multispan {
793 true => parse_multispan_value(working_set, spans, spans_idx, shape),
794 false => parse_value(working_set, spans[*spans_idx], shape),
795 };
796
797 let new_errors = working_set.parse_errors[starting_error_count..].to_vec();
798 let Some(first_error_offset) = new_errors.iter().map(|e| e.span().start).min() else {
800 return value;
801 };
802
803 if first_error_offset > max_first_error_offset {
804 propagate_error = match working_set.parse_errors.last() {
807 Some(ParseError::Expected(_, error_span))
808 | Some(ParseError::ExpectedWithStringMsg(_, error_span)) => {
809 matches!(
810 shape,
811 SyntaxShape::Block | SyntaxShape::Closure(_) | SyntaxShape::Expression
812 ) && *error_span != spans[*spans_idx]
813 }
814 _ => true,
815 };
816 max_first_error_offset = first_error_offset;
817 best_guess = Some(value);
818 best_guess_errors = new_errors;
819 }
820 working_set.parse_errors.truncate(starting_error_count);
821 }
822
823 if max_first_error_offset > spans[starting_spans_idx].start || propagate_error {
826 working_set.parse_errors.extend(best_guess_errors);
827 best_guess.expect("best_guess should not be None here!")
828 } else {
829 working_set.error(ParseError::ExpectedWithStringMsg(
830 format!("one of a list of accepted shapes: {possible_shapes:?}"),
831 spans[starting_spans_idx],
832 ));
833 Expression::garbage(working_set, spans[starting_spans_idx])
834 }
835}
836
837pub fn parse_multispan_value(
838 working_set: &mut StateWorkingSet,
839 spans: &[Span],
840 spans_idx: &mut usize,
841 shape: &SyntaxShape,
842) -> Expression {
843 trace!("parse multispan value");
844 match shape {
845 SyntaxShape::VarWithOptType => {
846 trace!("parsing: var with opt type");
847
848 parse_var_with_opt_type(working_set, spans, spans_idx, false).0
849 }
850 SyntaxShape::RowCondition => {
851 trace!("parsing: row condition");
852 let arg = parse_row_condition(working_set, &spans[*spans_idx..]);
853 *spans_idx = spans.len() - 1;
854
855 arg
856 }
857 SyntaxShape::MathExpression => {
858 trace!("parsing: math expression");
859
860 let arg = parse_math_expression(working_set, &spans[*spans_idx..], None);
861 *spans_idx = spans.len() - 1;
862
863 arg
864 }
865 SyntaxShape::OneOf(possible_shapes) => {
866 parse_oneof(working_set, spans, spans_idx, possible_shapes, true)
867 }
868
869 SyntaxShape::Expression => {
870 trace!("parsing: expression");
871
872 let arg = parse_expression(working_set, &spans[*spans_idx..]);
875 *spans_idx = spans.len() - 1;
876
877 arg
878 }
879 SyntaxShape::Signature => {
880 trace!("parsing: signature");
881
882 let sig = parse_full_signature(working_set, &spans[*spans_idx..]);
883 *spans_idx = spans.len() - 1;
884
885 sig
886 }
887 SyntaxShape::Keyword(keyword, arg) => {
888 trace!(
889 "parsing: keyword({}) {:?}",
890 String::from_utf8_lossy(keyword),
891 arg
892 );
893 let arg_span = spans[*spans_idx];
894
895 let arg_contents = working_set.get_span_contents(arg_span);
896
897 if arg_contents != keyword {
898 working_set.error(ParseError::ExpectedKeyword(
903 String::from_utf8_lossy(keyword).into(),
904 arg_span,
905 ))
906 }
907
908 *spans_idx += 1;
909 if *spans_idx >= spans.len() {
910 working_set.error(ParseError::KeywordMissingArgument(
911 arg.to_string(),
912 String::from_utf8_lossy(keyword).into(),
913 Span::new(spans[*spans_idx - 1].end, spans[*spans_idx - 1].end),
914 ));
915 let keyword = Keyword {
916 keyword: keyword.as_slice().into(),
917 span: spans[*spans_idx - 1],
918 expr: Expression::garbage(working_set, arg_span),
919 };
920 return Expression::new(
921 working_set,
922 Expr::Keyword(Box::new(keyword)),
923 arg_span,
924 Type::Any,
925 );
926 }
927
928 let keyword = Keyword {
929 keyword: keyword.as_slice().into(),
930 span: spans[*spans_idx - 1],
931 expr: parse_multispan_value(working_set, spans, spans_idx, arg),
932 };
933
934 Expression::new(
935 working_set,
936 Expr::Keyword(Box::new(keyword.clone())),
937 keyword.span.merge(keyword.expr.span),
938 keyword.expr.ty,
939 )
940 }
941 _ => {
942 let arg_span = spans[*spans_idx];
944
945 parse_value(working_set, arg_span, shape)
946 }
947 }
948}
949
950pub struct ParsedInternalCall {
951 pub call: Box<Call>,
952 pub output: Type,
953}
954
955pub fn parse_internal_call(
956 working_set: &mut StateWorkingSet,
957 command_span: Span,
958 spans: &[Span],
959 decl_id: DeclId,
960) -> ParsedInternalCall {
961 trace!("parsing: internal call (decl id: {})", decl_id.get());
962
963 let mut call = Call::new(command_span);
964 call.decl_id = decl_id;
965 call.head = command_span;
966 let _ = working_set.add_span(call.head);
967
968 let decl = working_set.get_decl(decl_id);
969 let signature = working_set.get_signature(decl);
970 let output = signature.get_output_type();
971
972 let lib_dirs_var_id = match decl.name() {
974 "use" | "overlay use" | "source-env" if decl.is_keyword() => {
975 find_dirs_var(working_set, LIB_DIRS_VAR)
976 }
977 "nu-check" if decl.is_builtin() => find_dirs_var(working_set, LIB_DIRS_VAR),
978 _ => None,
979 };
980
981 let mut positional_idx = 0;
983
984 let mut spans_idx = 0;
987
988 if let Some(alias) = decl.as_alias() {
989 if let Expression {
990 expr: Expr::Call(wrapped_call),
991 ..
992 } = &alias.wrapped_call
993 {
994 call = *wrapped_call.clone();
996 call.head = command_span;
997 positional_idx = call.positional_len();
999 } else {
1000 working_set.error(ParseError::UnknownState(
1001 "Alias does not point to internal call.".to_string(),
1002 command_span,
1003 ));
1004 return ParsedInternalCall {
1005 call: Box::new(call),
1006 output: Type::Any,
1007 };
1008 }
1009 }
1010
1011 if let Some(var_id) = lib_dirs_var_id {
1012 call.set_parser_info(
1013 DIR_VAR_PARSER_INFO.to_owned(),
1014 Expression::new(working_set, Expr::Var(var_id), call.head, Type::Any),
1015 );
1016 }
1017
1018 if signature.creates_scope {
1019 working_set.enter_scope();
1020 }
1021
1022 while spans_idx < spans.len() {
1023 let arg_span = spans[spans_idx];
1024
1025 let starting_error_count = working_set.parse_errors.len();
1026 let (long_name, arg) = parse_long_flag(working_set, spans, &mut spans_idx, &signature);
1028
1029 if let Some(long_name) = long_name {
1030 if working_set.parse_errors[starting_error_count..]
1032 .iter()
1033 .any(|x| matches!(x, ParseError::UnknownFlag(_, _, _, _)))
1034 && signature.allows_unknown_args
1035 {
1036 working_set.parse_errors.truncate(starting_error_count);
1037 let arg = parse_unknown_arg(working_set, arg_span, &signature);
1038
1039 call.add_unknown(arg);
1040 } else {
1041 call.add_named((long_name, None, arg));
1042 }
1043
1044 spans_idx += 1;
1045 continue;
1046 }
1047
1048 let starting_error_count = working_set.parse_errors.len();
1049
1050 let short_flags = parse_short_flags(
1052 working_set,
1053 spans,
1054 &mut spans_idx,
1055 positional_idx,
1056 &signature,
1057 );
1058
1059 if let Some(mut short_flags) = short_flags {
1060 if short_flags.is_empty() {
1061 short_flags.push(Flag {
1063 long: "".to_string(),
1064 short: Some('a'),
1065 arg: None,
1066 required: false,
1067 desc: "".to_string(),
1068 var_id: None,
1069 default_value: None,
1070 })
1071 }
1072
1073 if working_set.parse_errors[starting_error_count..]
1074 .iter()
1075 .any(|x| matches!(x, ParseError::UnknownFlag(_, _, _, _)))
1076 && signature.allows_unknown_args
1077 {
1078 working_set.parse_errors.truncate(starting_error_count);
1079 let arg = parse_unknown_arg(working_set, arg_span, &signature);
1080
1081 call.add_unknown(arg);
1082 } else {
1083 for flag in short_flags {
1084 let _ = working_set.add_span(spans[spans_idx]);
1085
1086 if let Some(arg_shape) = flag.arg {
1087 if let Some(arg) = spans.get(spans_idx + 1) {
1088 let arg = parse_value(working_set, *arg, &arg_shape);
1089 let (arg_name, val_expression) = ensure_flag_arg_type(
1090 working_set,
1091 flag.long.clone(),
1092 arg.clone(),
1093 &arg_shape,
1094 spans[spans_idx],
1095 );
1096
1097 if flag.long.is_empty() {
1098 if let Some(short) = flag.short {
1099 call.add_named((
1100 arg_name,
1101 Some(Spanned {
1102 item: short.to_string(),
1103 span: spans[spans_idx],
1104 }),
1105 Some(val_expression),
1106 ));
1107 }
1108 } else {
1109 call.add_named((arg_name, None, Some(val_expression)));
1110 }
1111 spans_idx += 1;
1112 } else {
1113 working_set.error(ParseError::MissingFlagParam(
1114 arg_shape.to_string(),
1115 arg_span,
1116 ))
1117 }
1118 } else if flag.long.is_empty() {
1119 if let Some(short) = flag.short {
1120 call.add_named((
1121 Spanned {
1122 item: String::new(),
1123 span: spans[spans_idx],
1124 },
1125 Some(Spanned {
1126 item: short.to_string(),
1127 span: spans[spans_idx],
1128 }),
1129 None,
1130 ));
1131 }
1132 } else {
1133 call.add_named((
1134 Spanned {
1135 item: flag.long.clone(),
1136 span: spans[spans_idx],
1137 },
1138 None,
1139 None,
1140 ));
1141 }
1142 }
1143 }
1144
1145 spans_idx += 1;
1146 continue;
1147 }
1148
1149 {
1150 let contents = working_set.get_span_contents(spans[spans_idx]);
1151
1152 if contents.len() > 3
1153 && contents.starts_with(b"...")
1154 && (contents[3] == b'$' || contents[3] == b'[' || contents[3] == b'(')
1155 {
1156 if signature.rest_positional.is_none() && !signature.allows_unknown_args {
1157 working_set.error(ParseError::UnexpectedSpreadArg(
1158 signature.call_signature(),
1159 arg_span,
1160 ));
1161 call.add_positional(Expression::garbage(working_set, arg_span));
1162 } else if positional_idx < signature.required_positional.len() {
1163 working_set.error(ParseError::MissingPositional(
1164 signature.required_positional[positional_idx].name.clone(),
1165 Span::new(spans[spans_idx].start, spans[spans_idx].start),
1166 signature.call_signature(),
1167 ));
1168 call.add_positional(Expression::garbage(working_set, arg_span));
1169 } else {
1170 let rest_shape = match &signature.rest_positional {
1171 Some(arg) if matches!(arg.shape, SyntaxShape::ExternalArgument) => {
1172 SyntaxShape::Any
1174 }
1175 Some(arg) => arg.shape.clone(),
1176 None => SyntaxShape::Any,
1177 };
1178 let args = parse_value(
1180 working_set,
1181 Span::new(arg_span.start + 3, arg_span.end),
1182 &SyntaxShape::List(Box::new(rest_shape)),
1183 );
1184
1185 call.add_spread(args);
1186 positional_idx =
1188 signature.required_positional.len() + signature.optional_positional.len();
1189 }
1190
1191 spans_idx += 1;
1192 continue;
1193 }
1194 }
1195
1196 if let Some(positional) = signature.get_positional(positional_idx) {
1198 let end = calculate_end_span(working_set, &signature, spans, spans_idx, positional_idx);
1199
1200 if end == spans_idx {
1202 let prev_span = if spans_idx == 0 {
1203 command_span
1204 } else {
1205 spans[spans_idx - 1]
1206 };
1207 let whitespace_span = Span::new(prev_span.end, spans[spans_idx].start);
1208 working_set.error(ParseError::MissingPositional(
1209 positional.name.clone(),
1210 whitespace_span,
1211 signature.call_signature(),
1212 ));
1213 call.add_positional(Expression::garbage(working_set, whitespace_span));
1214 positional_idx += 1;
1215 continue;
1216 }
1217 debug_assert!(end <= spans.len());
1218
1219 if spans[..end].is_empty() || spans_idx == end {
1220 working_set.error(ParseError::MissingPositional(
1221 positional.name.clone(),
1222 Span::new(spans[spans_idx].end, spans[spans_idx].end),
1223 signature.call_signature(),
1224 ));
1225 positional_idx += 1;
1226 continue;
1227 }
1228
1229 let arg = parse_multispan_value(
1230 working_set,
1231 &spans[..end],
1232 &mut spans_idx,
1233 &positional.shape,
1234 );
1235
1236 let arg = if !type_compatible(&positional.shape.to_type(), &arg.ty) {
1237 working_set.error(ParseError::TypeMismatch(
1238 positional.shape.to_type(),
1239 arg.ty,
1240 arg.span,
1241 ));
1242 Expression::garbage(working_set, arg.span)
1243 } else {
1244 arg
1245 };
1246 call.add_positional(arg);
1247 positional_idx += 1;
1248 } else if signature.allows_unknown_args {
1249 let arg = parse_unknown_arg(working_set, arg_span, &signature);
1250
1251 call.add_unknown(arg);
1252 } else {
1253 call.add_positional(Expression::garbage(working_set, arg_span));
1254 working_set.error(ParseError::ExtraPositional(
1255 signature.call_signature(),
1256 arg_span,
1257 ))
1258 }
1259
1260 spans_idx += 1;
1261 }
1262
1263 check_call(working_set, command_span, &signature, &call);
1264
1265 if signature.creates_scope {
1266 working_set.exit_scope();
1267 }
1268
1269 ParsedInternalCall {
1270 call: Box::new(call),
1271 output,
1272 }
1273}
1274
1275pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span) -> Expression {
1276 trace!("parsing: call");
1277
1278 if spans.is_empty() {
1279 working_set.error(ParseError::UnknownState(
1280 "Encountered command with zero spans".into(),
1281 Span::concat(spans),
1282 ));
1283 return garbage(working_set, head);
1284 }
1285
1286 let (cmd_start, pos, _name, maybe_decl_id) = find_longest_decl(working_set, spans);
1287
1288 if let Some(decl_id) = maybe_decl_id {
1289 if spans.len() > 1 {
1292 let test_equal = working_set.get_span_contents(spans[1]);
1293
1294 if test_equal == [b'='] {
1295 trace!("incomplete statement");
1296
1297 working_set.error(ParseError::UnknownState(
1298 "Incomplete statement".into(),
1299 Span::concat(spans),
1300 ));
1301 return garbage(working_set, Span::concat(spans));
1302 }
1303 }
1304
1305 let decl = working_set.get_decl(decl_id);
1307
1308 let parsed_call = if let Some(alias) = decl.as_alias() {
1309 if let Expression {
1310 expr: Expr::ExternalCall(head, args),
1311 span: _,
1312 span_id: _,
1313 ty,
1314 custom_completion,
1315 } = &alias.clone().wrapped_call
1316 {
1317 trace!("parsing: alias of external call");
1318
1319 let mut head = head.clone();
1320 head.span = Span::concat(&spans[cmd_start..pos]); let mut final_args = args.clone().into_vec();
1323 for arg_span in &spans[pos..] {
1324 let arg = parse_external_arg(working_set, *arg_span);
1325 final_args.push(arg);
1326 }
1327
1328 let mut expression = Expression::new(
1329 working_set,
1330 Expr::ExternalCall(head, final_args.into()),
1331 Span::concat(spans),
1332 ty.clone(),
1333 );
1334
1335 expression.custom_completion = *custom_completion;
1336 return expression;
1337 } else {
1338 trace!("parsing: alias of internal call");
1339 parse_internal_call(
1340 working_set,
1341 Span::concat(&spans[cmd_start..pos]),
1342 &spans[pos..],
1343 decl_id,
1344 )
1345 }
1346 } else {
1347 trace!("parsing: internal call");
1348 parse_internal_call(
1349 working_set,
1350 Span::concat(&spans[cmd_start..pos]),
1351 &spans[pos..],
1352 decl_id,
1353 )
1354 };
1355
1356 Expression::new(
1357 working_set,
1358 Expr::Call(parsed_call.call),
1359 Span::concat(spans),
1360 parsed_call.output,
1361 )
1362 } else {
1363 let bytes = working_set.get_span_contents(spans[0]);
1365 trace!("parsing: range {:?} ", bytes);
1366 if let (Some(b'.'), Some(b'.')) = (bytes.first(), bytes.get(1)) {
1367 trace!("-- found leading range indicator");
1368 let starting_error_count = working_set.parse_errors.len();
1369
1370 if let Some(range_expr) = parse_range(working_set, spans[0]) {
1371 trace!("-- successfully parsed range");
1372 return range_expr;
1373 }
1374 working_set.parse_errors.truncate(starting_error_count);
1375 }
1376 trace!("parsing: external call");
1377
1378 parse_external_call(working_set, spans)
1380 }
1381}
1382
1383pub fn find_longest_decl(
1384 working_set: &mut StateWorkingSet<'_>,
1385 spans: &[Span],
1386) -> (
1387 usize,
1388 usize,
1389 Vec<u8>,
1390 Option<nu_protocol::Id<nu_protocol::marker::Decl>>,
1391) {
1392 find_longest_decl_with_prefix(working_set, spans, b"")
1393}
1394
1395pub fn find_longest_decl_with_prefix(
1396 working_set: &mut StateWorkingSet<'_>,
1397 spans: &[Span],
1398 prefix: &[u8],
1399) -> (
1400 usize,
1401 usize,
1402 Vec<u8>,
1403 Option<nu_protocol::Id<nu_protocol::marker::Decl>>,
1404) {
1405 let mut pos = 0;
1406 let cmd_start = pos;
1407 let mut name_spans = vec![];
1408 let mut name = vec![];
1409 name.extend(prefix);
1410
1411 for word_span in spans[cmd_start..].iter() {
1412 name_spans.push(*word_span);
1415
1416 let name_part = working_set.get_span_contents(*word_span);
1417 if name.is_empty() {
1418 name.extend(name_part);
1419 } else {
1420 name.push(b' ');
1421 name.extend(name_part);
1422 }
1423
1424 pos += 1;
1425 }
1426
1427 let mut maybe_decl_id = working_set.find_decl(&name);
1428
1429 while maybe_decl_id.is_none() {
1430 if name_spans.len() <= 1 {
1432 break;
1434 }
1435
1436 name_spans.pop();
1437 pos -= 1;
1438
1439 name.clear();
1441 name.extend(prefix);
1442 for name_span in &name_spans {
1443 let name_part = working_set.get_span_contents(*name_span);
1444 if name.is_empty() {
1445 name.extend(name_part);
1446 } else {
1447 name.push(b' ');
1448 name.extend(name_part);
1449 }
1450 }
1451 maybe_decl_id = working_set.find_decl(&name);
1452 }
1453 (cmd_start, pos, name, maybe_decl_id)
1454}
1455
1456pub fn parse_attribute(
1457 working_set: &mut StateWorkingSet,
1458 lite_command: &LiteCommand,
1459) -> (Attribute, Option<String>) {
1460 let _ = lite_command
1461 .parts
1462 .first()
1463 .filter(|s| working_set.get_span_contents(**s).starts_with(b"@"))
1464 .expect("Attributes always start with an `@`");
1465
1466 assert!(
1467 lite_command.attribute_idx.is_empty(),
1468 "attributes can't have attributes"
1469 );
1470
1471 let mut spans = lite_command.parts.clone();
1472 if let Some(first) = spans.first_mut() {
1473 first.start += 1;
1474 }
1475 let spans = spans.as_slice();
1476 let attr_span = Span::concat(spans);
1477
1478 let (cmd_start, cmd_end, mut name, decl_id) =
1479 find_longest_decl_with_prefix(working_set, spans, b"attr");
1480
1481 debug_assert!(name.starts_with(b"attr "));
1482 let _ = name.drain(..(b"attr ".len()));
1483
1484 let name_span = Span::concat(&spans[cmd_start..cmd_end]);
1485
1486 let Ok(name) = String::from_utf8(name) else {
1487 working_set.error(ParseError::NonUtf8(name_span));
1488 return (
1489 Attribute {
1490 expr: garbage(working_set, attr_span),
1491 },
1492 None,
1493 );
1494 };
1495
1496 let Some(decl_id) = decl_id else {
1497 working_set.error(ParseError::UnknownCommand(name_span));
1498 return (
1499 Attribute {
1500 expr: garbage(working_set, attr_span),
1501 },
1502 None,
1503 );
1504 };
1505
1506 let decl = working_set.get_decl(decl_id);
1507
1508 let parsed_call = match decl.as_alias() {
1509 Some(alias) => match &alias.clone().wrapped_call {
1512 Expression {
1513 expr: Expr::ExternalCall(..),
1514 ..
1515 } => {
1516 let shell_error = ShellError::NotAConstCommand { span: name_span };
1517 working_set.error(shell_error.wrap(working_set, attr_span));
1518 return (
1519 Attribute {
1520 expr: garbage(working_set, Span::concat(spans)),
1521 },
1522 None,
1523 );
1524 }
1525 _ => {
1526 trace!("parsing: alias of internal call");
1527 parse_internal_call(working_set, name_span, &spans[cmd_end..], decl_id)
1528 }
1529 },
1530 None => {
1531 trace!("parsing: internal call");
1532 parse_internal_call(working_set, name_span, &spans[cmd_end..], decl_id)
1533 }
1534 };
1535
1536 (
1537 Attribute {
1538 expr: Expression::new(
1539 working_set,
1540 Expr::Call(parsed_call.call),
1541 Span::concat(spans),
1542 parsed_call.output,
1543 ),
1544 },
1545 Some(name),
1546 )
1547}
1548
1549pub fn parse_binary(working_set: &mut StateWorkingSet, span: Span) -> Expression {
1550 trace!("parsing: binary");
1551 let contents = working_set.get_span_contents(span);
1552 if contents.starts_with(b"0x[") {
1553 parse_binary_with_base(working_set, span, 16, 2, b"0x[", b"]")
1554 } else if contents.starts_with(b"0o[") {
1555 parse_binary_with_base(working_set, span, 8, 3, b"0o[", b"]")
1556 } else if contents.starts_with(b"0b[") {
1557 parse_binary_with_base(working_set, span, 2, 8, b"0b[", b"]")
1558 } else {
1559 working_set.error(ParseError::Expected("binary", span));
1560 garbage(working_set, span)
1561 }
1562}
1563
1564fn parse_binary_with_base(
1565 working_set: &mut StateWorkingSet,
1566 span: Span,
1567 base: u32,
1568 min_digits_per_byte: usize,
1569 prefix: &[u8],
1570 suffix: &[u8],
1571) -> Expression {
1572 let token = working_set.get_span_contents(span);
1573
1574 if let Some(token) = token.strip_prefix(prefix) {
1575 if let Some(token) = token.strip_suffix(suffix) {
1576 let (lexed, err) = lex(
1577 token,
1578 span.start + prefix.len(),
1579 &[b',', b'\r', b'\n'],
1580 &[],
1581 true,
1582 );
1583 if let Some(err) = err {
1584 working_set.error(err);
1585 }
1586
1587 let mut binary_value = vec![];
1588 for token in lexed {
1589 match token.contents {
1590 TokenContents::Item => {
1591 let contents = working_set.get_span_contents(token.span);
1592
1593 binary_value.extend_from_slice(contents);
1594 }
1595 TokenContents::Pipe
1596 | TokenContents::PipePipe
1597 | TokenContents::ErrGreaterPipe
1598 | TokenContents::OutGreaterThan
1599 | TokenContents::OutErrGreaterPipe
1600 | TokenContents::OutGreaterGreaterThan
1601 | TokenContents::ErrGreaterThan
1602 | TokenContents::ErrGreaterGreaterThan
1603 | TokenContents::OutErrGreaterThan
1604 | TokenContents::OutErrGreaterGreaterThan
1605 | TokenContents::AssignmentOperator => {
1606 working_set.error(ParseError::Expected("binary", span));
1607 return garbage(working_set, span);
1608 }
1609 TokenContents::Comment | TokenContents::Semicolon | TokenContents::Eol => {}
1610 }
1611 }
1612
1613 let required_padding = (min_digits_per_byte - binary_value.len() % min_digits_per_byte)
1614 % min_digits_per_byte;
1615
1616 if required_padding != 0 {
1617 binary_value = {
1618 let mut tail = binary_value;
1619 let mut binary_value: Vec<u8> = vec![b'0'; required_padding];
1620 binary_value.append(&mut tail);
1621 binary_value
1622 };
1623 }
1624
1625 let str = String::from_utf8_lossy(&binary_value).to_string();
1626
1627 match decode_with_base(&str, base, min_digits_per_byte) {
1628 Ok(v) => return Expression::new(working_set, Expr::Binary(v), span, Type::Binary),
1629 Err(x) => {
1630 working_set.error(ParseError::IncorrectValue(
1631 "not a binary value".into(),
1632 span,
1633 x.to_string(),
1634 ));
1635 return garbage(working_set, span);
1636 }
1637 }
1638 }
1639 }
1640
1641 working_set.error(ParseError::Expected("binary", span));
1642 garbage(working_set, span)
1643}
1644
1645fn decode_with_base(s: &str, base: u32, digits_per_byte: usize) -> Result<Vec<u8>, ParseIntError> {
1646 s.chars()
1647 .chunks(digits_per_byte)
1648 .into_iter()
1649 .map(|chunk| {
1650 let str: String = chunk.collect();
1651 u8::from_str_radix(&str, base)
1652 })
1653 .collect()
1654}
1655
1656fn strip_underscores(token: &[u8]) -> String {
1657 String::from_utf8_lossy(token)
1658 .chars()
1659 .filter(|c| *c != '_')
1660 .collect()
1661}
1662
1663pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression {
1664 let token = working_set.get_span_contents(span);
1665
1666 fn extract_int(
1667 working_set: &mut StateWorkingSet,
1668 token: &str,
1669 span: Span,
1670 radix: u32,
1671 ) -> Expression {
1672 if let Ok(num) = u64::from_str_radix(token, radix).map(|val| val as i64) {
1675 Expression::new(working_set, Expr::Int(num), span, Type::Int)
1676 } else {
1677 working_set.error(ParseError::InvalidLiteral(
1678 format!("invalid digits for radix {}", radix),
1679 "int".into(),
1680 span,
1681 ));
1682
1683 garbage(working_set, span)
1684 }
1685 }
1686
1687 let token = strip_underscores(token);
1688
1689 if token.is_empty() {
1690 working_set.error(ParseError::Expected("int", span));
1691 return garbage(working_set, span);
1692 }
1693
1694 if let Some(num) = token.strip_prefix("0b") {
1695 extract_int(working_set, num, span, 2)
1696 } else if let Some(num) = token.strip_prefix("0o") {
1697 extract_int(working_set, num, span, 8)
1698 } else if let Some(num) = token.strip_prefix("0x") {
1699 extract_int(working_set, num, span, 16)
1700 } else if let Ok(num) = token.parse::<i64>() {
1701 Expression::new(working_set, Expr::Int(num), span, Type::Int)
1702 } else {
1703 working_set.error(ParseError::Expected("int", span));
1704 garbage(working_set, span)
1705 }
1706}
1707
1708pub fn parse_float(working_set: &mut StateWorkingSet, span: Span) -> Expression {
1709 let token = working_set.get_span_contents(span);
1710 let token = strip_underscores(token);
1711
1712 if let Ok(x) = token.parse::<f64>() {
1713 Expression::new(working_set, Expr::Float(x), span, Type::Float)
1714 } else {
1715 working_set.error(ParseError::Expected("float", span));
1716
1717 garbage(working_set, span)
1718 }
1719}
1720
1721pub fn parse_number(working_set: &mut StateWorkingSet, span: Span) -> Expression {
1722 let starting_error_count = working_set.parse_errors.len();
1723
1724 let result = parse_int(working_set, span);
1725 if starting_error_count == working_set.parse_errors.len() {
1726 return result;
1727 } else if !matches!(
1728 working_set.parse_errors.last(),
1729 Some(ParseError::Expected(_, _))
1730 ) {
1731 } else {
1732 working_set.parse_errors.truncate(starting_error_count);
1733 }
1734
1735 let result = parse_float(working_set, span);
1736
1737 if starting_error_count == working_set.parse_errors.len() {
1738 return result;
1739 }
1740 working_set.parse_errors.truncate(starting_error_count);
1741
1742 working_set.error(ParseError::Expected("number", span));
1743 garbage(working_set, span)
1744}
1745
1746pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Option<Expression> {
1747 trace!("parsing: range");
1748 let starting_error_count = working_set.parse_errors.len();
1749
1750 let contents = working_set.get_span_contents(span);
1758
1759 let token = if let Ok(s) = String::from_utf8(contents.into()) {
1760 s
1761 } else {
1762 working_set.error(ParseError::NonUtf8(span));
1763 return None;
1764 };
1765
1766 if token.starts_with("...") {
1767 working_set.error(ParseError::Expected(
1768 "range operator ('..'), got spread ('...')",
1769 span,
1770 ));
1771 return None;
1772 }
1773
1774 if !token.contains("..") {
1775 working_set.error(ParseError::Expected("at least one range bound set", span));
1776 return None;
1777 }
1778
1779 let dotdot_pos: Vec<_> = token.match_indices("..").map(|(pos, _)| pos).collect();
1781
1782 let (next_op_pos, range_op_pos) = match dotdot_pos.len() {
1783 1 => (None, dotdot_pos[0]),
1784 2 => (Some(dotdot_pos[0]), dotdot_pos[1]),
1785 _ => {
1786 working_set.error(ParseError::Expected(
1787 "one range operator ('..' or '..<') and optionally one next operator ('..')",
1788 span,
1789 ));
1790 return None;
1791 }
1792 };
1793 if dotdot_pos[0] > 0 {
1796 let (_tokens, err) = lex(
1797 &contents[..dotdot_pos[0]],
1798 span.start,
1799 &[],
1800 &[b'.', b'?'],
1801 true,
1802 );
1803 if let Some(_err) = err {
1804 working_set.error(ParseError::Expected("Valid expression before ..", span));
1805 return None;
1806 }
1807 }
1808
1809 let (inclusion, range_op_str, range_op_span) = if let Some(pos) = token.find("..<") {
1810 if pos == range_op_pos {
1811 let op_str = "..<";
1812 let op_span = Span::new(
1813 span.start + range_op_pos,
1814 span.start + range_op_pos + op_str.len(),
1815 );
1816 (RangeInclusion::RightExclusive, "..<", op_span)
1817 } else {
1818 working_set.error(ParseError::Expected(
1819 "inclusive operator preceding second range bound",
1820 span,
1821 ));
1822 return None;
1823 }
1824 } else {
1825 let op_str = if token.contains("..=") { "..=" } else { ".." };
1826 let op_span = Span::new(
1827 span.start + range_op_pos,
1828 span.start + range_op_pos + op_str.len(),
1829 );
1830 (RangeInclusion::Inclusive, op_str, op_span)
1831 };
1832
1833 let from = if token.starts_with("..") {
1837 None
1839 } else {
1840 let from_span = Span::new(span.start, span.start + dotdot_pos[0]);
1841 Some(parse_value(working_set, from_span, &SyntaxShape::Number))
1842 };
1843
1844 let to = if token.ends_with(range_op_str) {
1845 None
1846 } else {
1847 let to_span = Span::new(range_op_span.end, span.end);
1848 Some(parse_value(working_set, to_span, &SyntaxShape::Number))
1849 };
1850
1851 trace!("-- from: {:?} to: {:?}", from, to);
1852
1853 if let (None, None) = (&from, &to) {
1854 working_set.error(ParseError::Expected("at least one range bound set", span));
1855 return None;
1856 }
1857
1858 let (next, next_op_span) = if let Some(pos) = next_op_pos {
1859 let next_op_span = Span::new(span.start + pos, span.start + pos + "..".len());
1860 let next_span = Span::new(next_op_span.end, range_op_span.start);
1861
1862 (
1863 Some(parse_value(working_set, next_span, &SyntaxShape::Number)),
1864 next_op_span,
1865 )
1866 } else {
1867 (None, span)
1868 };
1869
1870 if working_set.parse_errors.len() != starting_error_count {
1871 return None;
1872 }
1873
1874 let operator = RangeOperator {
1875 inclusion,
1876 span: range_op_span,
1877 next_op_span,
1878 };
1879
1880 let mut range = Range {
1881 from,
1882 next,
1883 to,
1884 operator,
1885 };
1886
1887 check_range_types(working_set, &mut range);
1888
1889 Some(Expression::new(
1890 working_set,
1891 Expr::Range(Box::new(range)),
1892 span,
1893 Type::Range,
1894 ))
1895}
1896
1897pub(crate) fn parse_dollar_expr(working_set: &mut StateWorkingSet, span: Span) -> Expression {
1898 trace!("parsing: dollar expression");
1899 let contents = working_set.get_span_contents(span);
1900
1901 if contents.starts_with(b"$\"") || contents.starts_with(b"$'") {
1902 parse_string_interpolation(working_set, span)
1903 } else if contents.starts_with(b"$.") {
1904 parse_simple_cell_path(working_set, Span::new(span.start + 2, span.end))
1905 } else {
1906 let starting_error_count = working_set.parse_errors.len();
1907
1908 if let Some(expr) = parse_range(working_set, span) {
1909 expr
1910 } else {
1911 working_set.parse_errors.truncate(starting_error_count);
1912 parse_full_cell_path(working_set, None, span)
1913 }
1914 }
1915}
1916
1917pub fn parse_raw_string(working_set: &mut StateWorkingSet, span: Span) -> Expression {
1918 trace!("parsing: raw-string, with required delimiters");
1919
1920 let bytes = working_set.get_span_contents(span);
1921
1922 let prefix_sharp_cnt = if bytes.starts_with(b"r#") {
1923 let mut sharp_cnt = 1;
1926 let mut index = 2;
1927 while index < bytes.len() && bytes[index] == b'#' {
1928 index += 1;
1929 sharp_cnt += 1;
1930 }
1931 sharp_cnt
1932 } else {
1933 working_set.error(ParseError::Expected("r#", span));
1934 return garbage(working_set, span);
1935 };
1936 let expect_postfix_sharp_cnt = prefix_sharp_cnt;
1937 if bytes.len() < prefix_sharp_cnt + expect_postfix_sharp_cnt + 3 {
1941 working_set.error(ParseError::Unclosed('\''.into(), span));
1942 return garbage(working_set, span);
1943 }
1944
1945 let postfix_bytes = &bytes[bytes.len() - expect_postfix_sharp_cnt..bytes.len()];
1947 if postfix_bytes.iter().any(|b| *b != b'#') {
1948 working_set.error(ParseError::Unbalanced(
1949 "prefix #".to_string(),
1950 "postfix #".to_string(),
1951 span,
1952 ));
1953 return garbage(working_set, span);
1954 }
1955 if bytes[1 + prefix_sharp_cnt] != b'\''
1957 || bytes[bytes.len() - expect_postfix_sharp_cnt - 1] != b'\''
1958 {
1959 working_set.error(ParseError::Unclosed('\''.into(), span));
1960 return garbage(working_set, span);
1961 }
1962
1963 let bytes = &bytes[prefix_sharp_cnt + 1 + 1..bytes.len() - 1 - prefix_sharp_cnt];
1964 if let Ok(token) = String::from_utf8(bytes.into()) {
1965 Expression::new(working_set, Expr::RawString(token), span, Type::String)
1966 } else {
1967 working_set.error(ParseError::Expected("utf8 raw-string", span));
1968 garbage(working_set, span)
1969 }
1970}
1971
1972pub fn parse_paren_expr(
1973 working_set: &mut StateWorkingSet,
1974 span: Span,
1975 shape: &SyntaxShape,
1976) -> Expression {
1977 let starting_error_count = working_set.parse_errors.len();
1978
1979 if let Some(expr) = parse_range(working_set, span) {
1980 expr
1981 } else {
1982 working_set.parse_errors.truncate(starting_error_count);
1983
1984 if matches!(shape, SyntaxShape::Signature) {
1985 parse_signature(working_set, span)
1986 } else {
1987 parse_full_cell_path(working_set, None, span)
1988 }
1989 }
1990}
1991
1992pub fn parse_brace_expr(
1993 working_set: &mut StateWorkingSet,
1994 span: Span,
1995 shape: &SyntaxShape,
1996) -> Expression {
1997 if span.end <= (span.start + 1) {
2006 working_set.error(ParseError::ExpectedWithStringMsg(
2007 format!("non-block value: {shape}"),
2008 span,
2009 ));
2010 return Expression::garbage(working_set, span);
2011 }
2012
2013 let bytes = working_set.get_span_contents(Span::new(span.start + 1, span.end - 1));
2014 let (tokens, _) = lex(bytes, span.start + 1, &[b'\r', b'\n', b'\t'], &[b':'], true);
2015
2016 let second_token = tokens
2017 .first()
2018 .map(|token| working_set.get_span_contents(token.span));
2019
2020 let second_token_contents = tokens.first().map(|token| token.contents);
2021
2022 let third_token = tokens
2023 .get(1)
2024 .map(|token| working_set.get_span_contents(token.span));
2025
2026 if second_token.is_none() {
2027 if matches!(shape, SyntaxShape::Closure(_)) {
2029 parse_closure_expression(working_set, shape, span)
2030 } else if matches!(shape, SyntaxShape::Block) {
2031 parse_block_expression(working_set, span)
2032 } else if matches!(shape, SyntaxShape::MatchBlock) {
2033 parse_match_block_expression(working_set, span)
2034 } else {
2035 parse_record(working_set, span)
2036 }
2037 } else if matches!(second_token_contents, Some(TokenContents::Pipe))
2038 || matches!(second_token_contents, Some(TokenContents::PipePipe))
2039 {
2040 parse_closure_expression(working_set, shape, span)
2041 } else if matches!(third_token, Some(b":")) {
2042 parse_full_cell_path(working_set, None, span)
2043 } else if matches!(shape, SyntaxShape::Closure(_)) {
2044 parse_closure_expression(working_set, shape, span)
2045 } else if matches!(shape, SyntaxShape::Block) {
2046 parse_block_expression(working_set, span)
2047 } else if matches!(shape, SyntaxShape::MatchBlock) {
2048 parse_match_block_expression(working_set, span)
2049 } else if second_token.is_some_and(|c| {
2050 c.len() > 3 && c.starts_with(b"...") && (c[3] == b'$' || c[3] == b'{' || c[3] == b'(')
2051 }) {
2052 parse_record(working_set, span)
2053 } else if matches!(shape, SyntaxShape::Any) {
2054 parse_closure_expression(working_set, shape, span)
2055 } else {
2056 working_set.error(ParseError::ExpectedWithStringMsg(
2057 format!("non-block value: {shape}"),
2058 span,
2059 ));
2060
2061 Expression::garbage(working_set, span)
2062 }
2063}
2064
2065pub fn parse_string_interpolation(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2066 #[derive(PartialEq, Eq, Debug)]
2067 enum InterpolationMode {
2068 String,
2069 Expression,
2070 }
2071
2072 let contents = working_set.get_span_contents(span);
2073
2074 let mut double_quote = false;
2075
2076 let (start, end) = if contents.starts_with(b"$\"") {
2077 double_quote = true;
2078 let end = if contents.ends_with(b"\"") && contents.len() > 2 {
2079 span.end - 1
2080 } else {
2081 span.end
2082 };
2083 (span.start + 2, end)
2084 } else if contents.starts_with(b"$'") {
2085 let end = if contents.ends_with(b"'") && contents.len() > 2 {
2086 span.end - 1
2087 } else {
2088 span.end
2089 };
2090 (span.start + 2, end)
2091 } else {
2092 (span.start, span.end)
2093 };
2094
2095 let inner_span = Span::new(start, end);
2096 let contents = working_set.get_span_contents(inner_span).to_vec();
2097
2098 let mut output = vec![];
2099 let mut mode = InterpolationMode::String;
2100 let mut token_start = start;
2101 let mut delimiter_stack = vec![];
2102
2103 let mut consecutive_backslashes: usize = 0;
2104
2105 let mut b = start;
2106
2107 while b != end {
2108 let current_byte = contents[b - start];
2109
2110 if mode == InterpolationMode::String {
2111 let preceding_consecutive_backslashes = consecutive_backslashes;
2112
2113 let is_backslash = current_byte == b'\\';
2114 consecutive_backslashes = if is_backslash {
2115 preceding_consecutive_backslashes + 1
2116 } else {
2117 0
2118 };
2119
2120 if current_byte == b'(' && (!double_quote || preceding_consecutive_backslashes % 2 == 0)
2121 {
2122 mode = InterpolationMode::Expression;
2123 if token_start < b {
2124 let span = Span::new(token_start, b);
2125 let str_contents = working_set.get_span_contents(span);
2126
2127 let (str_contents, err) = if double_quote {
2128 unescape_string(str_contents, span)
2129 } else {
2130 (str_contents.to_vec(), None)
2131 };
2132 if let Some(err) = err {
2133 working_set.error(err);
2134 }
2135
2136 output.push(Expression::new(
2137 working_set,
2138 Expr::String(String::from_utf8_lossy(&str_contents).to_string()),
2139 span,
2140 Type::String,
2141 ));
2142 token_start = b;
2143 }
2144 }
2145 }
2146
2147 if mode == InterpolationMode::Expression {
2148 let byte = current_byte;
2149 if let Some(b'\'') = delimiter_stack.last() {
2150 if byte == b'\'' {
2151 delimiter_stack.pop();
2152 }
2153 } else if let Some(b'"') = delimiter_stack.last() {
2154 if byte == b'"' {
2155 delimiter_stack.pop();
2156 }
2157 } else if let Some(b'`') = delimiter_stack.last() {
2158 if byte == b'`' {
2159 delimiter_stack.pop();
2160 }
2161 } else if byte == b'\'' {
2162 delimiter_stack.push(b'\'')
2163 } else if byte == b'"' {
2164 delimiter_stack.push(b'"');
2165 } else if byte == b'`' {
2166 delimiter_stack.push(b'`')
2167 } else if byte == b'(' {
2168 delimiter_stack.push(b')');
2169 } else if byte == b')' {
2170 if let Some(b')') = delimiter_stack.last() {
2171 delimiter_stack.pop();
2172 }
2173 if delimiter_stack.is_empty() {
2174 mode = InterpolationMode::String;
2175
2176 if token_start < b {
2177 let span = Span::new(token_start, b + 1);
2178
2179 let expr = parse_full_cell_path(working_set, None, span);
2180 output.push(expr);
2181 }
2182
2183 token_start = b + 1;
2184 continue;
2185 }
2186 }
2187 }
2188 b += 1;
2189 }
2190
2191 match mode {
2192 InterpolationMode::String => {
2193 if token_start < end {
2194 let span = Span::new(token_start, end);
2195 let str_contents = working_set.get_span_contents(span);
2196
2197 let (str_contents, err) = if double_quote {
2198 unescape_string(str_contents, span)
2199 } else {
2200 (str_contents.to_vec(), None)
2201 };
2202 if let Some(err) = err {
2203 working_set.error(err);
2204 }
2205
2206 output.push(Expression::new(
2207 working_set,
2208 Expr::String(String::from_utf8_lossy(&str_contents).to_string()),
2209 span,
2210 Type::String,
2211 ));
2212 }
2213 }
2214 InterpolationMode::Expression => {
2215 if token_start < end {
2216 let span = Span::new(token_start, end);
2217
2218 let expr = parse_full_cell_path(working_set, None, span);
2219 output.push(expr);
2220 }
2221 }
2222 }
2223
2224 Expression::new(
2225 working_set,
2226 Expr::StringInterpolation(output),
2227 span,
2228 Type::String,
2229 )
2230}
2231
2232pub fn parse_variable_expr(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2233 let contents = working_set.get_span_contents(span);
2234
2235 if contents == b"$nu" {
2236 return Expression::new(
2237 working_set,
2238 Expr::Var(nu_protocol::NU_VARIABLE_ID),
2239 span,
2240 Type::Any,
2241 );
2242 } else if contents == b"$in" {
2243 return Expression::new(
2244 working_set,
2245 Expr::Var(nu_protocol::IN_VARIABLE_ID),
2246 span,
2247 Type::Any,
2248 );
2249 } else if contents == b"$env" {
2250 return Expression::new(
2251 working_set,
2252 Expr::Var(nu_protocol::ENV_VARIABLE_ID),
2253 span,
2254 Type::Any,
2255 );
2256 }
2257
2258 let name = if contents.starts_with(b"$") {
2259 String::from_utf8_lossy(&contents[1..]).to_string()
2260 } else {
2261 String::from_utf8_lossy(contents).to_string()
2262 };
2263
2264 let bytes = working_set.get_span_contents(span);
2265 let suggestion = || {
2266 DidYouMean::new(
2267 &working_set.list_variables(),
2268 working_set.get_span_contents(span),
2269 )
2270 };
2271 if !is_variable(bytes) {
2272 working_set.error(ParseError::ExpectedWithDidYouMean(
2273 "valid variable name",
2274 suggestion(),
2275 span,
2276 ));
2277 garbage(working_set, span)
2278 } else if let Some(id) = working_set.find_variable(bytes) {
2279 Expression::new(
2280 working_set,
2281 Expr::Var(id),
2282 span,
2283 working_set.get_variable(id).ty.clone(),
2284 )
2285 } else if working_set.get_env_var(&name).is_some() {
2286 working_set.error(ParseError::EnvVarNotVar(name, span));
2287 garbage(working_set, span)
2288 } else {
2289 working_set.error(ParseError::VariableNotFound(suggestion(), span));
2290 garbage(working_set, span)
2291 }
2292}
2293
2294pub fn parse_cell_path(
2295 working_set: &mut StateWorkingSet,
2296 tokens: impl Iterator<Item = Token>,
2297 expect_dot: bool,
2298) -> Vec<PathMember> {
2299 enum TokenType {
2300 Dot, QuestionOrDot, PathMember, }
2304
2305 let mut expected_token = if expect_dot {
2307 TokenType::Dot
2308 } else {
2309 TokenType::PathMember
2310 };
2311
2312 let mut tail = vec![];
2313
2314 for path_element in tokens {
2315 let bytes = working_set.get_span_contents(path_element.span);
2316
2317 match expected_token {
2318 TokenType::Dot => {
2319 if bytes.len() != 1 || bytes[0] != b'.' {
2320 working_set.error(ParseError::Expected(".", path_element.span));
2321 return tail;
2322 }
2323 expected_token = TokenType::PathMember;
2324 }
2325 TokenType::QuestionOrDot => {
2326 if bytes.len() == 1 && bytes[0] == b'.' {
2327 expected_token = TokenType::PathMember;
2328 } else if bytes.len() == 1 && bytes[0] == b'?' {
2329 if let Some(last) = tail.last_mut() {
2330 match last {
2331 PathMember::String {
2332 ref mut optional, ..
2333 } => *optional = true,
2334 PathMember::Int {
2335 ref mut optional, ..
2336 } => *optional = true,
2337 }
2338 }
2339 expected_token = TokenType::Dot;
2340 } else {
2341 working_set.error(ParseError::Expected(". or ?", path_element.span));
2342 return tail;
2343 }
2344 }
2345 TokenType::PathMember => {
2346 let starting_error_count = working_set.parse_errors.len();
2347
2348 let expr = parse_int(working_set, path_element.span);
2349 working_set.parse_errors.truncate(starting_error_count);
2350
2351 match expr {
2352 Expression {
2353 expr: Expr::Int(val),
2354 span,
2355 ..
2356 } => tail.push(PathMember::Int {
2357 val: val as usize,
2358 span,
2359 optional: false,
2360 }),
2361 _ => {
2362 let result = parse_string(working_set, path_element.span);
2363 match result {
2364 Expression {
2365 expr: Expr::String(string),
2366 span,
2367 ..
2368 } => {
2369 tail.push(PathMember::String {
2370 val: string,
2371 span,
2372 optional: false,
2373 });
2374 }
2375 _ => {
2376 working_set
2377 .error(ParseError::Expected("string", path_element.span));
2378 return tail;
2379 }
2380 }
2381 }
2382 }
2383 expected_token = TokenType::QuestionOrDot;
2384 }
2385 }
2386 }
2387
2388 tail
2389}
2390
2391pub fn parse_simple_cell_path(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2392 let source = working_set.get_span_contents(span);
2393
2394 let (tokens, err) = lex(source, span.start, &[b'\n', b'\r'], &[b'.', b'?'], true);
2395 if let Some(err) = err {
2396 working_set.error(err)
2397 }
2398
2399 let tokens = tokens.into_iter().peekable();
2400
2401 let cell_path = parse_cell_path(working_set, tokens, false);
2402
2403 Expression::new(
2404 working_set,
2405 Expr::CellPath(CellPath { members: cell_path }),
2406 span,
2407 Type::CellPath,
2408 )
2409}
2410
2411pub fn parse_full_cell_path(
2412 working_set: &mut StateWorkingSet,
2413 implicit_head: Option<VarId>,
2414 span: Span,
2415) -> Expression {
2416 trace!("parsing: full cell path");
2417 let full_cell_span = span;
2418 let source = working_set.get_span_contents(span);
2419
2420 let (tokens, err) = lex(source, span.start, &[b'\n', b'\r'], &[b'.', b'?'], true);
2421 if let Some(err) = err {
2422 working_set.error(err)
2423 }
2424
2425 let mut tokens = tokens.into_iter().peekable();
2426 if let Some(head) = tokens.peek() {
2427 let bytes = working_set.get_span_contents(head.span);
2428 let (head, expect_dot) = if bytes.starts_with(b"(") {
2429 trace!("parsing: paren-head of full cell path");
2430
2431 let head_span = head.span;
2432 let mut start = head.span.start;
2433 let mut end = head.span.end;
2434
2435 if bytes.starts_with(b"(") {
2436 start += 1;
2437 }
2438 if bytes.ends_with(b")") {
2439 end -= 1;
2440 } else {
2441 working_set.error(ParseError::Unclosed(")".into(), Span::new(end, end)));
2442 }
2443
2444 let span = Span::new(start, end);
2445
2446 let source = working_set.get_span_contents(span);
2447
2448 let (output, err) = lex(source, span.start, &[b'\n', b'\r'], &[], true);
2449 if let Some(err) = err {
2450 working_set.error(err)
2451 }
2452
2453 let output = parse_block(working_set, &output, span, true, true);
2456
2457 let ty = output.output_type();
2458
2459 let block_id = working_set.add_block(Arc::new(output));
2460 tokens.next();
2461
2462 (
2463 Expression::new(working_set, Expr::Subexpression(block_id), head_span, ty),
2464 true,
2465 )
2466 } else if bytes.starts_with(b"[") {
2467 trace!("parsing: table head of full cell path");
2468
2469 let output = parse_table_expression(working_set, head.span, &SyntaxShape::Any);
2470
2471 tokens.next();
2472
2473 (output, true)
2474 } else if bytes.starts_with(b"{") {
2475 trace!("parsing: record head of full cell path");
2476 let output = parse_record(working_set, head.span);
2477
2478 tokens.next();
2479
2480 (output, true)
2481 } else if bytes.starts_with(b"$") {
2482 trace!("parsing: $variable head of full cell path");
2483
2484 let out = parse_variable_expr(working_set, head.span);
2485
2486 tokens.next();
2487
2488 (out, true)
2489 } else if let Some(var_id) = implicit_head {
2490 trace!("parsing: implicit head of full cell path");
2491 (
2492 Expression::new(working_set, Expr::Var(var_id), head.span, Type::Any),
2493 false,
2494 )
2495 } else {
2496 working_set.error(ParseError::Mismatch(
2497 "variable or subexpression".into(),
2498 String::from_utf8_lossy(bytes).to_string(),
2499 span,
2500 ));
2501 return garbage(working_set, span);
2502 };
2503
2504 let tail = parse_cell_path(working_set, tokens, expect_dot);
2505 let ty = if !tail.is_empty() {
2507 Type::Any
2510 } else {
2511 head.ty.clone()
2512 };
2513
2514 Expression::new(
2515 working_set,
2516 Expr::FullCellPath(Box::new(FullCellPath { head, tail })),
2517 full_cell_span,
2518 ty,
2519 )
2520 } else {
2521 garbage(working_set, span)
2522 }
2523}
2524
2525pub fn parse_directory(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2526 let bytes = working_set.get_span_contents(span);
2527 let quoted = is_quoted(bytes);
2528 let (token, err) = unescape_unquote_string(bytes, span);
2529 trace!("parsing: directory");
2530
2531 if err.is_none() {
2532 trace!("-- found {}", token);
2533
2534 Expression::new(
2535 working_set,
2536 Expr::Directory(token, quoted),
2537 span,
2538 Type::String,
2539 )
2540 } else {
2541 working_set.error(ParseError::Expected("directory", span));
2542
2543 garbage(working_set, span)
2544 }
2545}
2546
2547pub fn parse_filepath(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2548 let bytes = working_set.get_span_contents(span);
2549 let quoted = is_quoted(bytes);
2550 let (token, err) = unescape_unquote_string(bytes, span);
2551 trace!("parsing: filepath");
2552
2553 if err.is_none() {
2554 trace!("-- found {}", token);
2555
2556 Expression::new(
2557 working_set,
2558 Expr::Filepath(token, quoted),
2559 span,
2560 Type::String,
2561 )
2562 } else {
2563 working_set.error(ParseError::Expected("filepath", span));
2564
2565 garbage(working_set, span)
2566 }
2567}
2568
2569pub fn parse_datetime(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2571 trace!("parsing: datetime");
2572
2573 let bytes = working_set.get_span_contents(span);
2574
2575 if bytes.len() < 6
2576 || !bytes[0].is_ascii_digit()
2577 || !bytes[1].is_ascii_digit()
2578 || !bytes[2].is_ascii_digit()
2579 || !bytes[3].is_ascii_digit()
2580 || bytes[4] != b'-'
2581 {
2582 working_set.error(ParseError::Expected("datetime", span));
2583 return garbage(working_set, span);
2584 }
2585
2586 let token = String::from_utf8_lossy(bytes).to_string();
2587
2588 if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&token) {
2589 return Expression::new(working_set, Expr::DateTime(datetime), span, Type::Date);
2590 }
2591
2592 let just_date = token.clone() + "T00:00:00+00:00";
2594 if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&just_date) {
2595 return Expression::new(working_set, Expr::DateTime(datetime), span, Type::Date);
2596 }
2597
2598 let datetime = token + "+00:00";
2600 if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&datetime) {
2601 return Expression::new(working_set, Expr::DateTime(datetime), span, Type::Date);
2602 }
2603
2604 working_set.error(ParseError::Expected("datetime", span));
2605
2606 garbage(working_set, span)
2607}
2608
2609pub fn parse_duration(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2611 trace!("parsing: duration");
2612
2613 let bytes = working_set.get_span_contents(span);
2614
2615 match parse_unit_value(bytes, span, DURATION_UNIT_GROUPS, Type::Duration, |x| x) {
2616 Some(Ok(expr)) => {
2617 let span_id = working_set.add_span(span);
2618 expr.with_span_id(span_id)
2619 }
2620 Some(Err(mk_err_for)) => {
2621 working_set.error(mk_err_for("duration"));
2622 garbage(working_set, span)
2623 }
2624 None => {
2625 working_set.error(ParseError::Expected("duration with valid units", span));
2626 garbage(working_set, span)
2627 }
2628 }
2629}
2630
2631pub fn parse_filesize(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2633 trace!("parsing: filesize");
2634
2635 let bytes = working_set.get_span_contents(span);
2636
2637 if bytes.starts_with(b"0x") {
2639 working_set.error(ParseError::Expected("filesize with valid units", span));
2640 return garbage(working_set, span);
2641 }
2642
2643 match parse_unit_value(bytes, span, FILESIZE_UNIT_GROUPS, Type::Filesize, |x| {
2644 x.to_ascii_uppercase()
2645 }) {
2646 Some(Ok(expr)) => {
2647 let span_id = working_set.add_span(span);
2648 expr.with_span_id(span_id)
2649 }
2650 Some(Err(mk_err_for)) => {
2651 working_set.error(mk_err_for("filesize"));
2652 garbage(working_set, span)
2653 }
2654 None => {
2655 working_set.error(ParseError::Expected("filesize with valid units", span));
2656 garbage(working_set, span)
2657 }
2658 }
2659}
2660
2661type ParseUnitResult<'res> = Result<Expression, Box<dyn Fn(&'res str) -> ParseError>>;
2662type UnitGroup<'unit> = (Unit, &'unit str, Option<(Unit, i64)>);
2663
2664pub fn parse_unit_value<'res>(
2665 bytes: &[u8],
2666 span: Span,
2667 unit_groups: &[UnitGroup],
2668 ty: Type,
2669 transform: fn(String) -> String,
2670) -> Option<ParseUnitResult<'res>> {
2671 if bytes.len() < 2
2672 || !(bytes[0].is_ascii_digit() || (bytes[0] == b'-' && bytes[1].is_ascii_digit()))
2673 {
2674 return None;
2675 }
2676
2677 let value = transform(String::from_utf8_lossy(bytes).into());
2678
2679 if let Some((unit, name, convert)) = unit_groups.iter().find(|x| value.ends_with(x.1)) {
2680 let lhs_len = value.len() - name.len();
2681 let lhs = strip_underscores(value[..lhs_len].as_bytes());
2682 let lhs_span = Span::new(span.start, span.start + lhs_len);
2683 let unit_span = Span::new(span.start + lhs_len, span.end);
2684 if lhs.ends_with('$') {
2685 return None;
2688 }
2689
2690 let (decimal_part, number_part) = modf(match lhs.parse::<f64>() {
2691 Ok(it) => it,
2692 Err(_) => {
2693 let mk_err = move |name| {
2694 ParseError::LabeledError(
2695 format!("{name} value must be a number"),
2696 "not a number".into(),
2697 lhs_span,
2698 )
2699 };
2700 return Some(Err(Box::new(mk_err)));
2701 }
2702 });
2703
2704 let (num, unit) = match convert {
2705 Some(convert_to) => (
2706 ((number_part * convert_to.1 as f64) + (decimal_part * convert_to.1 as f64)) as i64,
2707 convert_to.0,
2708 ),
2709 None => (number_part as i64, *unit),
2710 };
2711
2712 trace!("-- found {} {:?}", num, unit);
2713 let value = ValueWithUnit {
2714 expr: Expression::new_unknown(Expr::Int(num), lhs_span, Type::Number),
2715 unit: Spanned {
2716 item: unit,
2717 span: unit_span,
2718 },
2719 };
2720 let expr = Expression::new_unknown(Expr::ValueWithUnit(Box::new(value)), span, ty);
2721
2722 Some(Ok(expr))
2723 } else {
2724 None
2725 }
2726}
2727
2728pub const FILESIZE_UNIT_GROUPS: &[UnitGroup] = &[
2729 (
2730 Unit::Filesize(FilesizeUnit::KB),
2731 "KB",
2732 Some((Unit::Filesize(FilesizeUnit::B), 1000)),
2733 ),
2734 (
2735 Unit::Filesize(FilesizeUnit::MB),
2736 "MB",
2737 Some((Unit::Filesize(FilesizeUnit::KB), 1000)),
2738 ),
2739 (
2740 Unit::Filesize(FilesizeUnit::GB),
2741 "GB",
2742 Some((Unit::Filesize(FilesizeUnit::MB), 1000)),
2743 ),
2744 (
2745 Unit::Filesize(FilesizeUnit::TB),
2746 "TB",
2747 Some((Unit::Filesize(FilesizeUnit::GB), 1000)),
2748 ),
2749 (
2750 Unit::Filesize(FilesizeUnit::PB),
2751 "PB",
2752 Some((Unit::Filesize(FilesizeUnit::TB), 1000)),
2753 ),
2754 (
2755 Unit::Filesize(FilesizeUnit::EB),
2756 "EB",
2757 Some((Unit::Filesize(FilesizeUnit::PB), 1000)),
2758 ),
2759 (
2760 Unit::Filesize(FilesizeUnit::KiB),
2761 "KIB",
2762 Some((Unit::Filesize(FilesizeUnit::B), 1024)),
2763 ),
2764 (
2765 Unit::Filesize(FilesizeUnit::MiB),
2766 "MIB",
2767 Some((Unit::Filesize(FilesizeUnit::KiB), 1024)),
2768 ),
2769 (
2770 Unit::Filesize(FilesizeUnit::GiB),
2771 "GIB",
2772 Some((Unit::Filesize(FilesizeUnit::MiB), 1024)),
2773 ),
2774 (
2775 Unit::Filesize(FilesizeUnit::TiB),
2776 "TIB",
2777 Some((Unit::Filesize(FilesizeUnit::GiB), 1024)),
2778 ),
2779 (
2780 Unit::Filesize(FilesizeUnit::PiB),
2781 "PIB",
2782 Some((Unit::Filesize(FilesizeUnit::TiB), 1024)),
2783 ),
2784 (
2785 Unit::Filesize(FilesizeUnit::EiB),
2786 "EIB",
2787 Some((Unit::Filesize(FilesizeUnit::EiB), 1024)),
2788 ),
2789 (Unit::Filesize(FilesizeUnit::B), "B", None),
2790];
2791
2792pub const DURATION_UNIT_GROUPS: &[UnitGroup] = &[
2793 (Unit::Nanosecond, "ns", None),
2794 (Unit::Microsecond, "us", Some((Unit::Nanosecond, 1000))),
2796 (
2797 Unit::Microsecond,
2799 "\u{00B5}s",
2800 Some((Unit::Nanosecond, 1000)),
2801 ),
2802 (
2803 Unit::Microsecond,
2805 "\u{03BC}s",
2806 Some((Unit::Nanosecond, 1000)),
2807 ),
2808 (Unit::Millisecond, "ms", Some((Unit::Microsecond, 1000))),
2809 (Unit::Second, "sec", Some((Unit::Millisecond, 1000))),
2810 (Unit::Minute, "min", Some((Unit::Second, 60))),
2811 (Unit::Hour, "hr", Some((Unit::Minute, 60))),
2812 (Unit::Day, "day", Some((Unit::Minute, 1440))),
2813 (Unit::Week, "wk", Some((Unit::Day, 7))),
2814];
2815
2816fn modf(x: f64) -> (f64, f64) {
2818 let rv2: f64;
2819 let mut u = x.to_bits();
2820 let e = (((u >> 52) & 0x7ff) as i32) - 0x3ff;
2821
2822 if e >= 52 {
2824 rv2 = x;
2825 if e == 0x400 && (u << 12) != 0 {
2826 return (x, rv2);
2828 }
2829 u &= 1 << 63;
2830 return (f64::from_bits(u), rv2);
2831 }
2832
2833 if e < 0 {
2835 u &= 1 << 63;
2836 rv2 = f64::from_bits(u);
2837 return (x, rv2);
2838 }
2839
2840 let mask = ((!0) >> 12) >> e;
2841 if (u & mask) == 0 {
2842 rv2 = x;
2843 u &= 1 << 63;
2844 return (f64::from_bits(u), rv2);
2845 }
2846 u &= !mask;
2847 rv2 = f64::from_bits(u);
2848 (x - rv2, rv2)
2849}
2850
2851pub fn parse_glob_pattern(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2852 let bytes = working_set.get_span_contents(span);
2853 let quoted = is_quoted(bytes);
2854 let (token, err) = unescape_unquote_string(bytes, span);
2855 trace!("parsing: glob pattern");
2856
2857 if err.is_none() {
2858 trace!("-- found {}", token);
2859
2860 Expression::new(
2861 working_set,
2862 Expr::GlobPattern(token, quoted),
2863 span,
2864 Type::Glob,
2865 )
2866 } else {
2867 working_set.error(ParseError::Expected("glob pattern string", span));
2868
2869 garbage(working_set, span)
2870 }
2871}
2872
2873pub fn unescape_string(bytes: &[u8], span: Span) -> (Vec<u8>, Option<ParseError>) {
2874 let mut output = Vec::new();
2875 let mut error = None;
2876
2877 let mut idx = 0;
2878
2879 if !bytes.contains(&b'\\') {
2880 return (bytes.to_vec(), None);
2881 }
2882
2883 'us_loop: while idx < bytes.len() {
2884 if bytes[idx] == b'\\' {
2885 idx += 1;
2887
2888 match bytes.get(idx) {
2889 Some(b'"') => {
2890 output.push(b'"');
2891 idx += 1;
2892 }
2893 Some(b'\'') => {
2894 output.push(b'\'');
2895 idx += 1;
2896 }
2897 Some(b'\\') => {
2898 output.push(b'\\');
2899 idx += 1;
2900 }
2901 Some(b'/') => {
2902 output.push(b'/');
2903 idx += 1;
2904 }
2905 Some(b'(') => {
2906 output.push(b'(');
2907 idx += 1;
2908 }
2909 Some(b')') => {
2910 output.push(b')');
2911 idx += 1;
2912 }
2913 Some(b'{') => {
2914 output.push(b'{');
2915 idx += 1;
2916 }
2917 Some(b'}') => {
2918 output.push(b'}');
2919 idx += 1;
2920 }
2921 Some(b'$') => {
2922 output.push(b'$');
2923 idx += 1;
2924 }
2925 Some(b'^') => {
2926 output.push(b'^');
2927 idx += 1;
2928 }
2929 Some(b'#') => {
2930 output.push(b'#');
2931 idx += 1;
2932 }
2933 Some(b'|') => {
2934 output.push(b'|');
2935 idx += 1;
2936 }
2937 Some(b'~') => {
2938 output.push(b'~');
2939 idx += 1;
2940 }
2941 Some(b'a') => {
2942 output.push(0x7);
2943 idx += 1;
2944 }
2945 Some(b'b') => {
2946 output.push(0x8);
2947 idx += 1;
2948 }
2949 Some(b'e') => {
2950 output.push(0x1b);
2951 idx += 1;
2952 }
2953 Some(b'f') => {
2954 output.push(0xc);
2955 idx += 1;
2956 }
2957 Some(b'n') => {
2958 output.push(b'\n');
2959 idx += 1;
2960 }
2961 Some(b'r') => {
2962 output.push(b'\r');
2963 idx += 1;
2964 }
2965 Some(b't') => {
2966 output.push(b'\t');
2967 idx += 1;
2968 }
2969 Some(b'u') => {
2970 let mut digits = String::with_capacity(10);
2971 let mut cur_idx = idx + 1; if let Some(b'{') = bytes.get(idx + 1) {
2974 cur_idx = idx + 2;
2975 loop {
2976 match bytes.get(cur_idx) {
2977 Some(b'}') => {
2978 cur_idx += 1;
2979 break;
2980 }
2981 Some(c) => {
2982 digits.push(*c as char);
2983 cur_idx += 1;
2984 }
2985 _ => {
2986 error = error.or(Some(ParseError::InvalidLiteral(
2987 "missing '}' for unicode escape '\\u{X...}'".into(),
2988 "string".into(),
2989 Span::new(span.start + idx, span.end),
2990 )));
2991 break 'us_loop;
2992 }
2993 }
2994 }
2995 }
2996
2997 if (1..=6).contains(&digits.len()) {
2998 let int = u32::from_str_radix(&digits, 16);
2999
3000 if let Ok(int) = int {
3001 if int <= 0x10ffff {
3002 let result = char::from_u32(int);
3003
3004 if let Some(result) = result {
3005 let mut buffer = vec![0; 4];
3006 let result = result.encode_utf8(&mut buffer);
3007
3008 for elem in result.bytes() {
3009 output.push(elem);
3010 }
3011
3012 idx = cur_idx;
3013 continue 'us_loop;
3014 }
3015 }
3016 }
3017 }
3018 error = error.or(Some(ParseError::InvalidLiteral(
3020 "invalid unicode escape '\\u{X...}', must be 1-6 hex digits, max value 10FFFF".into(),
3021 "string".into(),
3022 Span::new(span.start + idx, span.end),
3023 )));
3024 break 'us_loop;
3025 }
3026
3027 _ => {
3028 error = error.or(Some(ParseError::InvalidLiteral(
3029 "unrecognized escape after '\\'".into(),
3030 "string".into(),
3031 Span::new(span.start + idx, span.end),
3032 )));
3033 break 'us_loop;
3034 }
3035 }
3036 } else {
3037 output.push(bytes[idx]);
3038 idx += 1;
3039 }
3040 }
3041
3042 (output, error)
3043}
3044
3045pub fn unescape_unquote_string(bytes: &[u8], span: Span) -> (String, Option<ParseError>) {
3046 if bytes.starts_with(b"\"") {
3047 let bytes = trim_quotes(bytes);
3049
3050 let (bytes, err) = unescape_string(bytes, span);
3051
3052 if let Ok(token) = String::from_utf8(bytes) {
3053 (token, err)
3054 } else {
3055 (String::new(), Some(ParseError::Expected("string", span)))
3056 }
3057 } else {
3058 let bytes = trim_quotes(bytes);
3059
3060 if let Ok(token) = String::from_utf8(bytes.into()) {
3061 (token, None)
3062 } else {
3063 (String::new(), Some(ParseError::Expected("string", span)))
3064 }
3065 }
3066}
3067
3068pub fn parse_string(working_set: &mut StateWorkingSet, span: Span) -> Expression {
3069 trace!("parsing: string");
3070
3071 let bytes = working_set.get_span_contents(span);
3072
3073 if bytes.is_empty() {
3074 working_set.error(ParseError::Expected("String", span));
3075 return Expression::garbage(working_set, span);
3076 }
3077
3078 if bytes[0] != b'\'' && bytes[0] != b'"' && bytes[0] != b'`' && bytes.contains(&b'(') {
3080 return parse_string_interpolation(working_set, span);
3081 }
3082 {
3084 if bytes.starts_with(b"\"")
3085 && (bytes.iter().filter(|ch| **ch == b'"').count() > 1 && !bytes.ends_with(b"\""))
3086 {
3087 let close_delimiter_index = bytes
3088 .iter()
3089 .skip(1)
3090 .position(|ch| *ch == b'"')
3091 .expect("Already check input bytes contains at least two double quotes");
3092 let span = Span::new(span.start + close_delimiter_index + 2, span.end);
3094 working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(span));
3095 return garbage(working_set, span);
3096 }
3097
3098 if bytes.starts_with(b"\'")
3099 && (bytes.iter().filter(|ch| **ch == b'\'').count() > 1 && !bytes.ends_with(b"\'"))
3100 {
3101 let close_delimiter_index = bytes
3102 .iter()
3103 .skip(1)
3104 .position(|ch| *ch == b'\'')
3105 .expect("Already check input bytes contains at least two double quotes");
3106 let span = Span::new(span.start + close_delimiter_index + 2, span.end);
3108 working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(span));
3109 return garbage(working_set, span);
3110 }
3111 }
3112
3113 let (s, err) = unescape_unquote_string(bytes, span);
3114 if let Some(err) = err {
3115 working_set.error(err);
3116 }
3117
3118 Expression::new(working_set, Expr::String(s), span, Type::String)
3119}
3120
3121fn is_quoted(bytes: &[u8]) -> bool {
3122 (bytes.starts_with(b"\"") && bytes.ends_with(b"\"") && bytes.len() > 1)
3123 || (bytes.starts_with(b"\'") && bytes.ends_with(b"\'") && bytes.len() > 1)
3124}
3125
3126pub fn parse_string_strict(working_set: &mut StateWorkingSet, span: Span) -> Expression {
3127 trace!("parsing: string, with required delimiters");
3128
3129 let bytes = working_set.get_span_contents(span);
3130
3131 {
3133 let bytes = if bytes.starts_with(b"$") {
3134 &bytes[1..]
3135 } else {
3136 bytes
3137 };
3138 if bytes.starts_with(b"\"") && (bytes.len() == 1 || !bytes.ends_with(b"\"")) {
3139 working_set.error(ParseError::Unclosed("\"".into(), span));
3140 return garbage(working_set, span);
3141 }
3142 if bytes.starts_with(b"\'") && (bytes.len() == 1 || !bytes.ends_with(b"\'")) {
3143 working_set.error(ParseError::Unclosed("\'".into(), span));
3144 return garbage(working_set, span);
3145 }
3146 if bytes.starts_with(b"r#") && (bytes.len() == 1 || !bytes.ends_with(b"#")) {
3147 working_set.error(ParseError::Unclosed("r#".into(), span));
3148 return garbage(working_set, span);
3149 }
3150 }
3151
3152 let (bytes, quoted) = if (bytes.starts_with(b"\"") && bytes.ends_with(b"\"") && bytes.len() > 1)
3153 || (bytes.starts_with(b"\'") && bytes.ends_with(b"\'") && bytes.len() > 1)
3154 {
3155 (&bytes[1..(bytes.len() - 1)], true)
3156 } else if (bytes.starts_with(b"$\"") && bytes.ends_with(b"\"") && bytes.len() > 2)
3157 || (bytes.starts_with(b"$\'") && bytes.ends_with(b"\'") && bytes.len() > 2)
3158 {
3159 (&bytes[2..(bytes.len() - 1)], true)
3160 } else {
3161 (bytes, false)
3162 };
3163
3164 if let Ok(token) = String::from_utf8(bytes.into()) {
3165 trace!("-- found {}", token);
3166
3167 if quoted {
3168 Expression::new(working_set, Expr::String(token), span, Type::String)
3169 } else if token.contains(' ') {
3170 working_set.error(ParseError::Expected("string", span));
3171
3172 garbage(working_set, span)
3173 } else {
3174 Expression::new(working_set, Expr::String(token), span, Type::String)
3175 }
3176 } else {
3177 working_set.error(ParseError::Expected("string", span));
3178 garbage(working_set, span)
3179 }
3180}
3181
3182pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
3183 let Some(head_span) = spans.first() else {
3184 working_set.error(ParseError::WrongImportPattern(
3185 "needs at least one component of import pattern".to_string(),
3186 Span::concat(spans),
3187 ));
3188 return garbage(working_set, Span::concat(spans));
3189 };
3190
3191 let head_expr = parse_value(working_set, *head_span, &SyntaxShape::Any);
3192
3193 let (maybe_module_id, head_name) = match eval_constant(working_set, &head_expr) {
3194 Ok(Value::Nothing { .. }) => {
3195 return Expression::new(
3196 working_set,
3197 Expr::Nothing,
3198 Span::concat(spans),
3199 Type::Nothing,
3200 );
3201 }
3202 Ok(val) => match val.coerce_into_string() {
3203 Ok(s) => (working_set.find_module(s.as_bytes()), s.into_bytes()),
3204 Err(err) => {
3205 working_set.error(err.wrap(working_set, Span::concat(spans)));
3206 return garbage(working_set, Span::concat(spans));
3207 }
3208 },
3209 Err(err) => {
3210 working_set.error(err.wrap(working_set, Span::concat(spans)));
3211 return garbage(working_set, Span::concat(spans));
3212 }
3213 };
3214
3215 let mut import_pattern = ImportPattern {
3216 head: ImportPatternHead {
3217 name: head_name,
3218 id: maybe_module_id,
3219 span: *head_span,
3220 },
3221 members: vec![],
3222 hidden: HashSet::new(),
3223 constants: vec![],
3224 };
3225
3226 if spans.len() > 1 {
3227 let mut leaf_member_span = None;
3228
3229 for tail_span in spans[1..].iter() {
3230 if let Some(prev_span) = leaf_member_span {
3231 let what = if working_set.get_span_contents(prev_span) == b"*" {
3232 "glob"
3233 } else {
3234 "list"
3235 };
3236 working_set.error(ParseError::WrongImportPattern(
3237 format!(
3238 "{} member can be only at the end of an import pattern",
3239 what
3240 ),
3241 prev_span,
3242 ));
3243 return Expression::new(
3244 working_set,
3245 Expr::ImportPattern(Box::new(import_pattern)),
3246 prev_span,
3247 Type::List(Box::new(Type::String)),
3248 );
3249 }
3250
3251 let tail = working_set.get_span_contents(*tail_span);
3252
3253 if tail == b"*" {
3254 import_pattern
3255 .members
3256 .push(ImportPatternMember::Glob { span: *tail_span });
3257
3258 leaf_member_span = Some(*tail_span);
3259 } else if tail.starts_with(b"[") {
3260 let result = parse_list_expression(working_set, *tail_span, &SyntaxShape::String);
3261
3262 let mut output = vec![];
3263
3264 if let Expression {
3265 expr: Expr::List(list),
3266 ..
3267 } = result
3268 {
3269 for item in list {
3270 match item {
3271 ListItem::Item(expr) => {
3272 let contents = working_set.get_span_contents(expr.span);
3273 output.push((trim_quotes(contents).to_vec(), expr.span));
3274 }
3275 ListItem::Spread(_, spread) => {
3276 working_set.error(ParseError::WrongImportPattern(
3277 "cannot spread in an import pattern".into(),
3278 spread.span,
3279 ))
3280 }
3281 }
3282 }
3283
3284 import_pattern
3285 .members
3286 .push(ImportPatternMember::List { names: output });
3287 } else {
3288 working_set.error(ParseError::ExportNotFound(result.span));
3289 return Expression::new(
3290 working_set,
3291 Expr::ImportPattern(Box::new(import_pattern)),
3292 Span::concat(spans),
3293 Type::List(Box::new(Type::String)),
3294 );
3295 }
3296
3297 leaf_member_span = Some(*tail_span);
3298 } else {
3299 let tail = trim_quotes(tail);
3300
3301 import_pattern.members.push(ImportPatternMember::Name {
3302 name: tail.to_vec(),
3303 span: *tail_span,
3304 });
3305 }
3306 }
3307 }
3308
3309 Expression::new(
3310 working_set,
3311 Expr::ImportPattern(Box::new(import_pattern)),
3312 Span::concat(&spans[1..]),
3313 Type::List(Box::new(Type::String)),
3314 )
3315}
3316
3317pub fn parse_var_with_opt_type(
3322 working_set: &mut StateWorkingSet,
3323 spans: &[Span],
3324 spans_idx: &mut usize,
3325 mutable: bool,
3326) -> (Expression, Option<Type>) {
3327 let name_span = spans[*spans_idx];
3328 let bytes = working_set.get_span_contents(name_span).to_vec();
3329
3330 if bytes.contains(&b' ')
3331 || bytes.contains(&b'"')
3332 || bytes.contains(&b'\'')
3333 || bytes.contains(&b'`')
3334 {
3335 working_set.error(ParseError::VariableNotValid(spans[*spans_idx]));
3336 return (garbage(working_set, spans[*spans_idx]), None);
3337 }
3338
3339 if bytes.ends_with(b":") {
3340 let name_span = Span::new(name_span.start, name_span.end - 1);
3341 let var_name = bytes[0..(bytes.len() - 1)].to_vec();
3342
3343 if *spans_idx + 1 < spans.len() {
3345 *spans_idx += 1;
3346 let full_span = Span::concat(&spans[*spans_idx..]);
3349 let type_bytes = working_set.get_span_contents(full_span).to_vec();
3350
3351 let (tokens, parse_error) =
3352 lex_signature(&type_bytes, full_span.start, &[b','], &[], true);
3353
3354 if let Some(parse_error) = parse_error {
3355 working_set.error(parse_error);
3356 }
3357
3358 let ty = parse_type(working_set, &type_bytes, tokens[0].span);
3359 *spans_idx = spans.len() - 1;
3360
3361 if !is_variable(&var_name) {
3362 working_set.error(ParseError::Expected(
3363 "valid variable name",
3364 spans[*spans_idx - 1],
3365 ));
3366 return (garbage(working_set, spans[*spans_idx - 1]), None);
3367 }
3368
3369 let id = working_set.add_variable(var_name, spans[*spans_idx - 1], ty.clone(), mutable);
3370
3371 (
3372 Expression::new(working_set, Expr::VarDecl(id), name_span, ty.clone()),
3373 Some(ty),
3374 )
3375 } else {
3376 if !is_variable(&var_name) {
3377 working_set.error(ParseError::Expected(
3378 "valid variable name",
3379 spans[*spans_idx],
3380 ));
3381 return (garbage(working_set, spans[*spans_idx]), None);
3382 }
3383
3384 let id = working_set.add_variable(var_name, spans[*spans_idx], Type::Any, mutable);
3385
3386 working_set.error(ParseError::MissingType(spans[*spans_idx]));
3387 (
3388 Expression::new(working_set, Expr::VarDecl(id), spans[*spans_idx], Type::Any),
3389 None,
3390 )
3391 }
3392 } else {
3393 let var_name = bytes;
3394
3395 if !is_variable(&var_name) {
3396 working_set.error(ParseError::Expected(
3397 "valid variable name",
3398 spans[*spans_idx],
3399 ));
3400 return (garbage(working_set, spans[*spans_idx]), None);
3401 }
3402
3403 let id = working_set.add_variable(
3404 var_name,
3405 Span::concat(&spans[*spans_idx..*spans_idx + 1]),
3406 Type::Any,
3407 mutable,
3408 );
3409
3410 (
3411 Expression::new(working_set, Expr::VarDecl(id), spans[*spans_idx], Type::Any),
3412 None,
3413 )
3414 }
3415}
3416
3417pub fn expand_to_cell_path(
3418 working_set: &mut StateWorkingSet,
3419 expression: &mut Expression,
3420 var_id: VarId,
3421) {
3422 trace!("parsing: expanding to cell path");
3423 if let Expression {
3424 expr: Expr::String(_),
3425 span,
3426 ..
3427 } = expression
3428 {
3429 let new_expression = parse_full_cell_path(working_set, Some(var_id), *span);
3431
3432 *expression = new_expression;
3433 }
3434
3435 if let Expression {
3436 expr: Expr::UnaryNot(inner),
3437 ..
3438 } = expression
3439 {
3440 expand_to_cell_path(working_set, inner, var_id);
3441 }
3442}
3443
3444pub fn parse_input_output_types(
3445 working_set: &mut StateWorkingSet,
3446 spans: &[Span],
3447) -> Vec<(Type, Type)> {
3448 let mut full_span = Span::concat(spans);
3449
3450 let mut bytes = working_set.get_span_contents(full_span);
3451
3452 if bytes.starts_with(b"[") {
3453 bytes = &bytes[1..];
3454 full_span.start += 1;
3455 }
3456
3457 if bytes.ends_with(b"]") {
3458 bytes = &bytes[..(bytes.len() - 1)];
3459 full_span.end -= 1;
3460 }
3461
3462 let (tokens, parse_error) =
3463 lex_signature(bytes, full_span.start, &[b'\n', b'\r', b','], &[], true);
3464
3465 if let Some(parse_error) = parse_error {
3466 working_set.error(parse_error);
3467 }
3468
3469 let mut output = vec![];
3470
3471 let mut idx = 0;
3472 while idx < tokens.len() {
3473 let type_bytes = working_set.get_span_contents(tokens[idx].span).to_vec();
3474 let input_type = parse_type(working_set, &type_bytes, tokens[idx].span);
3475
3476 idx += 1;
3477 if idx >= tokens.len() {
3478 working_set.error(ParseError::Expected(
3479 "arrow (->)",
3480 Span::new(tokens[idx - 1].span.end, tokens[idx - 1].span.end),
3481 ));
3482 break;
3483 }
3484
3485 let arrow = working_set.get_span_contents(tokens[idx].span);
3486 if arrow != b"->" {
3487 working_set.error(ParseError::Expected("arrow (->)", tokens[idx].span));
3488 }
3489
3490 idx += 1;
3491 if idx >= tokens.len() {
3492 working_set.error(ParseError::MissingType(Span::new(
3493 tokens[idx - 1].span.end,
3494 tokens[idx - 1].span.end,
3495 )));
3496 break;
3497 }
3498
3499 let type_bytes = working_set.get_span_contents(tokens[idx].span).to_vec();
3500 let output_type = parse_type(working_set, &type_bytes, tokens[idx].span);
3501
3502 output.push((input_type, output_type));
3503
3504 idx += 1;
3505 }
3506
3507 output
3508}
3509
3510pub fn parse_full_signature(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
3511 match spans.len() {
3512 0 => {
3515 working_set.error(ParseError::InternalError(
3516 "failed to catch missing positional arguments".to_string(),
3517 Span::concat(spans),
3518 ));
3519 garbage(working_set, Span::concat(spans))
3520 }
3521
3522 1 => parse_signature(working_set, spans[0]),
3524
3525 2 if working_set.get_span_contents(spans[1]).starts_with(b"{") => {
3528 parse_signature(working_set, spans[0])
3529 }
3530
3531 _ => {
3536 let (mut arg_signature, input_output_types_pos) =
3537 if working_set.get_span_contents(spans[0]).ends_with(b":") {
3538 (
3539 parse_signature(working_set, Span::new(spans[0].start, spans[0].end - 1)),
3540 1,
3541 )
3542 } else if working_set.get_span_contents(spans[1]) == b":" {
3543 (parse_signature(working_set, spans[0]), 2)
3544 } else {
3545 working_set.error(ParseError::Expected(
3549 "colon (:) before type signature",
3550 Span::concat(&spans[1..]),
3551 ));
3552 (parse_signature(working_set, spans[0]), 1)
3555 };
3556
3557 let input_output_types =
3558 parse_input_output_types(working_set, &spans[input_output_types_pos..]);
3559
3560 if let Expression {
3561 expr: Expr::Signature(sig),
3562 span: expr_span,
3563 ..
3564 } = &mut arg_signature
3565 {
3566 sig.input_output_types = input_output_types;
3567 expr_span.end = Span::concat(&spans[input_output_types_pos..]).end;
3568 }
3569 arg_signature
3570 }
3571 }
3572}
3573
3574pub fn parse_row_condition(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
3575 let pos = spans.first().map(|s| s.start).unwrap_or(0);
3576 let var_id = working_set.add_variable(b"$it".to_vec(), Span::new(pos, pos), Type::Any, false);
3577 let expression = parse_math_expression(working_set, spans, Some(var_id));
3578 let span = Span::concat(spans);
3579
3580 let block_id = match expression.expr {
3581 Expr::Block(block_id) => block_id,
3582 Expr::Closure(block_id) => block_id,
3583 _ => {
3584 let mut block = Block::new();
3586 let mut pipeline = Pipeline::new();
3587 pipeline.elements.push(PipelineElement {
3588 pipe: None,
3589 expr: expression,
3590 redirection: None,
3591 });
3592
3593 block.pipelines.push(pipeline);
3594
3595 block.signature.required_positional.push(PositionalArg {
3596 name: "$it".into(),
3597 desc: "row condition".into(),
3598 shape: SyntaxShape::Any,
3599 var_id: Some(var_id),
3600 default_value: None,
3601 });
3602
3603 compile_block(working_set, &mut block);
3604
3605 working_set.add_block(Arc::new(block))
3606 }
3607 };
3608
3609 Expression::new(working_set, Expr::RowCondition(block_id), span, Type::Bool)
3610}
3611
3612pub fn parse_signature(working_set: &mut StateWorkingSet, span: Span) -> Expression {
3613 let bytes = working_set.get_span_contents(span);
3614
3615 let mut start = span.start;
3616 let mut end = span.end;
3617
3618 let mut has_paren = false;
3619
3620 if bytes.starts_with(b"[") {
3621 start += 1;
3622 } else if bytes.starts_with(b"(") {
3623 has_paren = true;
3624 start += 1;
3625 } else {
3626 working_set.error(ParseError::Expected("[ or (", Span::new(start, start + 1)));
3627 return garbage(working_set, span);
3628 }
3629
3630 if (has_paren && bytes.ends_with(b")")) || (!has_paren && bytes.ends_with(b"]")) {
3631 end -= 1;
3632 } else {
3633 working_set.error(ParseError::Unclosed("] or )".into(), Span::new(end, end)));
3634 }
3635
3636 let sig = parse_signature_helper(working_set, Span::new(start, end));
3637
3638 Expression::new(working_set, Expr::Signature(sig), span, Type::Any)
3639}
3640
3641pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> Box<Signature> {
3642 enum ParseMode {
3643 Arg,
3644 AfterCommaArg,
3645 Type,
3646 AfterType,
3647 DefaultValue,
3648 }
3649
3650 #[derive(Debug)]
3651 enum Arg {
3652 Positional {
3653 arg: PositionalArg,
3654 required: bool,
3655 type_annotated: bool,
3656 },
3657 RestPositional(PositionalArg),
3658 Flag {
3659 flag: Flag,
3660 type_annotated: bool,
3661 },
3662 }
3663
3664 let source = working_set.get_span_contents(span);
3665
3666 let (output, err) = lex_signature(
3667 source,
3668 span.start,
3669 &[b'\n', b'\r'],
3670 &[b':', b'=', b','],
3671 false,
3672 );
3673 if let Some(err) = err {
3674 working_set.error(err);
3675 }
3676
3677 let mut args: Vec<Arg> = vec![];
3678 let mut parse_mode = ParseMode::Arg;
3679
3680 for (index, token) in output.iter().enumerate() {
3681 let last_token = index == output.len() - 1;
3682
3683 match token {
3684 Token {
3685 contents: crate::TokenContents::Item | crate::TokenContents::AssignmentOperator,
3686 span,
3687 } => {
3688 let span = *span;
3689 let contents = working_set.get_span_contents(span).to_vec();
3690
3691 if contents == b":" {
3693 match parse_mode {
3694 ParseMode::Arg if last_token => working_set
3695 .error(ParseError::Expected("type", Span::new(span.end, span.end))),
3696 ParseMode::Arg => {
3697 parse_mode = ParseMode::Type;
3698 }
3699 ParseMode::AfterCommaArg | ParseMode::AfterType => {
3700 working_set.error(ParseError::Expected("parameter or flag", span));
3701 }
3702 ParseMode::Type | ParseMode::DefaultValue => {
3703 working_set.error(ParseError::Expected("type", span));
3705 }
3706 }
3707 }
3708 else if contents == b"=" {
3710 match parse_mode {
3711 ParseMode::Arg | ParseMode::AfterType if last_token => working_set.error(
3712 ParseError::Expected("default value", Span::new(span.end, span.end)),
3713 ),
3714 ParseMode::Arg | ParseMode::AfterType => {
3715 parse_mode = ParseMode::DefaultValue;
3716 }
3717 ParseMode::Type => {
3718 working_set.error(ParseError::Expected("type", span));
3719 }
3720 ParseMode::AfterCommaArg => {
3721 working_set.error(ParseError::Expected("parameter or flag", span));
3722 }
3723 ParseMode::DefaultValue => {
3724 working_set.error(ParseError::Expected("default value", span));
3726 }
3727 }
3728 }
3729 else if contents == b"," {
3731 match parse_mode {
3732 ParseMode::Arg | ParseMode::AfterType => {
3733 parse_mode = ParseMode::AfterCommaArg
3734 }
3735 ParseMode::AfterCommaArg => {
3736 working_set.error(ParseError::Expected("parameter or flag", span));
3737 }
3738 ParseMode::Type => {
3739 working_set.error(ParseError::Expected("type", span));
3740 }
3741 ParseMode::DefaultValue => {
3742 working_set.error(ParseError::Expected("default value", span));
3743 }
3744 }
3745 } else {
3746 match parse_mode {
3747 ParseMode::Arg | ParseMode::AfterCommaArg | ParseMode::AfterType => {
3748 if contents.starts_with(b"--") && contents.len() > 2 {
3750 let flags: Vec<_> =
3753 contents.split(|x| x == &b'(').map(|x| x.to_vec()).collect();
3754
3755 let long = String::from_utf8_lossy(&flags[0][2..]).to_string();
3756 let mut variable_name = flags[0][2..].to_vec();
3757 (0..variable_name.len()).for_each(|idx| {
3759 if variable_name[idx] == b'-' {
3760 variable_name[idx] = b'_';
3761 }
3762 });
3763
3764 if !is_variable(&variable_name) {
3765 working_set.error(ParseError::Expected(
3766 "valid variable name for this long flag",
3767 span,
3768 ))
3769 }
3770
3771 let var_id =
3772 working_set.add_variable(variable_name, span, Type::Any, false);
3773
3774 if flags.len() == 1 {
3776 args.push(Arg::Flag {
3777 flag: Flag {
3778 arg: None,
3779 desc: String::new(),
3780 long,
3781 short: None,
3782 required: false,
3783 var_id: Some(var_id),
3784 default_value: None,
3785 },
3786 type_annotated: false,
3787 });
3788 } else if flags.len() >= 3 {
3789 working_set.error(ParseError::Expected(
3790 "only one short flag alternative",
3791 span,
3792 ));
3793 } else {
3794 let short_flag = &flags[1];
3795 let short_flag = if !short_flag.starts_with(b"-")
3796 || !short_flag.ends_with(b")")
3797 {
3798 working_set.error(ParseError::Expected(
3799 "short flag alternative for the long flag",
3800 span,
3801 ));
3802 short_flag
3803 } else {
3804 &short_flag[1..(short_flag.len() - 1)]
3806 };
3807 let short_flag =
3811 String::from_utf8_lossy(short_flag).to_string();
3812 let chars: Vec<char> = short_flag.chars().collect();
3813 let long = String::from_utf8_lossy(&flags[0][2..]).to_string();
3814 let mut variable_name = flags[0][2..].to_vec();
3815
3816 (0..variable_name.len()).for_each(|idx| {
3817 if variable_name[idx] == b'-' {
3818 variable_name[idx] = b'_';
3819 }
3820 });
3821
3822 if !is_variable(&variable_name) {
3823 working_set.error(ParseError::Expected(
3824 "valid variable name for this short flag",
3825 span,
3826 ))
3827 }
3828
3829 let var_id = working_set.add_variable(
3830 variable_name,
3831 span,
3832 Type::Any,
3833 false,
3834 );
3835
3836 if chars.len() == 1 {
3837 args.push(Arg::Flag {
3838 flag: Flag {
3839 arg: None,
3840 desc: String::new(),
3841 long,
3842 short: Some(chars[0]),
3843 required: false,
3844 var_id: Some(var_id),
3845 default_value: None,
3846 },
3847 type_annotated: false,
3848 });
3849 } else {
3850 working_set.error(ParseError::Expected("short flag", span));
3851 }
3852 }
3853 parse_mode = ParseMode::Arg;
3854 }
3855 else if contents.starts_with(b"-") && contents.len() > 1 {
3857 let short_flag = &contents[1..];
3858 let short_flag = String::from_utf8_lossy(short_flag).to_string();
3859 let chars: Vec<char> = short_flag.chars().collect();
3860
3861 if chars.len() > 1 {
3862 working_set.error(ParseError::Expected("short flag", span));
3863 }
3864
3865 let mut encoded_var_name = vec![0u8; 4];
3866 let len = chars[0].encode_utf8(&mut encoded_var_name).len();
3867 let variable_name = encoded_var_name[0..len].to_vec();
3868
3869 if !is_variable(&variable_name) {
3870 working_set.error(ParseError::Expected(
3871 "valid variable name for this short flag",
3872 span,
3873 ))
3874 }
3875
3876 let var_id =
3877 working_set.add_variable(variable_name, span, Type::Any, false);
3878
3879 args.push(Arg::Flag {
3880 flag: Flag {
3881 arg: None,
3882 desc: String::new(),
3883 long: String::new(),
3884 short: Some(chars[0]),
3885 required: false,
3886 var_id: Some(var_id),
3887 default_value: None,
3888 },
3889 type_annotated: false,
3890 });
3891 parse_mode = ParseMode::Arg;
3892 }
3893 else if contents.starts_with(b"(-") {
3896 if matches!(parse_mode, ParseMode::AfterCommaArg) {
3897 working_set
3898 .error(ParseError::Expected("parameter or flag", span));
3899 }
3900 let short_flag = &contents[2..];
3901
3902 let short_flag = if !short_flag.ends_with(b")") {
3903 working_set.error(ParseError::Expected("short flag", span));
3904 short_flag
3905 } else {
3906 &short_flag[..(short_flag.len() - 1)]
3907 };
3908
3909 let short_flag = String::from_utf8_lossy(short_flag).to_string();
3910 let chars: Vec<char> = short_flag.chars().collect();
3911
3912 if chars.len() == 1 {
3913 match args.last_mut() {
3914 Some(Arg::Flag { flag, .. }) => {
3915 if flag.short.is_some() {
3916 working_set.error(ParseError::Expected(
3917 "one short flag",
3918 span,
3919 ));
3920 } else {
3921 flag.short = Some(chars[0]);
3922 }
3923 }
3924 _ => {
3925 working_set
3926 .error(ParseError::Expected("unknown flag", span));
3927 }
3928 }
3929 } else {
3930 working_set.error(ParseError::Expected("short flag", span));
3931 }
3932 }
3933 else if contents.ends_with(b"?") {
3935 let contents: Vec<_> = contents[..(contents.len() - 1)].into();
3936 let name = String::from_utf8_lossy(&contents).to_string();
3937
3938 if !is_variable(&contents) {
3939 working_set.error(ParseError::Expected(
3940 "valid variable name for this optional parameter",
3941 span,
3942 ))
3943 }
3944
3945 let var_id =
3946 working_set.add_variable(contents, span, Type::Any, false);
3947
3948 args.push(Arg::Positional {
3949 arg: PositionalArg {
3950 desc: String::new(),
3951 name,
3952 shape: SyntaxShape::Any,
3953 var_id: Some(var_id),
3954 default_value: None,
3955 },
3956 required: false,
3957 type_annotated: false,
3958 });
3959 parse_mode = ParseMode::Arg;
3960 }
3961 else if let Some(contents) = contents.strip_prefix(b"...") {
3963 let name = String::from_utf8_lossy(contents).to_string();
3964 let contents_vec: Vec<u8> = contents.to_vec();
3965
3966 if !is_variable(&contents_vec) {
3967 working_set.error(ParseError::Expected(
3968 "valid variable name for this rest parameter",
3969 span,
3970 ))
3971 }
3972
3973 let var_id =
3974 working_set.add_variable(contents_vec, span, Type::Any, false);
3975
3976 args.push(Arg::RestPositional(PositionalArg {
3977 desc: String::new(),
3978 name,
3979 shape: SyntaxShape::Any,
3980 var_id: Some(var_id),
3981 default_value: None,
3982 }));
3983 parse_mode = ParseMode::Arg;
3984 }
3985 else {
3987 let name = String::from_utf8_lossy(&contents).to_string();
3988 let contents_vec = contents.to_vec();
3989
3990 if !is_variable(&contents_vec) {
3991 working_set.error(ParseError::Expected(
3992 "valid variable name for this parameter",
3993 span,
3994 ))
3995 }
3996
3997 let var_id =
3998 working_set.add_variable(contents_vec, span, Type::Any, false);
3999
4000 args.push(Arg::Positional {
4002 arg: PositionalArg {
4003 desc: String::new(),
4004 name,
4005 shape: SyntaxShape::Any,
4006 var_id: Some(var_id),
4007 default_value: None,
4008 },
4009 required: true,
4010 type_annotated: false,
4011 });
4012 parse_mode = ParseMode::Arg;
4013 }
4014 }
4015 ParseMode::Type => {
4016 if let Some(last) = args.last_mut() {
4017 let syntax_shape = parse_shape_name(
4018 working_set,
4019 &contents,
4020 span,
4021 ShapeDescriptorUse::Argument,
4022 );
4023 match last {
4025 Arg::Positional {
4026 arg: PositionalArg { shape, var_id, .. },
4027 required: _,
4028 type_annotated,
4029 } => {
4030 working_set.set_variable_type(var_id.expect("internal error: all custom parameters must have var_ids"), syntax_shape.to_type());
4031 *shape = syntax_shape;
4032 *type_annotated = true;
4033 }
4034 Arg::RestPositional(PositionalArg {
4035 shape, var_id, ..
4036 }) => {
4037 working_set.set_variable_type(var_id.expect("internal error: all custom parameters must have var_ids"), Type::List(Box::new(syntax_shape.to_type())));
4038 *shape = syntax_shape;
4039 }
4040 Arg::Flag {
4041 flag: Flag { arg, var_id, .. },
4042 type_annotated,
4043 } => {
4044 working_set.set_variable_type(var_id.expect("internal error: all custom parameters must have var_ids"), syntax_shape.to_type());
4045 if syntax_shape == SyntaxShape::Boolean {
4046 working_set.error(ParseError::LabeledError(
4047 "Type annotations are not allowed for boolean switches.".to_string(),
4048 "Remove the `: bool` type annotation.".to_string(),
4049 span,
4050 ));
4051 }
4052 *arg = Some(syntax_shape);
4053 *type_annotated = true;
4054 }
4055 }
4056 }
4057 parse_mode = ParseMode::AfterType;
4058 }
4059 ParseMode::DefaultValue => {
4060 if let Some(last) = args.last_mut() {
4061 let expression = parse_value(working_set, span, &SyntaxShape::Any);
4062
4063 match last {
4065 Arg::Positional {
4066 arg:
4067 PositionalArg {
4068 shape,
4069 var_id,
4070 default_value,
4071 ..
4072 },
4073 required,
4074 type_annotated,
4075 } => {
4076 let var_id = var_id.expect("internal error: all custom parameters must have var_ids");
4077 let var_type = &working_set.get_variable(var_id).ty;
4078 match var_type {
4079 Type::Any => {
4080 if !*type_annotated {
4081 working_set.set_variable_type(
4082 var_id,
4083 expression.ty.clone(),
4084 );
4085 }
4086 }
4087 _ => {
4088 if !type_compatible(var_type, &expression.ty) {
4089 working_set.error(
4090 ParseError::AssignmentMismatch(
4091 "Default value wrong type".into(),
4092 format!(
4093 "expected default value to be `{var_type}`"
4094 ),
4095 expression.span,
4096 ),
4097 )
4098 }
4099 }
4100 }
4101
4102 *default_value = if let Ok(constant) =
4103 eval_constant(working_set, &expression)
4104 {
4105 Some(constant)
4106 } else {
4107 working_set.error(ParseError::NonConstantDefaultValue(
4108 expression.span,
4109 ));
4110 None
4111 };
4112
4113 if !*type_annotated {
4114 *shape = expression.ty.to_shape();
4115 }
4116 *required = false;
4117 }
4118 Arg::RestPositional(..) => {
4119 working_set.error(ParseError::AssignmentMismatch(
4120 "Rest parameter was given a default value".into(),
4121 "can't have default value".into(),
4122 expression.span,
4123 ))
4124 }
4125 Arg::Flag {
4126 flag:
4127 Flag {
4128 arg,
4129 var_id,
4130 default_value,
4131 ..
4132 },
4133 type_annotated,
4134 } => {
4135 let expression_span = expression.span;
4136
4137 *default_value = if let Ok(value) =
4138 eval_constant(working_set, &expression)
4139 {
4140 Some(value)
4141 } else {
4142 working_set.error(ParseError::NonConstantDefaultValue(
4143 expression_span,
4144 ));
4145 None
4146 };
4147
4148 let var_id = var_id.expect("internal error: all custom parameters must have var_ids");
4149 let var_type = &working_set.get_variable(var_id).ty;
4150 let expression_ty = expression.ty.clone();
4151
4152 match var_type {
4155 Type::Any => {
4156 if !*type_annotated {
4157 *arg = Some(expression_ty.to_shape());
4158 working_set
4159 .set_variable_type(var_id, expression_ty);
4160 }
4161 }
4162 t => {
4163 if !type_compatible(t, &expression_ty) {
4164 working_set.error(
4165 ParseError::AssignmentMismatch(
4166 "Default value is the wrong type"
4167 .into(),
4168 format!(
4169 "expected default value to be `{t}`"
4170 ),
4171 expression_span,
4172 ),
4173 )
4174 }
4175 }
4176 }
4177 }
4178 }
4179 }
4180 parse_mode = ParseMode::Arg;
4181 }
4182 }
4183 }
4184 }
4185 Token {
4186 contents: crate::TokenContents::Comment,
4187 span,
4188 } => {
4189 let contents = working_set.get_span_contents(Span::new(span.start + 1, span.end));
4190
4191 let mut contents = String::from_utf8_lossy(contents).to_string();
4192 contents = contents.trim().into();
4193
4194 if let Some(last) = args.last_mut() {
4195 match last {
4196 Arg::Flag { flag, .. } => {
4197 if !flag.desc.is_empty() {
4198 flag.desc.push('\n');
4199 }
4200 flag.desc.push_str(&contents);
4201 }
4202 Arg::Positional {
4203 arg: positional, ..
4204 } => {
4205 if !positional.desc.is_empty() {
4206 positional.desc.push('\n');
4207 }
4208 positional.desc.push_str(&contents);
4209 }
4210 Arg::RestPositional(positional) => {
4211 if !positional.desc.is_empty() {
4212 positional.desc.push('\n');
4213 }
4214 positional.desc.push_str(&contents);
4215 }
4216 }
4217 }
4218 }
4219 _ => {}
4220 }
4221 }
4222
4223 let mut sig = Signature::new(String::new());
4224
4225 for arg in args {
4226 match arg {
4227 Arg::Positional {
4228 arg: positional,
4229 required,
4230 ..
4231 } => {
4232 if required {
4233 if !sig.optional_positional.is_empty() {
4234 working_set.error(ParseError::RequiredAfterOptional(
4235 positional.name.clone(),
4236 span,
4237 ))
4238 }
4239 sig.required_positional.push(positional)
4240 } else {
4241 sig.optional_positional.push(positional)
4242 }
4243 }
4244 Arg::Flag { flag, .. } => sig.named.push(flag),
4245 Arg::RestPositional(positional) => {
4246 if positional.name.is_empty() {
4247 working_set.error(ParseError::RestNeedsName(span))
4248 } else if sig.rest_positional.is_none() {
4249 sig.rest_positional = Some(PositionalArg {
4250 name: positional.name,
4251 ..positional
4252 })
4253 } else {
4254 working_set.error(ParseError::MultipleRestParams(span))
4256 }
4257 }
4258 }
4259 }
4260
4261 Box::new(sig)
4262}
4263
4264pub fn parse_list_expression(
4265 working_set: &mut StateWorkingSet,
4266 span: Span,
4267 element_shape: &SyntaxShape,
4268) -> Expression {
4269 let bytes = working_set.get_span_contents(span);
4270
4271 let mut start = span.start;
4272 let mut end = span.end;
4273
4274 if bytes.starts_with(b"[") {
4275 start += 1;
4276 }
4277 if bytes.ends_with(b"]") {
4278 end -= 1;
4279 } else {
4280 working_set.error(ParseError::Unclosed("]".into(), Span::new(end, end)));
4281 }
4282
4283 let inner_span = Span::new(start, end);
4284 let source = working_set.get_span_contents(inner_span);
4285
4286 let (output, err) = lex(source, inner_span.start, &[b'\n', b'\r', b','], &[], true);
4287 if let Some(err) = err {
4288 working_set.error(err)
4289 }
4290
4291 let (mut output, err) = lite_parse(&output, working_set);
4292 if let Some(err) = err {
4293 working_set.error(err)
4294 }
4295
4296 let mut args = vec![];
4297
4298 let mut contained_type: Option<Type> = None;
4299
4300 if !output.block.is_empty() {
4301 for mut command in output.block.remove(0).commands {
4302 let mut spans_idx = 0;
4303
4304 while spans_idx < command.parts.len() {
4305 let curr_span = command.parts[spans_idx];
4306 let curr_tok = working_set.get_span_contents(curr_span);
4307 let (arg, ty) = if curr_tok.starts_with(b"...")
4308 && curr_tok.len() > 3
4309 && (curr_tok[3] == b'$' || curr_tok[3] == b'[' || curr_tok[3] == b'(')
4310 {
4311 command.parts[spans_idx] = Span::new(curr_span.start + 3, curr_span.end);
4314 let spread_arg = parse_multispan_value(
4315 working_set,
4316 &command.parts,
4317 &mut spans_idx,
4318 &SyntaxShape::List(Box::new(element_shape.clone())),
4319 );
4320 let elem_ty = match &spread_arg.ty {
4321 Type::List(elem_ty) => *elem_ty.clone(),
4322 _ => Type::Any,
4323 };
4324 let span = Span::new(curr_span.start, curr_span.start + 3);
4325 (ListItem::Spread(span, spread_arg), elem_ty)
4326 } else {
4327 let arg = parse_multispan_value(
4328 working_set,
4329 &command.parts,
4330 &mut spans_idx,
4331 element_shape,
4332 );
4333 let ty = arg.ty.clone();
4334 (ListItem::Item(arg), ty)
4335 };
4336
4337 if let Some(ref ctype) = contained_type {
4338 if *ctype != ty {
4339 contained_type = Some(Type::Any);
4340 }
4341 } else {
4342 contained_type = Some(ty);
4343 }
4344
4345 args.push(arg);
4346
4347 spans_idx += 1;
4348 }
4349 }
4350 }
4351
4352 Expression::new(
4353 working_set,
4354 Expr::List(args),
4355 span,
4356 Type::List(Box::new(if let Some(ty) = contained_type {
4357 ty
4358 } else {
4359 Type::Any
4360 })),
4361 )
4362}
4363
4364fn parse_table_row(
4365 working_set: &mut StateWorkingSet,
4366 span: Span,
4367) -> Result<(Vec<Expression>, Span), Span> {
4368 let list = parse_list_expression(working_set, span, &SyntaxShape::Any);
4369 let Expression {
4370 expr: Expr::List(list),
4371 span,
4372 ..
4373 } = list
4374 else {
4375 unreachable!("the item must be a list")
4376 };
4377
4378 list.into_iter()
4379 .map(|item| match item {
4380 ListItem::Item(expr) => Ok(expr),
4381 ListItem::Spread(_, spread) => Err(spread.span),
4382 })
4383 .collect::<Result<_, _>>()
4384 .map(|exprs| (exprs, span))
4385}
4386
4387fn parse_table_expression(
4388 working_set: &mut StateWorkingSet,
4389 span: Span,
4390 list_element_shape: &SyntaxShape,
4391) -> Expression {
4392 let bytes = working_set.get_span_contents(span);
4393 let inner_span = {
4394 let start = if bytes.starts_with(b"[") {
4395 span.start + 1
4396 } else {
4397 span.start
4398 };
4399
4400 let end = if bytes.ends_with(b"]") {
4401 span.end - 1
4402 } else {
4403 let end = span.end;
4404 working_set.error(ParseError::Unclosed("]".into(), Span::new(end, end)));
4405 span.end
4406 };
4407
4408 Span::new(start, end)
4409 };
4410
4411 let source = working_set.get_span_contents(inner_span);
4412 let (tokens, err) = lex(source, inner_span.start, &[b'\n', b'\r', b','], &[], true);
4413 if let Some(err) = err {
4414 working_set.error(err);
4415 }
4416
4417 let [first, second, rest @ ..] = &tokens[..] else {
4420 return parse_list_expression(working_set, span, list_element_shape);
4421 };
4422 if !working_set.get_span_contents(first.span).starts_with(b"[")
4423 || second.contents != TokenContents::Semicolon
4424 || rest.is_empty()
4425 {
4426 return parse_list_expression(working_set, span, list_element_shape);
4427 };
4428 let head = parse_table_row(working_set, first.span);
4429
4430 let errors = working_set.parse_errors.len();
4431
4432 let (head, rows) = match head {
4433 Ok((head, _)) => {
4434 let rows = rest
4435 .iter()
4436 .filter_map(|it| {
4437 use std::cmp::Ordering;
4438
4439 match working_set.get_span_contents(it.span) {
4440 b"," => None,
4441 text if !text.starts_with(b"[") => {
4442 let err = ParseError::LabeledErrorWithHelp {
4443 error: String::from("Table item not list"),
4444 label: String::from("not a list"),
4445 span: it.span,
4446 help: String::from("All table items must be lists"),
4447 };
4448 working_set.error(err);
4449 None
4450 }
4451 _ => match parse_table_row(working_set, it.span) {
4452 Ok((list, span)) => {
4453 match list.len().cmp(&head.len()) {
4454 Ordering::Less => {
4455 let err = ParseError::MissingColumns(head.len(), span);
4456 working_set.error(err);
4457 }
4458 Ordering::Greater => {
4459 let span = {
4460 let start = list[head.len()].span.start;
4461 let end = span.end;
4462 Span::new(start, end)
4463 };
4464 let err = ParseError::ExtraColumns(head.len(), span);
4465 working_set.error(err);
4466 }
4467 Ordering::Equal => {}
4468 }
4469 Some(list)
4470 }
4471 Err(span) => {
4472 let err = ParseError::LabeledError(
4473 String::from("Cannot spread in a table row"),
4474 String::from("invalid spread here"),
4475 span,
4476 );
4477 working_set.error(err);
4478 None
4479 }
4480 },
4481 }
4482 })
4483 .collect();
4484
4485 (head, rows)
4486 }
4487 Err(span) => {
4488 let err = ParseError::LabeledError(
4489 String::from("Cannot spread in a table row"),
4490 String::from("invalid spread here"),
4491 span,
4492 );
4493 working_set.error(err);
4494 (Vec::new(), Vec::new())
4495 }
4496 };
4497
4498 let ty = if working_set.parse_errors.len() == errors {
4499 let (ty, errs) = table_type(&head, &rows);
4500 working_set.parse_errors.extend(errs);
4501 ty
4502 } else {
4503 Type::table()
4504 };
4505
4506 let table = Table {
4507 columns: head.into(),
4508 rows: rows.into_iter().map(Into::into).collect(),
4509 };
4510
4511 Expression::new(working_set, Expr::Table(table), span, ty)
4512}
4513
4514fn table_type(head: &[Expression], rows: &[Vec<Expression>]) -> (Type, Vec<ParseError>) {
4515 let mut errors = vec![];
4516 let mut rows = rows.to_vec();
4517 let mut mk_ty = || -> Type {
4518 rows.iter_mut()
4519 .map(|row| row.pop().map(|x| x.ty).unwrap_or_default())
4520 .reduce(|acc, ty| -> Type {
4521 if type_compatible(&acc, &ty) {
4522 ty
4523 } else {
4524 Type::Any
4525 }
4526 })
4527 .unwrap_or_default()
4528 };
4529
4530 let mk_error = |span| ParseError::LabeledErrorWithHelp {
4531 error: "Table column name not string".into(),
4532 label: "must be a string".into(),
4533 help: "Table column names should be able to be converted into strings".into(),
4534 span,
4535 };
4536
4537 let mut ty = head
4538 .iter()
4539 .rev()
4540 .map(|expr| {
4541 if let Some(str) = expr.as_string() {
4542 str
4543 } else {
4544 errors.push(mk_error(expr.span));
4545 String::from("{ column }")
4546 }
4547 })
4548 .map(|title| (title, mk_ty()))
4549 .collect_vec();
4550
4551 ty.reverse();
4552
4553 (Type::Table(ty.into()), errors)
4554}
4555
4556pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) -> Expression {
4557 trace!("parsing: block expression");
4558
4559 let bytes = working_set.get_span_contents(span);
4560
4561 let mut start = span.start;
4562 let mut end = span.end;
4563
4564 if bytes.starts_with(b"{") {
4565 start += 1;
4566 } else {
4567 working_set.error(ParseError::Expected("block", span));
4568 return garbage(working_set, span);
4569 }
4570 if bytes.ends_with(b"}") {
4571 end -= 1;
4572 } else {
4573 working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
4574 }
4575
4576 let inner_span = Span::new(start, end);
4577
4578 let source = working_set.get_span_contents(inner_span);
4579
4580 let (output, err) = lex(source, start, &[], &[], false);
4581 if let Some(err) = err {
4582 working_set.error(err);
4583 }
4584
4585 working_set.enter_scope();
4586
4587 let (signature, amt_to_skip): (Option<(Box<Signature>, Span)>, usize) = match output.first() {
4589 Some(Token {
4590 contents: TokenContents::Pipe,
4591 span,
4592 }) => {
4593 working_set.error(ParseError::Expected("block but found closure", *span));
4594 (None, 0)
4595 }
4596 _ => (None, 0),
4597 };
4598
4599 let mut output = parse_block(working_set, &output[amt_to_skip..], span, false, false);
4600
4601 if let Some(signature) = signature {
4602 output.signature = signature.0;
4603 }
4604
4605 output.span = Some(span);
4606
4607 working_set.exit_scope();
4608
4609 let block_id = working_set.add_block(Arc::new(output));
4610
4611 Expression::new(working_set, Expr::Block(block_id), span, Type::Any)
4612}
4613
4614pub fn parse_match_block_expression(working_set: &mut StateWorkingSet, span: Span) -> Expression {
4615 let bytes = working_set.get_span_contents(span);
4616
4617 let mut start = span.start;
4618 let mut end = span.end;
4619
4620 if bytes.starts_with(b"{") {
4621 start += 1;
4622 } else {
4623 working_set.error(ParseError::Expected("closure", span));
4624 return garbage(working_set, span);
4625 }
4626 if bytes.ends_with(b"}") {
4627 end -= 1;
4628 } else {
4629 working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
4630 }
4631
4632 let inner_span = Span::new(start, end);
4633
4634 let source = working_set.get_span_contents(inner_span);
4635
4636 let (output, err) = lex(source, start, &[b' ', b'\r', b'\n', b',', b'|'], &[], true);
4637 if let Some(err) = err {
4638 working_set.error(err);
4639 }
4640
4641 let mut position = 0;
4642
4643 let mut output_matches = vec![];
4644
4645 while position < output.len() {
4646 working_set.enter_scope();
4649
4650 let mut pattern = parse_pattern(working_set, output[position].span);
4652
4653 position += 1;
4654
4655 if position >= output.len() {
4656 working_set.error(ParseError::Mismatch(
4657 "=>".into(),
4658 "end of input".into(),
4659 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4660 ));
4661
4662 working_set.exit_scope();
4663 break;
4664 }
4665
4666 let mut connector = working_set.get_span_contents(output[position].span);
4667
4668 if connector == b"|" && position < output.len() {
4670 let mut or_pattern = vec![pattern];
4671
4672 while connector == b"|" && position < output.len() {
4673 connector = b"";
4674
4675 position += 1;
4676
4677 if position >= output.len() {
4678 working_set.error(ParseError::Mismatch(
4679 "pattern".into(),
4680 "end of input".into(),
4681 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4682 ));
4683 break;
4684 }
4685
4686 let pattern = parse_pattern(working_set, output[position].span);
4687 or_pattern.push(pattern);
4688
4689 position += 1;
4690 if position >= output.len() {
4691 working_set.error(ParseError::Mismatch(
4692 "=>".into(),
4693 "end of input".into(),
4694 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4695 ));
4696 break;
4697 } else {
4698 connector = working_set.get_span_contents(output[position].span);
4699 }
4700 }
4701
4702 let start = or_pattern
4703 .first()
4704 .expect("internal error: unexpected state of or-pattern")
4705 .span
4706 .start;
4707 let end = or_pattern
4708 .last()
4709 .expect("internal error: unexpected state of or-pattern")
4710 .span
4711 .end;
4712
4713 pattern = MatchPattern {
4714 pattern: Pattern::Or(or_pattern),
4715 guard: None,
4716 span: Span::new(start, end),
4717 }
4718 } else if connector == b"if" {
4720 let if_end = {
4721 let end = output[position].span.end;
4722 Span::new(end, end)
4723 };
4724
4725 position += 1;
4726
4727 let mk_err = || ParseError::LabeledErrorWithHelp {
4728 error: "Match guard without an expression".into(),
4729 label: "expected an expression".into(),
4730 help: "The `if` keyword must be followed with an expression".into(),
4731 span: if_end,
4732 };
4733
4734 if output.get(position).is_none() {
4735 working_set.error(mk_err());
4736 return garbage(working_set, span);
4737 };
4738
4739 let (tokens, found) = if let Some((pos, _)) = output[position..]
4740 .iter()
4741 .find_position(|t| working_set.get_span_contents(t.span) == b"=>")
4742 {
4743 if position + pos == position {
4744 working_set.error(mk_err());
4745 return garbage(working_set, span);
4746 }
4747
4748 (&output[position..position + pos], true)
4749 } else {
4750 (&output[position..], false)
4751 };
4752
4753 let mut start = 0;
4754 let guard = parse_multispan_value(
4755 working_set,
4756 &tokens.iter().map(|tok| tok.span).collect_vec(),
4757 &mut start,
4758 &SyntaxShape::MathExpression,
4759 );
4760
4761 pattern.guard = Some(Box::new(guard));
4762 position += if found { start + 1 } else { start };
4763 connector = working_set.get_span_contents(output[position].span);
4764 }
4765 if connector != b"=>" {
4767 working_set.error(ParseError::Mismatch(
4768 "=>".into(),
4769 "end of input".into(),
4770 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4771 ));
4772 } else {
4773 position += 1;
4774 }
4775
4776 if position >= output.len() {
4778 working_set.error(ParseError::Mismatch(
4779 "match result".into(),
4780 "end of input".into(),
4781 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4782 ));
4783
4784 working_set.exit_scope();
4785 break;
4786 }
4787
4788 let result = parse_multispan_value(
4789 working_set,
4790 &[output[position].span],
4791 &mut 0,
4792 &SyntaxShape::OneOf(vec![SyntaxShape::Block, SyntaxShape::Expression]),
4793 );
4794 position += 1;
4795 working_set.exit_scope();
4796
4797 output_matches.push((pattern, result));
4798 }
4799
4800 Expression::new(
4801 working_set,
4802 Expr::MatchBlock(output_matches),
4803 span,
4804 Type::Any,
4805 )
4806}
4807
4808pub fn parse_closure_expression(
4809 working_set: &mut StateWorkingSet,
4810 shape: &SyntaxShape,
4811 span: Span,
4812) -> Expression {
4813 trace!("parsing: closure expression");
4814
4815 let bytes = working_set.get_span_contents(span);
4816
4817 let mut start = span.start;
4818 let mut end = span.end;
4819
4820 if bytes.starts_with(b"{") {
4821 start += 1;
4822 } else {
4823 working_set.error(ParseError::Expected("closure", span));
4824 return garbage(working_set, span);
4825 }
4826 if bytes.ends_with(b"}") {
4827 end -= 1;
4828 } else {
4829 working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
4830 }
4831
4832 let inner_span = Span::new(start, end);
4833
4834 let source = working_set.get_span_contents(inner_span);
4835
4836 let (output, err) = lex(source, start, &[], &[], false);
4837 if let Some(err) = err {
4838 working_set.error(err);
4839 }
4840
4841 working_set.enter_scope();
4842
4843 let (signature, amt_to_skip): (Option<(Box<Signature>, Span)>, usize) = match output.first() {
4845 Some(Token {
4846 contents: TokenContents::Pipe,
4847 span,
4848 }) => {
4849 let start_point = span.start;
4851 let mut token_iter = output.iter().enumerate().skip(1);
4852 let mut end_span = None;
4853 let mut amt_to_skip = 1;
4854
4855 for token in &mut token_iter {
4856 if let Token {
4857 contents: TokenContents::Pipe,
4858 span,
4859 } = token.1
4860 {
4861 end_span = Some(span);
4862 amt_to_skip += token.0;
4863 break;
4864 }
4865 }
4866
4867 let end_point = if let Some(span) = end_span {
4868 span.end
4869 } else {
4870 working_set.error(ParseError::Unclosed("|".into(), Span::new(end, end)));
4871 end
4872 };
4873
4874 let signature_span = Span::new(start_point, end_point);
4875 let signature = parse_signature_helper(working_set, signature_span);
4876
4877 (Some((signature, signature_span)), amt_to_skip)
4878 }
4879 Some(Token {
4880 contents: TokenContents::PipePipe,
4881 span,
4882 }) => (
4883 Some((Box::new(Signature::new("closure".to_string())), *span)),
4884 1,
4885 ),
4886 _ => (None, 0),
4887 };
4888
4889 if let SyntaxShape::Closure(Some(v)) = shape {
4891 if let Some((sig, sig_span)) = &signature {
4892 if sig.num_positionals() > v.len() {
4893 working_set.error(ParseError::ExpectedWithStringMsg(
4894 format!(
4895 "{} closure parameter{}",
4896 v.len(),
4897 if v.len() > 1 { "s" } else { "" }
4898 ),
4899 *sig_span,
4900 ));
4901 }
4902
4903 for (expected, PositionalArg { name, shape, .. }) in
4904 v.iter().zip(sig.required_positional.iter())
4905 {
4906 if expected != shape && *shape != SyntaxShape::Any {
4907 working_set.error(ParseError::ParameterMismatchType(
4908 name.to_owned(),
4909 expected.to_string(),
4910 shape.to_string(),
4911 *sig_span,
4912 ));
4913 }
4914 }
4915 }
4916 }
4917
4918 let mut output = parse_block(working_set, &output[amt_to_skip..], span, false, false);
4919
4920 if let Some(signature) = signature {
4921 output.signature = signature.0;
4922 }
4923
4924 output.span = Some(span);
4925
4926 working_set.exit_scope();
4927
4928 let block_id = working_set.add_block(Arc::new(output));
4929
4930 Expression::new(working_set, Expr::Closure(block_id), span, Type::Closure)
4931}
4932
4933pub fn parse_value(
4934 working_set: &mut StateWorkingSet,
4935 span: Span,
4936 shape: &SyntaxShape,
4937) -> Expression {
4938 trace!("parsing: value: {}", shape);
4939
4940 let bytes = working_set.get_span_contents(span);
4941
4942 if bytes.is_empty() {
4943 working_set.error(ParseError::IncompleteParser(span));
4944 return garbage(working_set, span);
4945 }
4946
4947 match bytes {
4949 b"true" => {
4950 if matches!(shape, SyntaxShape::Boolean) || matches!(shape, SyntaxShape::Any) {
4951 return Expression::new(working_set, Expr::Bool(true), span, Type::Bool);
4952 } else {
4953 working_set.error(ParseError::Expected("non-boolean value", span));
4954 return Expression::garbage(working_set, span);
4955 }
4956 }
4957 b"false" => {
4958 if matches!(shape, SyntaxShape::Boolean) || matches!(shape, SyntaxShape::Any) {
4959 return Expression::new(working_set, Expr::Bool(false), span, Type::Bool);
4960 } else {
4961 working_set.error(ParseError::Expected("non-boolean value", span));
4962 return Expression::garbage(working_set, span);
4963 }
4964 }
4965 b"null" => {
4966 return Expression::new(working_set, Expr::Nothing, span, Type::Nothing);
4967 }
4968 b"-inf" | b"inf" | b"NaN" => {
4969 return parse_float(working_set, span);
4970 }
4971 _ => {}
4972 }
4973
4974 match bytes[0] {
4975 b'$' => return parse_dollar_expr(working_set, span),
4976 b'(' => return parse_paren_expr(working_set, span, shape),
4977 b'{' => return parse_brace_expr(working_set, span, shape),
4978 b'[' => match shape {
4979 SyntaxShape::Any
4980 | SyntaxShape::List(_)
4981 | SyntaxShape::Table(_)
4982 | SyntaxShape::Signature
4983 | SyntaxShape::Filepath
4984 | SyntaxShape::String
4985 | SyntaxShape::GlobPattern
4986 | SyntaxShape::ExternalArgument => {}
4987 SyntaxShape::OneOf(possible_shapes) => {
4988 if !possible_shapes
4989 .iter()
4990 .any(|s| matches!(s, SyntaxShape::List(_)))
4991 {
4992 working_set.error(ParseError::Expected("non-[] value", span));
4993 return Expression::garbage(working_set, span);
4994 }
4995 }
4996 _ => {
4997 working_set.error(ParseError::Expected("non-[] value", span));
4998 return Expression::garbage(working_set, span);
4999 }
5000 },
5001 b'r' if bytes.len() > 1 && bytes[1] == b'#' => {
5002 return parse_raw_string(working_set, span);
5003 }
5004 _ => {}
5005 }
5006
5007 match shape {
5008 SyntaxShape::CompleterWrapper(shape, custom_completion) => {
5009 let mut expression = parse_value(working_set, span, shape);
5010 expression.custom_completion = Some(*custom_completion);
5011 expression
5012 }
5013 SyntaxShape::Number => parse_number(working_set, span),
5014 SyntaxShape::Float => parse_float(working_set, span),
5015 SyntaxShape::Int => parse_int(working_set, span),
5016 SyntaxShape::Duration => parse_duration(working_set, span),
5017 SyntaxShape::DateTime => parse_datetime(working_set, span),
5018 SyntaxShape::Filesize => parse_filesize(working_set, span),
5019 SyntaxShape::Range => {
5020 parse_range(working_set, span).unwrap_or_else(|| garbage(working_set, span))
5021 }
5022 SyntaxShape::Filepath => parse_filepath(working_set, span),
5023 SyntaxShape::Directory => parse_directory(working_set, span),
5024 SyntaxShape::GlobPattern => parse_glob_pattern(working_set, span),
5025 SyntaxShape::String => parse_string(working_set, span),
5026 SyntaxShape::Binary => parse_binary(working_set, span),
5027 SyntaxShape::Signature => {
5028 if bytes.starts_with(b"[") {
5029 parse_signature(working_set, span)
5030 } else {
5031 working_set.error(ParseError::Expected("signature", span));
5032
5033 Expression::garbage(working_set, span)
5034 }
5035 }
5036 SyntaxShape::List(elem) => {
5037 if bytes.starts_with(b"[") {
5038 parse_table_expression(working_set, span, elem)
5039 } else {
5040 working_set.error(ParseError::Expected("list", span));
5041
5042 Expression::garbage(working_set, span)
5043 }
5044 }
5045 SyntaxShape::Table(_) => {
5046 if bytes.starts_with(b"[") {
5047 parse_table_expression(working_set, span, &SyntaxShape::Any)
5048 } else {
5049 working_set.error(ParseError::Expected("table", span));
5050
5051 Expression::garbage(working_set, span)
5052 }
5053 }
5054 SyntaxShape::CellPath => parse_simple_cell_path(working_set, span),
5055 SyntaxShape::Boolean => {
5056 if bytes == b"true" || bytes == b"false" {
5058 Expression::new(working_set, Expr::Bool(true), span, Type::Bool)
5059 } else {
5060 working_set.error(ParseError::Expected("bool", span));
5061
5062 Expression::garbage(working_set, span)
5063 }
5064 }
5065
5066 SyntaxShape::Block | SyntaxShape::Closure(..) | SyntaxShape::Record(_) => {
5069 working_set.error(ParseError::Expected("block, closure or record", span));
5070
5071 Expression::garbage(working_set, span)
5072 }
5073
5074 SyntaxShape::ExternalArgument => parse_regular_external_arg(working_set, span),
5075 SyntaxShape::OneOf(possible_shapes) => {
5076 parse_oneof(working_set, &[span], &mut 0, possible_shapes, false)
5077 }
5078
5079 SyntaxShape::Any => {
5080 if bytes.starts_with(b"[") {
5081 parse_full_cell_path(working_set, None, span)
5083 } else {
5084 let shapes = [
5085 SyntaxShape::Binary,
5086 SyntaxShape::Range,
5087 SyntaxShape::Filesize,
5088 SyntaxShape::Duration,
5089 SyntaxShape::DateTime,
5090 SyntaxShape::Int,
5091 SyntaxShape::Number,
5092 SyntaxShape::String,
5093 ];
5094 for shape in shapes.iter() {
5095 let starting_error_count = working_set.parse_errors.len();
5096
5097 let s = parse_value(working_set, span, shape);
5098
5099 if starting_error_count == working_set.parse_errors.len() {
5100 return s;
5101 } else {
5102 match working_set.parse_errors.get(starting_error_count) {
5103 Some(
5104 ParseError::Expected(_, _)
5105 | ParseError::ExpectedWithStringMsg(_, _),
5106 ) => {
5107 working_set.parse_errors.truncate(starting_error_count);
5108 continue;
5109 }
5110 _ => {
5111 return s;
5112 }
5113 }
5114 }
5115 }
5116 working_set.error(ParseError::Expected("any shape", span));
5117 garbage(working_set, span)
5118 }
5119 }
5120 x => {
5121 working_set.error(ParseError::ExpectedWithStringMsg(
5122 x.to_type().to_string(),
5123 span,
5124 ));
5125 garbage(working_set, span)
5126 }
5127 }
5128}
5129
5130pub fn parse_assignment_operator(working_set: &mut StateWorkingSet, span: Span) -> Expression {
5131 let contents = working_set.get_span_contents(span);
5132
5133 let operator = match contents {
5134 b"=" => Operator::Assignment(Assignment::Assign),
5135 b"+=" => Operator::Assignment(Assignment::AddAssign),
5136 b"-=" => Operator::Assignment(Assignment::SubtractAssign),
5137 b"*=" => Operator::Assignment(Assignment::MultiplyAssign),
5138 b"/=" => Operator::Assignment(Assignment::DivideAssign),
5139 b"++=" => Operator::Assignment(Assignment::ConcatenateAssign),
5140 _ => {
5141 working_set.error(ParseError::Expected("assignment operator", span));
5142 return garbage(working_set, span);
5143 }
5144 };
5145
5146 Expression::new(working_set, Expr::Operator(operator), span, Type::Any)
5147}
5148
5149pub fn parse_assignment_expression(
5150 working_set: &mut StateWorkingSet,
5151 spans: &[Span],
5152) -> Expression {
5153 trace!("parsing: assignment expression");
5154 let expr_span = Span::concat(spans);
5155
5156 let Some(op_index) = spans
5158 .iter()
5159 .position(|span| is_assignment_operator(working_set.get_span_contents(*span)))
5160 else {
5161 working_set.error(ParseError::Expected("assignment expression", expr_span));
5162 return garbage(working_set, expr_span);
5163 };
5164
5165 let lhs_spans = &spans[0..op_index];
5166 let op_span = spans[op_index];
5167 let rhs_spans = &spans[(op_index + 1)..];
5168
5169 if lhs_spans.is_empty() {
5170 working_set.error(ParseError::Expected(
5171 "left hand side of assignment",
5172 op_span,
5173 ));
5174 return garbage(working_set, expr_span);
5175 }
5176
5177 if rhs_spans.is_empty() {
5178 working_set.error(ParseError::Expected(
5179 "right hand side of assignment",
5180 op_span,
5181 ));
5182 return garbage(working_set, expr_span);
5183 }
5184
5185 let mut lhs = parse_expression(working_set, lhs_spans);
5187 match &lhs.expr {
5189 Expr::FullCellPath(p) => {
5190 if let Expr::Var(var_id) = p.head.expr {
5191 if var_id != nu_protocol::ENV_VARIABLE_ID
5192 && !working_set.get_variable(var_id).mutable
5193 {
5194 working_set.error(ParseError::AssignmentRequiresMutableVar(lhs.span))
5195 }
5196 }
5197 }
5198 _ => working_set.error(ParseError::AssignmentRequiresVar(lhs.span)),
5199 }
5200
5201 let mut operator = parse_assignment_operator(working_set, op_span);
5202
5203 let rhs_span = Span::concat(rhs_spans);
5205
5206 let (rhs_tokens, rhs_error) = lex(
5207 working_set.get_span_contents(rhs_span),
5208 rhs_span.start,
5209 &[],
5210 &[],
5211 true,
5212 );
5213 working_set.parse_errors.extend(rhs_error);
5214
5215 trace!("parsing: assignment right-hand side subexpression");
5216 let rhs_block = parse_block(working_set, &rhs_tokens, rhs_span, false, true);
5217 let rhs_ty = rhs_block.output_type();
5218
5219 if let Some(Expr::ExternalCall(head, ..)) = rhs_block
5223 .pipelines
5224 .first()
5225 .and_then(|pipeline| pipeline.elements.first())
5226 .map(|element| &element.expr.expr)
5227 {
5228 let contents = working_set.get_span_contents(Span {
5229 start: head.span.start - 1,
5230 end: head.span.end,
5231 });
5232 if !contents.starts_with(b"^") {
5233 working_set.parse_errors.push(ParseError::LabeledErrorWithHelp {
5234 error: "External command calls must be explicit in assignments".into(),
5235 label: "add a caret (^) before the command name if you intended to run and capture its output".into(),
5236 help: "the parsing of assignments was changed in 0.97.0, and this would have previously been treated as a string. Alternatively, quote the string with single or double quotes to avoid it being interpreted as a command name. This restriction may be removed in a future release.".into(),
5237 span: head.span,
5238 });
5239 }
5240 }
5241
5242 let rhs_block_id = working_set.add_block(Arc::new(rhs_block));
5243 let mut rhs = Expression::new(
5244 working_set,
5245 Expr::Subexpression(rhs_block_id),
5246 rhs_span,
5247 rhs_ty,
5248 );
5249
5250 let (result_ty, err) = math_result_type(working_set, &mut lhs, &mut operator, &mut rhs);
5251 if let Some(err) = err {
5252 working_set.parse_errors.push(err);
5253 }
5254
5255 Expression::new(
5256 working_set,
5257 Expr::BinaryOp(Box::new(lhs), Box::new(operator), Box::new(rhs)),
5258 expr_span,
5259 result_ty,
5260 )
5261}
5262
5263pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expression {
5264 let contents = working_set.get_span_contents(span);
5265
5266 let operator = match contents {
5267 b"==" => Operator::Comparison(Comparison::Equal),
5268 b"!=" => Operator::Comparison(Comparison::NotEqual),
5269 b"<" => Operator::Comparison(Comparison::LessThan),
5270 b"<=" => Operator::Comparison(Comparison::LessThanOrEqual),
5271 b">" => Operator::Comparison(Comparison::GreaterThan),
5272 b">=" => Operator::Comparison(Comparison::GreaterThanOrEqual),
5273 b"=~" | b"like" => Operator::Comparison(Comparison::RegexMatch),
5274 b"!~" | b"not-like" => Operator::Comparison(Comparison::NotRegexMatch),
5275 b"in" => Operator::Comparison(Comparison::In),
5276 b"not-in" => Operator::Comparison(Comparison::NotIn),
5277 b"has" => Operator::Comparison(Comparison::Has),
5278 b"not-has" => Operator::Comparison(Comparison::NotHas),
5279 b"starts-with" => Operator::Comparison(Comparison::StartsWith),
5280 b"ends-with" => Operator::Comparison(Comparison::EndsWith),
5281 b"+" => Operator::Math(Math::Add),
5282 b"-" => Operator::Math(Math::Subtract),
5283 b"*" => Operator::Math(Math::Multiply),
5284 b"/" => Operator::Math(Math::Divide),
5285 b"//" => Operator::Math(Math::FloorDivide),
5286 b"mod" => Operator::Math(Math::Modulo),
5287 b"**" => Operator::Math(Math::Pow),
5288 b"++" => Operator::Math(Math::Concatenate),
5289 b"bit-or" => Operator::Bits(Bits::BitOr),
5290 b"bit-xor" => Operator::Bits(Bits::BitXor),
5291 b"bit-and" => Operator::Bits(Bits::BitAnd),
5292 b"bit-shl" => Operator::Bits(Bits::ShiftLeft),
5293 b"bit-shr" => Operator::Bits(Bits::ShiftRight),
5294 b"or" => Operator::Boolean(Boolean::Or),
5295 b"xor" => Operator::Boolean(Boolean::Xor),
5296 b"and" => Operator::Boolean(Boolean::And),
5297 pow @ (b"^" | b"pow") => {
5299 working_set.error(ParseError::UnknownOperator(
5300 match pow {
5301 b"^" => "^",
5302 b"pow" => "pow",
5303 _ => unreachable!(),
5304 },
5305 "Use '**' for exponentiation or 'bit-xor' for bitwise XOR.",
5306 span,
5307 ));
5308 return garbage(working_set, span);
5309 }
5310 equality @ (b"is" | b"===") => {
5311 working_set.error(ParseError::UnknownOperator(
5312 match equality {
5313 b"is" => "is",
5314 b"===" => "===",
5315 _ => unreachable!(),
5316 },
5317 "Did you mean '=='?",
5318 span,
5319 ));
5320 return garbage(working_set, span);
5321 }
5322 b"contains" => {
5323 working_set.error(ParseError::UnknownOperator(
5324 "contains",
5325 "Did you mean 'has'?",
5326 span,
5327 ));
5328 return garbage(working_set, span);
5329 }
5330 b"%" => {
5331 working_set.error(ParseError::UnknownOperator(
5332 "%",
5333 "Did you mean 'mod'?",
5334 span,
5335 ));
5336 return garbage(working_set, span);
5337 }
5338 b"&" => {
5339 working_set.error(ParseError::UnknownOperator(
5340 "&",
5341 "Did you mean 'bit-and'?",
5342 span,
5343 ));
5344 return garbage(working_set, span);
5345 }
5346 b"<<" => {
5347 working_set.error(ParseError::UnknownOperator(
5348 "<<",
5349 "Did you mean 'bit-shl'?",
5350 span,
5351 ));
5352 return garbage(working_set, span);
5353 }
5354 b">>" => {
5355 working_set.error(ParseError::UnknownOperator(
5356 ">>",
5357 "Did you mean 'bit-shr'?",
5358 span,
5359 ));
5360 return garbage(working_set, span);
5361 }
5362 bits @ (b"bits-and" | b"bits-xor" | b"bits-or" | b"bits-shl" | b"bits-shr") => {
5363 working_set.error(ParseError::UnknownOperator(
5364 match bits {
5365 b"bits-and" => "bits-and",
5366 b"bits-xor" => "bits-xor",
5367 b"bits-or" => "bits-or",
5368 b"bits-shl" => "bits-shl",
5369 b"bits-shr" => "bits-shr",
5370 _ => unreachable!(),
5371 },
5372 match bits {
5373 b"bits-and" => "Did you mean 'bit-and'?",
5374 b"bits-xor" => "Did you mean 'bit-xor'?",
5375 b"bits-or" => "Did you mean 'bit-or'?",
5376 b"bits-shl" => "Did you mean 'bit-shl'?",
5377 b"bits-shr" => "Did you mean 'bit-shr'?",
5378 _ => unreachable!(),
5379 },
5380 span,
5381 ));
5382 return garbage(working_set, span);
5383 }
5384 op if is_assignment_operator(op) => {
5385 working_set.error(ParseError::Expected("a non-assignment operator", span));
5386 return garbage(working_set, span);
5387 }
5388 _ => {
5389 working_set.error(ParseError::Expected("operator", span));
5390 return garbage(working_set, span);
5391 }
5392 };
5393
5394 Expression::new(working_set, Expr::Operator(operator), span, Type::Any)
5395}
5396
5397pub fn parse_math_expression(
5398 working_set: &mut StateWorkingSet,
5399 spans: &[Span],
5400 lhs_row_var_id: Option<VarId>,
5401) -> Expression {
5402 trace!("parsing: math expression");
5403
5404 let mut expr_stack: Vec<Expression> = vec![];
5415
5416 let mut idx = 0;
5417 let mut last_prec = u8::MAX;
5418
5419 let first_span = working_set.get_span_contents(spans[0]);
5420
5421 let mut not_start_spans = vec![];
5422
5423 if first_span == b"if" || first_span == b"match" {
5424 if spans.len() > 1 {
5426 return parse_call(working_set, spans, spans[0]);
5427 } else {
5428 working_set.error(ParseError::Expected(
5429 "expression",
5430 Span::new(spans[0].end, spans[0].end),
5431 ));
5432 return garbage(working_set, spans[0]);
5433 }
5434 } else if first_span == b"not" {
5435 not_start_spans.push(spans[idx].start);
5436 idx += 1;
5437 while idx < spans.len() {
5438 let next_value = working_set.get_span_contents(spans[idx]);
5439
5440 if next_value == b"not" {
5441 not_start_spans.push(spans[idx].start);
5442 idx += 1;
5443 } else {
5444 break;
5445 }
5446 }
5447
5448 if idx == spans.len() {
5449 working_set.error(ParseError::Expected(
5450 "expression",
5451 Span::new(spans[idx - 1].end, spans[idx - 1].end),
5452 ));
5453 return garbage(working_set, spans[idx - 1]);
5454 }
5455 }
5456
5457 let mut lhs = parse_value(working_set, spans[idx], &SyntaxShape::Any);
5458
5459 for not_start_span in not_start_spans.iter().rev() {
5460 lhs = Expression::new(
5467 working_set,
5468 Expr::UnaryNot(Box::new(lhs)),
5469 Span::new(*not_start_span, spans[idx].end),
5470 Type::Bool,
5471 );
5472 }
5473 not_start_spans.clear();
5474
5475 idx += 1;
5476
5477 if idx >= spans.len() {
5478 if let Some(row_var_id) = lhs_row_var_id {
5480 expand_to_cell_path(working_set, &mut lhs, row_var_id);
5481 }
5482 }
5483
5484 expr_stack.push(lhs);
5485
5486 while idx < spans.len() {
5487 let op = parse_operator(working_set, spans[idx]);
5488
5489 let op_prec = op.precedence();
5490
5491 idx += 1;
5492
5493 if idx == spans.len() {
5494 working_set.error(ParseError::IncompleteMathExpression(spans[idx - 1]));
5496
5497 expr_stack.push(Expression::garbage(working_set, spans[idx - 1]));
5498 expr_stack.push(Expression::garbage(working_set, spans[idx - 1]));
5499
5500 break;
5501 }
5502
5503 let content = working_set.get_span_contents(spans[idx]);
5504 if content == b"if" || content == b"match" {
5507 let rhs = parse_call(working_set, &spans[idx..], spans[0]);
5508 expr_stack.push(op);
5509 expr_stack.push(rhs);
5510 break;
5511 } else if content == b"not" {
5512 not_start_spans.push(spans[idx].start);
5513 idx += 1;
5514 while idx < spans.len() {
5515 let next_value = working_set.get_span_contents(spans[idx]);
5516
5517 if next_value == b"not" {
5518 not_start_spans.push(spans[idx].start);
5519 idx += 1;
5520 } else {
5521 break;
5522 }
5523 }
5524
5525 if idx == spans.len() {
5526 working_set.error(ParseError::Expected(
5527 "expression",
5528 Span::new(spans[idx - 1].end, spans[idx - 1].end),
5529 ));
5530 return garbage(working_set, spans[idx - 1]);
5531 }
5532 }
5533 let mut rhs = parse_value(working_set, spans[idx], &SyntaxShape::Any);
5534
5535 for not_start_span in not_start_spans.iter().rev() {
5536 rhs = Expression::new(
5543 working_set,
5544 Expr::UnaryNot(Box::new(rhs)),
5545 Span::new(*not_start_span, spans[idx].end),
5546 Type::Bool,
5547 );
5548 }
5549 not_start_spans.clear();
5550
5551 while op_prec <= last_prec && expr_stack.len() > 1 {
5552 let mut rhs = expr_stack
5555 .pop()
5556 .expect("internal error: expression stack empty");
5557 let mut op = expr_stack
5558 .pop()
5559 .expect("internal error: expression stack empty");
5560
5561 last_prec = op.precedence();
5562
5563 if last_prec < op_prec {
5564 expr_stack.push(op);
5565 expr_stack.push(rhs);
5566 break;
5567 }
5568
5569 let mut lhs = expr_stack
5570 .pop()
5571 .expect("internal error: expression stack empty");
5572
5573 if let Some(row_var_id) = lhs_row_var_id {
5574 expand_to_cell_path(working_set, &mut lhs, row_var_id);
5575 }
5576
5577 let (result_ty, err) = math_result_type(working_set, &mut lhs, &mut op, &mut rhs);
5578 if let Some(err) = err {
5579 working_set.error(err);
5580 }
5581
5582 let op_span = Span::append(lhs.span, rhs.span);
5583 expr_stack.push(Expression::new(
5584 working_set,
5585 Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
5586 op_span,
5587 result_ty,
5588 ));
5589 }
5590 expr_stack.push(op);
5591 expr_stack.push(rhs);
5592
5593 last_prec = op_prec;
5594
5595 idx += 1;
5596 }
5597
5598 while expr_stack.len() != 1 {
5599 let mut rhs = expr_stack
5600 .pop()
5601 .expect("internal error: expression stack empty");
5602 let mut op = expr_stack
5603 .pop()
5604 .expect("internal error: expression stack empty");
5605 let mut lhs = expr_stack
5606 .pop()
5607 .expect("internal error: expression stack empty");
5608
5609 if let Some(row_var_id) = lhs_row_var_id {
5610 expand_to_cell_path(working_set, &mut lhs, row_var_id);
5611 }
5612
5613 let (result_ty, err) = math_result_type(working_set, &mut lhs, &mut op, &mut rhs);
5614 if let Some(err) = err {
5615 working_set.error(err)
5616 }
5617
5618 let binary_op_span = Span::append(lhs.span, rhs.span);
5619 expr_stack.push(Expression::new(
5620 working_set,
5621 Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
5622 binary_op_span,
5623 result_ty,
5624 ));
5625 }
5626
5627 expr_stack
5628 .pop()
5629 .expect("internal error: expression stack empty")
5630}
5631
5632pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
5633 trace!("parsing: expression");
5634
5635 let mut pos = 0;
5636 let mut shorthand = vec![];
5637
5638 while pos < spans.len() {
5639 let name = working_set.get_span_contents(spans[pos]);
5641
5642 let split = name.splitn(2, |x| *x == b'=');
5643 let split: Vec<_> = split.collect();
5644 if !name.starts_with(b"^")
5645 && split.len() == 2
5646 && !split[0].is_empty()
5647 && !split[0].ends_with(b"..")
5648 {
5650 let point = split[0].len() + 1;
5651
5652 let starting_error_count = working_set.parse_errors.len();
5653
5654 let lhs_span = Span::new(spans[pos].start, spans[pos].start + point - 1);
5655 if !is_identifier(working_set.get_span_contents(lhs_span)) {
5656 break;
5657 }
5658
5659 let lhs = parse_string_strict(working_set, lhs_span);
5660 let rhs = if spans[pos].start + point < spans[pos].end {
5661 let rhs_span = Span::new(spans[pos].start + point, spans[pos].end);
5662
5663 if working_set.get_span_contents(rhs_span).starts_with(b"$") {
5664 parse_dollar_expr(working_set, rhs_span)
5665 } else {
5666 parse_string_strict(working_set, rhs_span)
5667 }
5668 } else {
5669 Expression::new(
5670 working_set,
5671 Expr::String(String::new()),
5672 Span::unknown(),
5673 Type::Nothing,
5674 )
5675 };
5676
5677 if starting_error_count == working_set.parse_errors.len() {
5678 shorthand.push((lhs, rhs));
5679 pos += 1;
5680 } else {
5681 working_set.parse_errors.truncate(starting_error_count);
5682 break;
5683 }
5684 } else {
5685 break;
5686 }
5687 }
5688
5689 if pos == spans.len() {
5690 working_set.error(ParseError::UnknownCommand(spans[0]));
5691 return garbage(working_set, Span::concat(spans));
5692 }
5693
5694 let output = if spans[pos..]
5695 .iter()
5696 .any(|span| is_assignment_operator(working_set.get_span_contents(*span)))
5697 {
5698 parse_assignment_expression(working_set, &spans[pos..])
5699 } else if is_math_expression_like(working_set, spans[pos]) {
5700 parse_math_expression(working_set, &spans[pos..], None)
5701 } else {
5702 let bytes = working_set.get_span_contents(spans[pos]).to_vec();
5703
5704 match bytes.as_slice() {
5706 b"def" | b"extern" | b"for" | b"module" | b"use" | b"source" | b"alias" | b"export"
5707 | b"hide" => {
5708 working_set.error(ParseError::BuiltinCommandInPipeline(
5709 String::from_utf8(bytes)
5710 .expect("builtin commands bytes should be able to convert to string"),
5711 spans[0],
5712 ));
5713
5714 parse_call(working_set, &spans[pos..], spans[0])
5715 }
5716 b"let" | b"const" | b"mut" => {
5717 working_set.error(ParseError::AssignInPipeline(
5718 String::from_utf8(bytes)
5719 .expect("builtin commands bytes should be able to convert to string"),
5720 String::from_utf8_lossy(match spans.len() {
5721 1..=3 => b"value",
5722 _ => working_set.get_span_contents(spans[3]),
5723 })
5724 .to_string(),
5725 String::from_utf8_lossy(match spans.len() {
5726 1 => b"variable",
5727 _ => working_set.get_span_contents(spans[1]),
5728 })
5729 .to_string(),
5730 spans[0],
5731 ));
5732 parse_call(working_set, &spans[pos..], spans[0])
5733 }
5734 b"overlay" => {
5735 if spans.len() > 1 && working_set.get_span_contents(spans[1]) == b"list" {
5736 parse_call(working_set, &spans[pos..], spans[0])
5738 } else {
5739 working_set.error(ParseError::BuiltinCommandInPipeline(
5740 "overlay".into(),
5741 spans[0],
5742 ));
5743
5744 parse_call(working_set, &spans[pos..], spans[0])
5745 }
5746 }
5747 b"where" => parse_where_expr(working_set, &spans[pos..]),
5748 #[cfg(feature = "plugin")]
5749 b"plugin" => {
5750 if spans.len() > 1 && working_set.get_span_contents(spans[1]) == b"use" {
5751 working_set.error(ParseError::BuiltinCommandInPipeline(
5753 "plugin use".into(),
5754 spans[0],
5755 ));
5756 }
5757
5758 parse_call(working_set, &spans[pos..], spans[0])
5759 }
5760
5761 _ => parse_call(working_set, &spans[pos..], spans[0]),
5762 }
5763 };
5764
5765 if !shorthand.is_empty() {
5766 let with_env = working_set.find_decl(b"with-env");
5767 if let Some(decl_id) = with_env {
5768 let mut block = Block::default();
5769 let ty = output.ty.clone();
5770 block.pipelines = vec![Pipeline::from_vec(vec![output])];
5771 block.span = Some(Span::concat(spans));
5772
5773 compile_block(working_set, &mut block);
5774
5775 let block_id = working_set.add_block(Arc::new(block));
5776
5777 let mut env_vars = vec![];
5778 for sh in shorthand {
5779 env_vars.push(RecordItem::Pair(sh.0, sh.1));
5780 }
5781
5782 let arguments = vec![
5783 Argument::Positional(Expression::new(
5784 working_set,
5785 Expr::Record(env_vars),
5786 Span::concat(&spans[..pos]),
5787 Type::Any,
5788 )),
5789 Argument::Positional(Expression::new(
5790 working_set,
5791 Expr::Closure(block_id),
5792 Span::concat(&spans[pos..]),
5793 Type::Closure,
5794 )),
5795 ];
5796
5797 let expr = Expr::Call(Box::new(Call {
5798 head: Span::unknown(),
5799 decl_id,
5800 arguments,
5801 parser_info: HashMap::new(),
5802 }));
5803
5804 Expression::new(working_set, expr, Span::concat(spans), ty)
5805 } else {
5806 output
5807 }
5808 } else {
5809 output
5810 }
5811}
5812
5813pub fn parse_builtin_commands(
5814 working_set: &mut StateWorkingSet,
5815 lite_command: &LiteCommand,
5816) -> Pipeline {
5817 trace!("parsing: builtin commands");
5818 if !is_math_expression_like(working_set, lite_command.parts[0])
5819 && !is_unaliasable_parser_keyword(working_set, &lite_command.parts)
5820 {
5821 trace!("parsing: not math expression or unaliasable parser keyword");
5822 let name = working_set.get_span_contents(lite_command.parts[0]);
5823 if let Some(decl_id) = working_set.find_decl(name) {
5824 let cmd = working_set.get_decl(decl_id);
5825 if cmd.is_alias() {
5826 let call_expr = parse_call(working_set, &lite_command.parts, lite_command.parts[0]);
5829
5830 if let Expression {
5831 expr: Expr::Call(call),
5832 ..
5833 } = call_expr
5834 {
5835 let cmd = working_set.get_decl(call.decl_id);
5837 match cmd.name() {
5838 "overlay hide" => return parse_overlay_hide(working_set, call),
5839 "overlay new" => return parse_overlay_new(working_set, call),
5840 "overlay use" => return parse_overlay_use(working_set, call),
5841 _ => { }
5842 }
5843 }
5844 }
5845 }
5846 }
5847
5848 trace!("parsing: checking for keywords");
5849 let name = lite_command
5850 .command_parts()
5851 .first()
5852 .map(|s| working_set.get_span_contents(*s))
5853 .unwrap_or(b"");
5854
5855 match name {
5856 b"def" => parse_def(working_set, lite_command, None).0,
5858 b"extern" => parse_extern(working_set, lite_command, None),
5859 b"export" => parse_export_in_block(working_set, lite_command),
5861 _ if lite_command.has_attributes() => parse_attribute_block(working_set, lite_command),
5863 b"let" => parse_let(
5864 working_set,
5865 &lite_command
5866 .parts_including_redirection()
5867 .collect::<Vec<Span>>(),
5868 ),
5869 b"const" => parse_const(working_set, &lite_command.parts).0,
5870 b"mut" => parse_mut(
5871 working_set,
5872 &lite_command
5873 .parts_including_redirection()
5874 .collect::<Vec<Span>>(),
5875 ),
5876 b"for" => {
5877 let expr = parse_for(working_set, lite_command);
5878 Pipeline::from_vec(vec![expr])
5879 }
5880 b"alias" => parse_alias(working_set, lite_command, None),
5881 b"module" => parse_module(working_set, lite_command, None).0,
5882 b"use" => parse_use(working_set, lite_command, None).0,
5883 b"overlay" => {
5884 if let Some(redirection) = lite_command.redirection.as_ref() {
5885 working_set.error(redirecting_builtin_error("overlay", redirection));
5886 return garbage_pipeline(working_set, &lite_command.parts);
5887 }
5888 parse_keyword(working_set, lite_command)
5889 }
5890 b"source" | b"source-env" => parse_source(working_set, lite_command),
5891 b"hide" => parse_hide(working_set, lite_command),
5892 b"where" => parse_where(working_set, lite_command),
5893 #[cfg(feature = "plugin")]
5895 b"plugin"
5896 if lite_command
5897 .parts
5898 .get(1)
5899 .is_some_and(|span| working_set.get_span_contents(*span) == b"use") =>
5900 {
5901 if let Some(redirection) = lite_command.redirection.as_ref() {
5902 working_set.error(redirecting_builtin_error("plugin use", redirection));
5903 return garbage_pipeline(working_set, &lite_command.parts);
5904 }
5905 parse_keyword(working_set, lite_command)
5906 }
5907 _ => {
5908 let element = parse_pipeline_element(working_set, lite_command);
5909
5910 if let Expression {
5922 expr: Expr::Call(call),
5923 ..
5924 } = &element.expr
5925 {
5926 let cmd = working_set.get_decl(call.decl_id);
5928 match cmd.name() {
5929 "overlay hide" => return parse_overlay_hide(working_set, call.clone()),
5930 "overlay new" => return parse_overlay_new(working_set, call.clone()),
5931 "overlay use" => return parse_overlay_use(working_set, call.clone()),
5932 _ => { }
5933 }
5934 }
5935 Pipeline {
5936 elements: vec![element],
5937 }
5938 }
5939 }
5940}
5941
5942fn check_record_key_or_value(
5943 working_set: &StateWorkingSet,
5944 expr: &Expression,
5945 position: &str,
5946) -> Option<ParseError> {
5947 let bareword_error = |string_value: &Expression| {
5948 working_set
5949 .get_span_contents(string_value.span)
5950 .iter()
5951 .find_position(|b| **b == b':')
5952 .map(|(i, _)| {
5953 let colon_position = i + string_value.span.start;
5954 ParseError::InvalidLiteral(
5955 "colon".to_string(),
5956 format!("bare word specifying record {}", position),
5957 Span::new(colon_position, colon_position + 1),
5958 )
5959 })
5960 };
5961 let value_span = working_set.get_span_contents(expr.span);
5962 match expr.expr {
5963 Expr::String(_) => {
5964 if ![b'"', b'\'', b'`'].contains(&value_span[0]) {
5965 bareword_error(expr)
5966 } else {
5967 None
5968 }
5969 }
5970 Expr::StringInterpolation(ref expressions) => {
5971 if value_span[0] != b'$' {
5972 expressions
5973 .iter()
5974 .filter(|expr| matches!(expr.expr, Expr::String(_)))
5975 .filter_map(bareword_error)
5976 .next()
5977 } else {
5978 None
5979 }
5980 }
5981 _ => None,
5982 }
5983}
5984
5985pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression {
5986 let bytes = working_set.get_span_contents(span);
5987
5988 let mut start = span.start;
5989 let mut end = span.end;
5990
5991 if bytes.starts_with(b"{") {
5992 start += 1;
5993 } else {
5994 working_set.error(ParseError::Expected("{", Span::new(start, start + 1)));
5995 return garbage(working_set, span);
5996 }
5997
5998 let mut unclosed = false;
5999 let mut extra_tokens = false;
6000 if bytes.ends_with(b"}") {
6001 end -= 1;
6002 } else {
6003 unclosed = true;
6004 }
6005
6006 let inner_span = Span::new(start, end);
6007
6008 let mut lex_state = LexState {
6009 input: working_set.get_span_contents(inner_span),
6010 output: Vec::new(),
6011 error: None,
6012 span_offset: start,
6013 };
6014 while !lex_state.input.is_empty() {
6015 if lex_state.input[0] == b'}' {
6016 extra_tokens = true;
6017 unclosed = false;
6018 break;
6019 }
6020 let additional_whitespace = &[b'\n', b'\r', b','];
6021 if lex_n_tokens(&mut lex_state, additional_whitespace, &[b':'], true, 1) < 1 {
6022 break;
6023 };
6024 let span = lex_state
6025 .output
6026 .last()
6027 .expect("should have gotten 1 token")
6028 .span;
6029 let contents = working_set.get_span_contents(span);
6030 if contents.len() > 3
6031 && contents.starts_with(b"...")
6032 && (contents[3] == b'$' || contents[3] == b'{' || contents[3] == b'(')
6033 {
6034 continue;
6036 }
6037 if lex_n_tokens(&mut lex_state, additional_whitespace, &[b':'], true, 1) < 1 {
6039 break;
6040 };
6041 if lex_n_tokens(&mut lex_state, additional_whitespace, &[], true, 1) < 1 {
6043 break;
6044 };
6045 }
6046 let (tokens, err) = (lex_state.output, lex_state.error);
6047
6048 if unclosed {
6049 working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
6050 } else if extra_tokens {
6051 working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(Span::new(
6052 lex_state.span_offset + 1,
6053 end,
6054 )));
6055 }
6056
6057 if let Some(err) = err {
6058 working_set.error(err);
6059 }
6060
6061 let mut output = vec![];
6062 let mut idx = 0;
6063
6064 let mut field_types = Some(vec![]);
6065 while idx < tokens.len() {
6066 let curr_span = tokens[idx].span;
6067 let curr_tok = working_set.get_span_contents(curr_span);
6068 if curr_tok.starts_with(b"...")
6069 && curr_tok.len() > 3
6070 && (curr_tok[3] == b'$' || curr_tok[3] == b'{' || curr_tok[3] == b'(')
6071 {
6072 let inner = parse_value(
6074 working_set,
6075 Span::new(curr_span.start + 3, curr_span.end),
6076 &SyntaxShape::Record(vec![]),
6077 );
6078 idx += 1;
6079
6080 match &inner.ty {
6081 Type::Record(inner_fields) => {
6082 if let Some(fields) = &mut field_types {
6083 for (field, ty) in inner_fields.as_ref() {
6084 fields.push((field.clone(), ty.clone()));
6085 }
6086 }
6087 }
6088 _ => {
6089 field_types = None;
6092 }
6093 }
6094 output.push(RecordItem::Spread(
6095 Span::new(curr_span.start, curr_span.start + 3),
6096 inner,
6097 ));
6098 } else {
6099 let field_token = &tokens[idx];
6101 let field = if field_token.contents != TokenContents::Item {
6102 working_set.error(ParseError::Expected(
6103 "item in record key position",
6104 Span::new(field_token.span.start, field_token.span.end),
6105 ));
6106 garbage(working_set, curr_span)
6107 } else {
6108 let field = parse_value(working_set, curr_span, &SyntaxShape::Any);
6109 if let Some(error) = check_record_key_or_value(working_set, &field, "key") {
6110 working_set.error(error);
6111 garbage(working_set, field.span)
6112 } else {
6113 field
6114 }
6115 };
6116
6117 idx += 1;
6118 if idx == tokens.len() {
6119 working_set.error(ParseError::Expected(
6120 "':'",
6121 Span::new(curr_span.end, curr_span.end),
6122 ));
6123 output.push(RecordItem::Pair(
6124 garbage(working_set, curr_span),
6125 garbage(working_set, Span::new(curr_span.end, curr_span.end)),
6126 ));
6127 break;
6128 }
6129 let colon_span = tokens[idx].span;
6130 let colon = working_set.get_span_contents(colon_span);
6131 idx += 1;
6132 if colon != b":" {
6133 working_set.error(ParseError::Expected(
6134 "':'",
6135 Span::new(colon_span.start, colon_span.start),
6136 ));
6137 output.push(RecordItem::Pair(
6138 field,
6139 garbage(
6140 working_set,
6141 Span::new(colon_span.start, tokens[tokens.len() - 1].span.end),
6142 ),
6143 ));
6144 break;
6145 }
6146 if idx == tokens.len() {
6147 working_set.error(ParseError::Expected(
6148 "value for record field",
6149 Span::new(colon_span.end, colon_span.end),
6150 ));
6151 output.push(RecordItem::Pair(
6152 garbage(working_set, Span::new(curr_span.start, colon_span.end)),
6153 garbage(
6154 working_set,
6155 Span::new(colon_span.end, tokens[tokens.len() - 1].span.end),
6156 ),
6157 ));
6158 break;
6159 }
6160
6161 let value_token = &tokens[idx];
6162 let value = if value_token.contents != TokenContents::Item {
6163 working_set.error(ParseError::Expected(
6164 "item in record value position",
6165 Span::new(value_token.span.start, value_token.span.end),
6166 ));
6167 garbage(
6168 working_set,
6169 Span::new(value_token.span.start, value_token.span.end),
6170 )
6171 } else {
6172 let value = parse_value(working_set, tokens[idx].span, &SyntaxShape::Any);
6173 if let Some(parse_error) = check_record_key_or_value(working_set, &value, "value") {
6174 working_set.error(parse_error);
6175 garbage(working_set, value.span)
6176 } else {
6177 value
6178 }
6179 };
6180 idx += 1;
6181
6182 if let Some(field) = field.as_string() {
6183 if let Some(fields) = &mut field_types {
6184 fields.push((field, value.ty.clone()));
6185 }
6186 } else {
6187 field_types = None;
6190 }
6191 output.push(RecordItem::Pair(field, value));
6192 }
6193 }
6194
6195 Expression::new(
6196 working_set,
6197 Expr::Record(output),
6198 span,
6199 if let Some(fields) = field_types {
6200 Type::Record(fields.into())
6201 } else {
6202 Type::Any
6203 },
6204 )
6205}
6206
6207fn parse_redirection_target(
6208 working_set: &mut StateWorkingSet,
6209 target: &LiteRedirectionTarget,
6210) -> RedirectionTarget {
6211 match target {
6212 LiteRedirectionTarget::File {
6213 connector,
6214 file,
6215 append,
6216 } => RedirectionTarget::File {
6217 expr: parse_value(working_set, *file, &SyntaxShape::Any),
6218 append: *append,
6219 span: *connector,
6220 },
6221 LiteRedirectionTarget::Pipe { connector } => RedirectionTarget::Pipe { span: *connector },
6222 }
6223}
6224
6225pub(crate) fn parse_redirection(
6226 working_set: &mut StateWorkingSet,
6227 target: &LiteRedirection,
6228) -> PipelineRedirection {
6229 match target {
6230 LiteRedirection::Single { source, target } => PipelineRedirection::Single {
6231 source: *source,
6232 target: parse_redirection_target(working_set, target),
6233 },
6234 LiteRedirection::Separate { out, err } => PipelineRedirection::Separate {
6235 out: parse_redirection_target(working_set, out),
6236 err: parse_redirection_target(working_set, err),
6237 },
6238 }
6239}
6240
6241fn parse_pipeline_element(
6242 working_set: &mut StateWorkingSet,
6243 command: &LiteCommand,
6244) -> PipelineElement {
6245 trace!("parsing: pipeline element");
6246
6247 let expr = parse_expression(working_set, &command.parts);
6248
6249 let redirection = command
6250 .redirection
6251 .as_ref()
6252 .map(|r| parse_redirection(working_set, r));
6253
6254 PipelineElement {
6255 pipe: command.pipe,
6256 expr,
6257 redirection,
6258 }
6259}
6260
6261pub(crate) fn redirecting_builtin_error(
6262 name: &'static str,
6263 redirection: &LiteRedirection,
6264) -> ParseError {
6265 match redirection {
6266 LiteRedirection::Single { target, .. } => {
6267 ParseError::RedirectingBuiltinCommand(name, target.connector(), None)
6268 }
6269 LiteRedirection::Separate { out, err } => ParseError::RedirectingBuiltinCommand(
6270 name,
6271 out.connector().min(err.connector()),
6272 Some(out.connector().max(err.connector())),
6273 ),
6274 }
6275}
6276
6277pub fn parse_pipeline(working_set: &mut StateWorkingSet, pipeline: &LitePipeline) -> Pipeline {
6278 if pipeline.commands.len() > 1 {
6279 let elements: Vec<_> = pipeline
6281 .commands
6282 .iter()
6283 .enumerate()
6284 .map(|(index, element)| {
6285 let element = parse_pipeline_element(working_set, element);
6286 if index > 0 && element.has_in_variable(working_set) {
6288 wrap_element_with_collect(working_set, element.clone())
6289 } else {
6290 element
6291 }
6292 })
6293 .collect();
6294
6295 Pipeline { elements }
6296 } else {
6297 parse_builtin_commands(working_set, &pipeline.commands[0])
6299 }
6300}
6301
6302pub fn parse_block(
6303 working_set: &mut StateWorkingSet,
6304 tokens: &[Token],
6305 span: Span,
6306 scoped: bool,
6307 is_subexpression: bool,
6308) -> Block {
6309 let (lite_block, err) = lite_parse(tokens, working_set);
6310 if let Some(err) = err {
6311 working_set.error(err);
6312 }
6313
6314 trace!("parsing block: {:?}", lite_block);
6315
6316 if scoped {
6317 working_set.enter_scope();
6318 }
6319
6320 for pipeline in &lite_block.block {
6323 if pipeline.commands.len() == 1 {
6324 parse_def_predecl(working_set, pipeline.commands[0].command_parts())
6325 }
6326 }
6327
6328 let mut block = Block::new_with_capacity(lite_block.block.len());
6329 block.span = Some(span);
6330
6331 for lite_pipeline in &lite_block.block {
6332 let pipeline = parse_pipeline(working_set, lite_pipeline);
6333 block.pipelines.push(pipeline);
6334 }
6335
6336 if !is_subexpression
6339 && block
6340 .pipelines
6341 .iter()
6342 .flat_map(|pipeline| pipeline.elements.first())
6343 .any(|element| element.has_in_variable(working_set))
6344 {
6345 let inner_block = std::mem::take(&mut block);
6347 block.span = inner_block.span;
6348 let ty = inner_block.output_type();
6349 let block_id = working_set.add_block(Arc::new(inner_block));
6350
6351 let subexpression = Expression::new(working_set, Expr::Subexpression(block_id), span, ty);
6353 let collect = wrap_expr_with_collect(working_set, subexpression);
6354
6355 block.pipelines.push(Pipeline {
6356 elements: vec![PipelineElement {
6357 pipe: None,
6358 expr: collect,
6359 redirection: None,
6360 }],
6361 });
6362 }
6363
6364 if scoped {
6365 working_set.exit_scope();
6366 }
6367
6368 let errors = type_check::check_block_input_output(working_set, &block);
6369 if !errors.is_empty() {
6370 working_set.parse_errors.extend_from_slice(&errors);
6371 }
6372
6373 if !is_subexpression && working_set.parse_errors.is_empty() {
6376 compile_block(working_set, &mut block);
6377 }
6378
6379 block
6380}
6381
6382fn compile_block(working_set: &mut StateWorkingSet<'_>, block: &mut Block) {
6384 match nu_engine::compile(working_set, block) {
6385 Ok(ir_block) => {
6386 block.ir_block = Some(ir_block);
6387 }
6388 Err(err) => working_set.compile_errors.push(err),
6389 }
6390}
6391
6392pub fn discover_captures_in_closure(
6393 working_set: &StateWorkingSet,
6394 block: &Block,
6395 seen: &mut Vec<VarId>,
6396 seen_blocks: &mut HashMap<BlockId, Vec<(VarId, Span)>>,
6397 output: &mut Vec<(VarId, Span)>,
6398) -> Result<(), ParseError> {
6399 for flag in &block.signature.named {
6400 if let Some(var_id) = flag.var_id {
6401 seen.push(var_id);
6402 }
6403 }
6404
6405 for positional in &block.signature.required_positional {
6406 if let Some(var_id) = positional.var_id {
6407 seen.push(var_id);
6408 }
6409 }
6410 for positional in &block.signature.optional_positional {
6411 if let Some(var_id) = positional.var_id {
6412 seen.push(var_id);
6413 }
6414 }
6415 if let Some(positional) = &block.signature.rest_positional {
6416 if let Some(var_id) = positional.var_id {
6417 seen.push(var_id);
6418 }
6419 }
6420
6421 for pipeline in &block.pipelines {
6422 discover_captures_in_pipeline(working_set, pipeline, seen, seen_blocks, output)?;
6423 }
6424
6425 Ok(())
6426}
6427
6428fn discover_captures_in_pipeline(
6429 working_set: &StateWorkingSet,
6430 pipeline: &Pipeline,
6431 seen: &mut Vec<VarId>,
6432 seen_blocks: &mut HashMap<BlockId, Vec<(VarId, Span)>>,
6433 output: &mut Vec<(VarId, Span)>,
6434) -> Result<(), ParseError> {
6435 for element in &pipeline.elements {
6436 discover_captures_in_pipeline_element(working_set, element, seen, seen_blocks, output)?;
6437 }
6438
6439 Ok(())
6440}
6441
6442pub fn discover_captures_in_pipeline_element(
6444 working_set: &StateWorkingSet,
6445 element: &PipelineElement,
6446 seen: &mut Vec<VarId>,
6447 seen_blocks: &mut HashMap<BlockId, Vec<(VarId, Span)>>,
6448 output: &mut Vec<(VarId, Span)>,
6449) -> Result<(), ParseError> {
6450 discover_captures_in_expr(working_set, &element.expr, seen, seen_blocks, output)?;
6451
6452 if let Some(redirection) = element.redirection.as_ref() {
6453 match redirection {
6454 PipelineRedirection::Single { target, .. } => {
6455 if let Some(expr) = target.expr() {
6456 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6457 }
6458 }
6459 PipelineRedirection::Separate { out, err } => {
6460 if let Some(expr) = out.expr() {
6461 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6462 }
6463 if let Some(expr) = err.expr() {
6464 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6465 }
6466 }
6467 }
6468 }
6469
6470 Ok(())
6471}
6472
6473pub fn discover_captures_in_pattern(pattern: &MatchPattern, seen: &mut Vec<VarId>) {
6474 match &pattern.pattern {
6475 Pattern::Variable(var_id) => seen.push(*var_id),
6476 Pattern::List(items) => {
6477 for item in items {
6478 discover_captures_in_pattern(item, seen)
6479 }
6480 }
6481 Pattern::Record(items) => {
6482 for item in items {
6483 discover_captures_in_pattern(&item.1, seen)
6484 }
6485 }
6486 Pattern::Or(patterns) => {
6487 for pattern in patterns {
6488 discover_captures_in_pattern(pattern, seen)
6489 }
6490 }
6491 Pattern::Rest(var_id) => seen.push(*var_id),
6492 Pattern::Expression(_)
6493 | Pattern::Value(_)
6494 | Pattern::IgnoreValue
6495 | Pattern::IgnoreRest
6496 | Pattern::Garbage => {}
6497 }
6498}
6499
6500pub fn discover_captures_in_expr(
6502 working_set: &StateWorkingSet,
6503 expr: &Expression,
6504 seen: &mut Vec<VarId>,
6505 seen_blocks: &mut HashMap<BlockId, Vec<(VarId, Span)>>,
6506 output: &mut Vec<(VarId, Span)>,
6507) -> Result<(), ParseError> {
6508 match &expr.expr {
6509 Expr::AttributeBlock(ab) => {
6510 discover_captures_in_expr(working_set, &ab.item, seen, seen_blocks, output)?;
6511 }
6512 Expr::BinaryOp(lhs, _, rhs) => {
6513 discover_captures_in_expr(working_set, lhs, seen, seen_blocks, output)?;
6514 discover_captures_in_expr(working_set, rhs, seen, seen_blocks, output)?;
6515 }
6516 Expr::UnaryNot(expr) => {
6517 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6518 }
6519 Expr::Closure(block_id) => {
6520 let block = working_set.get_block(*block_id);
6521 let results = {
6522 let mut seen = vec![];
6523 let mut results = vec![];
6524
6525 discover_captures_in_closure(
6526 working_set,
6527 block,
6528 &mut seen,
6529 seen_blocks,
6530 &mut results,
6531 )?;
6532
6533 for (var_id, span) in results.iter() {
6534 if !seen.contains(var_id) {
6535 if let Some(variable) = working_set.get_variable_if_possible(*var_id) {
6536 if variable.mutable {
6537 return Err(ParseError::CaptureOfMutableVar(*span));
6538 }
6539 }
6540 }
6541 }
6542
6543 results
6544 };
6545 seen_blocks.insert(*block_id, results.clone());
6546 for (var_id, span) in results.into_iter() {
6547 if !seen.contains(&var_id) {
6548 output.push((var_id, span))
6549 }
6550 }
6551 }
6552 Expr::Block(block_id) => {
6553 let block = working_set.get_block(*block_id);
6554 let results = {
6556 let mut seen = vec![];
6557 let mut results = vec![];
6558 discover_captures_in_closure(
6559 working_set,
6560 block,
6561 &mut seen,
6562 seen_blocks,
6563 &mut results,
6564 )?;
6565 results
6566 };
6567
6568 seen_blocks.insert(*block_id, results.clone());
6569 for (var_id, span) in results.into_iter() {
6570 if !seen.contains(&var_id) {
6571 output.push((var_id, span))
6572 }
6573 }
6574 }
6575 Expr::Binary(_) => {}
6576 Expr::Bool(_) => {}
6577 Expr::Call(call) => {
6578 let decl = working_set.get_decl(call.decl_id);
6579 if let Some(block_id) = decl.block_id() {
6580 match seen_blocks.get(&block_id) {
6581 Some(capture_list) => {
6582 for capture in capture_list {
6584 if !seen.contains(&capture.0) {
6585 output.push(*capture);
6586 }
6587 }
6588 }
6589 None => {
6590 let block = working_set.get_block(block_id);
6591 if !block.captures.is_empty() {
6592 for capture in &block.captures {
6593 if !seen.contains(capture) {
6594 output.push((*capture, call.head));
6595 }
6596 }
6597 } else {
6598 let result = {
6599 let mut seen = vec![];
6600 seen_blocks.insert(block_id, output.clone());
6601
6602 let mut result = vec![];
6603 discover_captures_in_closure(
6604 working_set,
6605 block,
6606 &mut seen,
6607 seen_blocks,
6608 &mut result,
6609 )?;
6610
6611 result
6612 };
6613 for capture in &result {
6615 if !seen.contains(&capture.0) {
6616 output.push(*capture);
6617 }
6618 }
6619
6620 seen_blocks.insert(block_id, result);
6621 }
6622 }
6623 }
6624 }
6625
6626 for arg in &call.arguments {
6627 match arg {
6628 Argument::Named(named) => {
6629 if let Some(arg) = &named.2 {
6630 discover_captures_in_expr(working_set, arg, seen, seen_blocks, output)?;
6631 }
6632 }
6633 Argument::Positional(expr)
6634 | Argument::Unknown(expr)
6635 | Argument::Spread(expr) => {
6636 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6637 }
6638 }
6639 }
6640 }
6641 Expr::CellPath(_) => {}
6642 Expr::DateTime(_) => {}
6643 Expr::ExternalCall(head, args) => {
6644 discover_captures_in_expr(working_set, head, seen, seen_blocks, output)?;
6645
6646 for ExternalArgument::Regular(expr) | ExternalArgument::Spread(expr) in args.as_ref() {
6647 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6648 }
6649 }
6650 Expr::Filepath(_, _) => {}
6651 Expr::Directory(_, _) => {}
6652 Expr::Float(_) => {}
6653 Expr::FullCellPath(cell_path) => {
6654 discover_captures_in_expr(working_set, &cell_path.head, seen, seen_blocks, output)?;
6655 }
6656 Expr::ImportPattern(_) => {}
6657 Expr::Overlay(_) => {}
6658 Expr::Garbage => {}
6659 Expr::Nothing => {}
6660 Expr::GlobPattern(_, _) => {}
6661 Expr::Int(_) => {}
6662 Expr::Keyword(kw) => {
6663 discover_captures_in_expr(working_set, &kw.expr, seen, seen_blocks, output)?;
6664 }
6665 Expr::List(list) => {
6666 for item in list {
6667 discover_captures_in_expr(working_set, item.expr(), seen, seen_blocks, output)?;
6668 }
6669 }
6670 Expr::Operator(_) => {}
6671 Expr::Range(range) => {
6672 if let Some(from) = &range.from {
6673 discover_captures_in_expr(working_set, from, seen, seen_blocks, output)?;
6674 }
6675 if let Some(next) = &range.next {
6676 discover_captures_in_expr(working_set, next, seen, seen_blocks, output)?;
6677 }
6678 if let Some(to) = &range.to {
6679 discover_captures_in_expr(working_set, to, seen, seen_blocks, output)?;
6680 }
6681 }
6682 Expr::Record(items) => {
6683 for item in items {
6684 match item {
6685 RecordItem::Pair(field_name, field_value) => {
6686 discover_captures_in_expr(
6687 working_set,
6688 field_name,
6689 seen,
6690 seen_blocks,
6691 output,
6692 )?;
6693 discover_captures_in_expr(
6694 working_set,
6695 field_value,
6696 seen,
6697 seen_blocks,
6698 output,
6699 )?;
6700 }
6701 RecordItem::Spread(_, record) => {
6702 discover_captures_in_expr(working_set, record, seen, seen_blocks, output)?;
6703 }
6704 }
6705 }
6706 }
6707 Expr::Signature(sig) => {
6708 for pos in &sig.required_positional {
6710 if let Some(var_id) = pos.var_id {
6711 seen.push(var_id);
6712 }
6713 }
6714 for pos in &sig.optional_positional {
6715 if let Some(var_id) = pos.var_id {
6716 seen.push(var_id);
6717 }
6718 }
6719 if let Some(rest) = &sig.rest_positional {
6720 if let Some(var_id) = rest.var_id {
6721 seen.push(var_id);
6722 }
6723 }
6724 for named in &sig.named {
6725 if let Some(var_id) = named.var_id {
6726 seen.push(var_id);
6727 }
6728 }
6729 }
6730 Expr::String(_) => {}
6731 Expr::RawString(_) => {}
6732 Expr::StringInterpolation(exprs) | Expr::GlobInterpolation(exprs, _) => {
6733 for expr in exprs {
6734 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6735 }
6736 }
6737 Expr::MatchBlock(match_block) => {
6738 for match_ in match_block {
6739 discover_captures_in_pattern(&match_.0, seen);
6740 discover_captures_in_expr(working_set, &match_.1, seen, seen_blocks, output)?;
6741 }
6742 }
6743 Expr::Collect(var_id, expr) => {
6744 seen.push(*var_id);
6745 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?
6746 }
6747 Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
6748 let block = working_set.get_block(*block_id);
6749
6750 let results = {
6751 let mut results = vec![];
6752 let mut seen = vec![];
6753 discover_captures_in_closure(
6754 working_set,
6755 block,
6756 &mut seen,
6757 seen_blocks,
6758 &mut results,
6759 )?;
6760 results
6761 };
6762
6763 seen_blocks.insert(*block_id, results.clone());
6764 for (var_id, span) in results.into_iter() {
6765 if !seen.contains(&var_id) {
6766 output.push((var_id, span))
6767 }
6768 }
6769 }
6770 Expr::Table(table) => {
6771 for header in table.columns.as_ref() {
6772 discover_captures_in_expr(working_set, header, seen, seen_blocks, output)?;
6773 }
6774 for row in table.rows.as_ref() {
6775 for cell in row.as_ref() {
6776 discover_captures_in_expr(working_set, cell, seen, seen_blocks, output)?;
6777 }
6778 }
6779 }
6780 Expr::ValueWithUnit(value) => {
6781 discover_captures_in_expr(working_set, &value.expr, seen, seen_blocks, output)?;
6782 }
6783 Expr::Var(var_id) => {
6784 if (*var_id > ENV_VARIABLE_ID || *var_id == IN_VARIABLE_ID) && !seen.contains(var_id) {
6785 output.push((*var_id, expr.span));
6786 }
6787 }
6788 Expr::VarDecl(var_id) => {
6789 seen.push(*var_id);
6790 }
6791 }
6792 Ok(())
6793}
6794
6795fn wrap_redirection_with_collect(
6796 working_set: &mut StateWorkingSet,
6797 target: RedirectionTarget,
6798) -> RedirectionTarget {
6799 match target {
6800 RedirectionTarget::File { expr, append, span } => RedirectionTarget::File {
6801 expr: wrap_expr_with_collect(working_set, expr),
6802 span,
6803 append,
6804 },
6805 RedirectionTarget::Pipe { span } => RedirectionTarget::Pipe { span },
6806 }
6807}
6808
6809fn wrap_element_with_collect(
6810 working_set: &mut StateWorkingSet,
6811 element: PipelineElement,
6812) -> PipelineElement {
6813 PipelineElement {
6814 pipe: element.pipe,
6815 expr: wrap_expr_with_collect(working_set, element.expr),
6816 redirection: element.redirection.map(|r| match r {
6817 PipelineRedirection::Single { source, target } => PipelineRedirection::Single {
6818 source,
6819 target: wrap_redirection_with_collect(working_set, target),
6820 },
6821 PipelineRedirection::Separate { out, err } => PipelineRedirection::Separate {
6822 out: wrap_redirection_with_collect(working_set, out),
6823 err: wrap_redirection_with_collect(working_set, err),
6824 },
6825 }),
6826 }
6827}
6828
6829fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: Expression) -> Expression {
6830 let span = expr.span;
6831
6832 let var_id = working_set.add_variable(
6835 b"$in".into(),
6836 Span::new(span.start, span.start),
6837 Type::Any,
6838 false,
6839 );
6840 let mut expr = expr.clone();
6841 expr.replace_in_variable(working_set, var_id);
6842
6843 let ty = expr.ty.clone();
6845 Expression::new(
6846 working_set,
6847 Expr::Collect(var_id, Box::new(expr)),
6848 span,
6849 ty,
6851 )
6852}
6853
6854pub fn parse(
6858 working_set: &mut StateWorkingSet,
6859 fname: Option<&str>,
6860 contents: &[u8],
6861 scoped: bool,
6862) -> Arc<Block> {
6863 trace!("parse");
6864 let name = match fname {
6865 Some(fname) => {
6866 nu_path::expand_to_real_path(fname)
6868 .to_string_lossy()
6869 .to_string()
6870 }
6871 None => "source".to_string(),
6872 };
6873
6874 let file_id = working_set.add_file(name, contents);
6875 let new_span = working_set.get_span_for_file(file_id);
6876
6877 let previously_parsed_block = working_set.find_block_by_span(new_span);
6878
6879 let mut output = {
6880 if let Some(block) = previously_parsed_block {
6881 return block;
6883 } else {
6884 let (output, err) = lex(contents, new_span.start, &[], &[], false);
6886 if let Some(err) = err {
6889 working_set.error(err)
6890 }
6891
6892 Arc::new(parse_block(working_set, &output, new_span, scoped, false))
6893 }
6894 };
6895
6896 let mut seen = vec![];
6897 let mut seen_blocks = HashMap::new();
6898
6899 let mut captures = vec![];
6900 match discover_captures_in_closure(
6901 working_set,
6902 &output,
6903 &mut seen,
6904 &mut seen_blocks,
6905 &mut captures,
6906 ) {
6907 Ok(_) => {
6908 Arc::make_mut(&mut output).captures =
6909 captures.into_iter().map(|(var_id, _)| var_id).collect();
6910 }
6911 Err(err) => working_set.error(err),
6912 }
6913
6914 let mut errors = vec![];
6916 for (block_idx, block) in working_set.delta.blocks.iter().enumerate() {
6917 let block_id = block_idx + working_set.permanent_state.num_blocks();
6918 let block_id = BlockId::new(block_id);
6919
6920 if !seen_blocks.contains_key(&block_id) {
6921 let mut captures = vec![];
6922
6923 match discover_captures_in_closure(
6924 working_set,
6925 block,
6926 &mut seen,
6927 &mut seen_blocks,
6928 &mut captures,
6929 ) {
6930 Ok(_) => {
6931 seen_blocks.insert(block_id, captures);
6932 }
6933 Err(err) => {
6934 errors.push(err);
6935 }
6936 }
6937 }
6938 }
6939 for err in errors {
6940 working_set.error(err)
6941 }
6942
6943 for (block_id, captures) in seen_blocks.into_iter() {
6944 let block = working_set.get_block(block_id);
6949 let block_captures_empty = block.captures.is_empty();
6950 if !captures.is_empty()
6960 && block_captures_empty
6961 && block_id.get() >= working_set.permanent_state.num_blocks()
6962 {
6963 let block = working_set.get_block_mut(block_id);
6964 block.captures = captures.into_iter().map(|(var_id, _)| var_id).collect();
6965 }
6966 }
6967
6968 output
6969}