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.as_bytes()[..lhs_len]);
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 mut unit = match convert {
2705 Some(convert_to) => convert_to.0,
2706 None => *unit,
2707 };
2708
2709 let num_float = match convert {
2710 Some(convert_to) => {
2711 (number_part * convert_to.1 as f64) + (decimal_part * convert_to.1 as f64)
2712 }
2713 None => number_part,
2714 };
2715
2716 let num = match unit_to_ns_factor(&unit) {
2718 Some(factor) => {
2719 let num_ns = num_float * factor;
2720 if i64::MIN as f64 <= num_ns && num_ns <= i64::MAX as f64 {
2721 unit = Unit::Nanosecond;
2722 num_ns as i64
2723 } else {
2724 num_float as i64
2726 }
2727 }
2728 None => num_float as i64,
2729 };
2730
2731 trace!("-- found {} {:?}", num, unit);
2732 let value = ValueWithUnit {
2733 expr: Expression::new_unknown(Expr::Int(num), lhs_span, Type::Number),
2734 unit: Spanned {
2735 item: unit,
2736 span: unit_span,
2737 },
2738 };
2739 let expr = Expression::new_unknown(Expr::ValueWithUnit(Box::new(value)), span, ty);
2740
2741 Some(Ok(expr))
2742 } else {
2743 None
2744 }
2745}
2746
2747pub const FILESIZE_UNIT_GROUPS: &[UnitGroup] = &[
2748 (
2749 Unit::Filesize(FilesizeUnit::KB),
2750 "KB",
2751 Some((Unit::Filesize(FilesizeUnit::B), 1000)),
2752 ),
2753 (
2754 Unit::Filesize(FilesizeUnit::MB),
2755 "MB",
2756 Some((Unit::Filesize(FilesizeUnit::KB), 1000)),
2757 ),
2758 (
2759 Unit::Filesize(FilesizeUnit::GB),
2760 "GB",
2761 Some((Unit::Filesize(FilesizeUnit::MB), 1000)),
2762 ),
2763 (
2764 Unit::Filesize(FilesizeUnit::TB),
2765 "TB",
2766 Some((Unit::Filesize(FilesizeUnit::GB), 1000)),
2767 ),
2768 (
2769 Unit::Filesize(FilesizeUnit::PB),
2770 "PB",
2771 Some((Unit::Filesize(FilesizeUnit::TB), 1000)),
2772 ),
2773 (
2774 Unit::Filesize(FilesizeUnit::EB),
2775 "EB",
2776 Some((Unit::Filesize(FilesizeUnit::PB), 1000)),
2777 ),
2778 (
2779 Unit::Filesize(FilesizeUnit::KiB),
2780 "KIB",
2781 Some((Unit::Filesize(FilesizeUnit::B), 1024)),
2782 ),
2783 (
2784 Unit::Filesize(FilesizeUnit::MiB),
2785 "MIB",
2786 Some((Unit::Filesize(FilesizeUnit::KiB), 1024)),
2787 ),
2788 (
2789 Unit::Filesize(FilesizeUnit::GiB),
2790 "GIB",
2791 Some((Unit::Filesize(FilesizeUnit::MiB), 1024)),
2792 ),
2793 (
2794 Unit::Filesize(FilesizeUnit::TiB),
2795 "TIB",
2796 Some((Unit::Filesize(FilesizeUnit::GiB), 1024)),
2797 ),
2798 (
2799 Unit::Filesize(FilesizeUnit::PiB),
2800 "PIB",
2801 Some((Unit::Filesize(FilesizeUnit::TiB), 1024)),
2802 ),
2803 (
2804 Unit::Filesize(FilesizeUnit::EiB),
2805 "EIB",
2806 Some((Unit::Filesize(FilesizeUnit::PiB), 1024)),
2807 ),
2808 (Unit::Filesize(FilesizeUnit::B), "B", None),
2809];
2810
2811pub const DURATION_UNIT_GROUPS: &[UnitGroup] = &[
2812 (Unit::Nanosecond, "ns", None),
2813 (Unit::Microsecond, "us", Some((Unit::Nanosecond, 1000))),
2815 (
2816 Unit::Microsecond,
2818 "\u{00B5}s",
2819 Some((Unit::Nanosecond, 1000)),
2820 ),
2821 (
2822 Unit::Microsecond,
2824 "\u{03BC}s",
2825 Some((Unit::Nanosecond, 1000)),
2826 ),
2827 (Unit::Millisecond, "ms", Some((Unit::Microsecond, 1000))),
2828 (Unit::Second, "sec", Some((Unit::Millisecond, 1000))),
2829 (Unit::Minute, "min", Some((Unit::Second, 60))),
2830 (Unit::Hour, "hr", Some((Unit::Minute, 60))),
2831 (Unit::Day, "day", Some((Unit::Minute, 1440))),
2832 (Unit::Week, "wk", Some((Unit::Day, 7))),
2833];
2834
2835fn unit_to_ns_factor(unit: &Unit) -> Option<f64> {
2836 match unit {
2837 Unit::Nanosecond => Some(1.0),
2838 Unit::Microsecond => Some(1_000.0),
2839 Unit::Millisecond => Some(1_000_000.0),
2840 Unit::Second => Some(1_000_000_000.0),
2841 Unit::Minute => Some(60.0 * 1_000_000_000.0),
2842 Unit::Hour => Some(60.0 * 60.0 * 1_000_000_000.0),
2843 Unit::Day => Some(24.0 * 60.0 * 60.0 * 1_000_000_000.0),
2844 Unit::Week => Some(7.0 * 24.0 * 60.0 * 60.0 * 1_000_000_000.0),
2845 _ => None,
2846 }
2847}
2848
2849fn modf(x: f64) -> (f64, f64) {
2851 let rv2: f64;
2852 let mut u = x.to_bits();
2853 let e = (((u >> 52) & 0x7ff) as i32) - 0x3ff;
2854
2855 if e >= 52 {
2857 rv2 = x;
2858 if e == 0x400 && (u << 12) != 0 {
2859 return (x, rv2);
2861 }
2862 u &= 1 << 63;
2863 return (f64::from_bits(u), rv2);
2864 }
2865
2866 if e < 0 {
2868 u &= 1 << 63;
2869 rv2 = f64::from_bits(u);
2870 return (x, rv2);
2871 }
2872
2873 let mask = ((!0) >> 12) >> e;
2874 if (u & mask) == 0 {
2875 rv2 = x;
2876 u &= 1 << 63;
2877 return (f64::from_bits(u), rv2);
2878 }
2879 u &= !mask;
2880 rv2 = f64::from_bits(u);
2881 (x - rv2, rv2)
2882}
2883
2884pub fn parse_glob_pattern(working_set: &mut StateWorkingSet, span: Span) -> Expression {
2885 let bytes = working_set.get_span_contents(span);
2886 let quoted = is_quoted(bytes);
2887 let (token, err) = unescape_unquote_string(bytes, span);
2888 trace!("parsing: glob pattern");
2889
2890 if err.is_none() {
2891 trace!("-- found {}", token);
2892
2893 Expression::new(
2894 working_set,
2895 Expr::GlobPattern(token, quoted),
2896 span,
2897 Type::Glob,
2898 )
2899 } else {
2900 working_set.error(ParseError::Expected("glob pattern string", span));
2901
2902 garbage(working_set, span)
2903 }
2904}
2905
2906pub fn unescape_string(bytes: &[u8], span: Span) -> (Vec<u8>, Option<ParseError>) {
2907 let mut output = Vec::new();
2908 let mut error = None;
2909
2910 let mut idx = 0;
2911
2912 if !bytes.contains(&b'\\') {
2913 return (bytes.to_vec(), None);
2914 }
2915
2916 'us_loop: while idx < bytes.len() {
2917 if bytes[idx] == b'\\' {
2918 idx += 1;
2920
2921 match bytes.get(idx) {
2922 Some(b'"') => {
2923 output.push(b'"');
2924 idx += 1;
2925 }
2926 Some(b'\'') => {
2927 output.push(b'\'');
2928 idx += 1;
2929 }
2930 Some(b'\\') => {
2931 output.push(b'\\');
2932 idx += 1;
2933 }
2934 Some(b'/') => {
2935 output.push(b'/');
2936 idx += 1;
2937 }
2938 Some(b'(') => {
2939 output.push(b'(');
2940 idx += 1;
2941 }
2942 Some(b')') => {
2943 output.push(b')');
2944 idx += 1;
2945 }
2946 Some(b'{') => {
2947 output.push(b'{');
2948 idx += 1;
2949 }
2950 Some(b'}') => {
2951 output.push(b'}');
2952 idx += 1;
2953 }
2954 Some(b'$') => {
2955 output.push(b'$');
2956 idx += 1;
2957 }
2958 Some(b'^') => {
2959 output.push(b'^');
2960 idx += 1;
2961 }
2962 Some(b'#') => {
2963 output.push(b'#');
2964 idx += 1;
2965 }
2966 Some(b'|') => {
2967 output.push(b'|');
2968 idx += 1;
2969 }
2970 Some(b'~') => {
2971 output.push(b'~');
2972 idx += 1;
2973 }
2974 Some(b'a') => {
2975 output.push(0x7);
2976 idx += 1;
2977 }
2978 Some(b'b') => {
2979 output.push(0x8);
2980 idx += 1;
2981 }
2982 Some(b'e') => {
2983 output.push(0x1b);
2984 idx += 1;
2985 }
2986 Some(b'f') => {
2987 output.push(0xc);
2988 idx += 1;
2989 }
2990 Some(b'n') => {
2991 output.push(b'\n');
2992 idx += 1;
2993 }
2994 Some(b'r') => {
2995 output.push(b'\r');
2996 idx += 1;
2997 }
2998 Some(b't') => {
2999 output.push(b'\t');
3000 idx += 1;
3001 }
3002 Some(b'u') => {
3003 let mut digits = String::with_capacity(10);
3004 let mut cur_idx = idx + 1; if let Some(b'{') = bytes.get(idx + 1) {
3007 cur_idx = idx + 2;
3008 loop {
3009 match bytes.get(cur_idx) {
3010 Some(b'}') => {
3011 cur_idx += 1;
3012 break;
3013 }
3014 Some(c) => {
3015 digits.push(*c as char);
3016 cur_idx += 1;
3017 }
3018 _ => {
3019 error = error.or(Some(ParseError::InvalidLiteral(
3020 "missing '}' for unicode escape '\\u{X...}'".into(),
3021 "string".into(),
3022 Span::new(span.start + idx, span.end),
3023 )));
3024 break 'us_loop;
3025 }
3026 }
3027 }
3028 }
3029
3030 if (1..=6).contains(&digits.len()) {
3031 let int = u32::from_str_radix(&digits, 16);
3032
3033 if let Ok(int) = int {
3034 if int <= 0x10ffff {
3035 let result = char::from_u32(int);
3036
3037 if let Some(result) = result {
3038 let mut buffer = vec![0; 4];
3039 let result = result.encode_utf8(&mut buffer);
3040
3041 for elem in result.bytes() {
3042 output.push(elem);
3043 }
3044
3045 idx = cur_idx;
3046 continue 'us_loop;
3047 }
3048 }
3049 }
3050 }
3051 error = error.or(Some(ParseError::InvalidLiteral(
3053 "invalid unicode escape '\\u{X...}', must be 1-6 hex digits, max value 10FFFF".into(),
3054 "string".into(),
3055 Span::new(span.start + idx, span.end),
3056 )));
3057 break 'us_loop;
3058 }
3059
3060 _ => {
3061 error = error.or(Some(ParseError::InvalidLiteral(
3062 "unrecognized escape after '\\'".into(),
3063 "string".into(),
3064 Span::new(span.start + idx, span.end),
3065 )));
3066 break 'us_loop;
3067 }
3068 }
3069 } else {
3070 output.push(bytes[idx]);
3071 idx += 1;
3072 }
3073 }
3074
3075 (output, error)
3076}
3077
3078pub fn unescape_unquote_string(bytes: &[u8], span: Span) -> (String, Option<ParseError>) {
3079 if bytes.starts_with(b"\"") {
3080 let bytes = trim_quotes(bytes);
3082
3083 let (bytes, err) = unescape_string(bytes, span);
3084
3085 if let Ok(token) = String::from_utf8(bytes) {
3086 (token, err)
3087 } else {
3088 (String::new(), Some(ParseError::Expected("string", span)))
3089 }
3090 } else {
3091 let bytes = trim_quotes(bytes);
3092
3093 if let Ok(token) = String::from_utf8(bytes.into()) {
3094 (token, None)
3095 } else {
3096 (String::new(), Some(ParseError::Expected("string", span)))
3097 }
3098 }
3099}
3100
3101pub fn parse_string(working_set: &mut StateWorkingSet, span: Span) -> Expression {
3102 trace!("parsing: string");
3103
3104 let bytes = working_set.get_span_contents(span);
3105
3106 if bytes.is_empty() {
3107 working_set.error(ParseError::Expected("String", span));
3108 return Expression::garbage(working_set, span);
3109 }
3110
3111 if bytes[0] != b'\'' && bytes[0] != b'"' && bytes[0] != b'`' && bytes.contains(&b'(') {
3113 return parse_string_interpolation(working_set, span);
3114 }
3115 {
3117 if bytes.starts_with(b"\"")
3118 && (bytes.iter().filter(|ch| **ch == b'"').count() > 1 && !bytes.ends_with(b"\""))
3119 {
3120 let close_delimiter_index = bytes
3121 .iter()
3122 .skip(1)
3123 .position(|ch| *ch == b'"')
3124 .expect("Already check input bytes contains at least two double quotes");
3125 let span = Span::new(span.start + close_delimiter_index + 2, span.end);
3127 working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(span));
3128 return garbage(working_set, span);
3129 }
3130
3131 if bytes.starts_with(b"\'")
3132 && (bytes.iter().filter(|ch| **ch == b'\'').count() > 1 && !bytes.ends_with(b"\'"))
3133 {
3134 let close_delimiter_index = bytes
3135 .iter()
3136 .skip(1)
3137 .position(|ch| *ch == b'\'')
3138 .expect("Already check input bytes contains at least two double quotes");
3139 let span = Span::new(span.start + close_delimiter_index + 2, span.end);
3141 working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(span));
3142 return garbage(working_set, span);
3143 }
3144 }
3145
3146 let (s, err) = unescape_unquote_string(bytes, span);
3147 if let Some(err) = err {
3148 working_set.error(err);
3149 }
3150
3151 Expression::new(working_set, Expr::String(s), span, Type::String)
3152}
3153
3154fn is_quoted(bytes: &[u8]) -> bool {
3155 (bytes.starts_with(b"\"") && bytes.ends_with(b"\"") && bytes.len() > 1)
3156 || (bytes.starts_with(b"\'") && bytes.ends_with(b"\'") && bytes.len() > 1)
3157}
3158
3159pub fn parse_string_strict(working_set: &mut StateWorkingSet, span: Span) -> Expression {
3160 trace!("parsing: string, with required delimiters");
3161
3162 let bytes = working_set.get_span_contents(span);
3163
3164 {
3166 let bytes = if bytes.starts_with(b"$") {
3167 &bytes[1..]
3168 } else {
3169 bytes
3170 };
3171 if bytes.starts_with(b"\"") && (bytes.len() == 1 || !bytes.ends_with(b"\"")) {
3172 working_set.error(ParseError::Unclosed("\"".into(), span));
3173 return garbage(working_set, span);
3174 }
3175 if bytes.starts_with(b"\'") && (bytes.len() == 1 || !bytes.ends_with(b"\'")) {
3176 working_set.error(ParseError::Unclosed("\'".into(), span));
3177 return garbage(working_set, span);
3178 }
3179 if bytes.starts_with(b"r#") && (bytes.len() == 1 || !bytes.ends_with(b"#")) {
3180 working_set.error(ParseError::Unclosed("r#".into(), span));
3181 return garbage(working_set, span);
3182 }
3183 }
3184
3185 let (bytes, quoted) = if (bytes.starts_with(b"\"") && bytes.ends_with(b"\"") && bytes.len() > 1)
3186 || (bytes.starts_with(b"\'") && bytes.ends_with(b"\'") && bytes.len() > 1)
3187 {
3188 (&bytes[1..(bytes.len() - 1)], true)
3189 } else if (bytes.starts_with(b"$\"") && bytes.ends_with(b"\"") && bytes.len() > 2)
3190 || (bytes.starts_with(b"$\'") && bytes.ends_with(b"\'") && bytes.len() > 2)
3191 {
3192 (&bytes[2..(bytes.len() - 1)], true)
3193 } else {
3194 (bytes, false)
3195 };
3196
3197 if let Ok(token) = String::from_utf8(bytes.into()) {
3198 trace!("-- found {}", token);
3199
3200 if quoted {
3201 Expression::new(working_set, Expr::String(token), span, Type::String)
3202 } else if token.contains(' ') {
3203 working_set.error(ParseError::Expected("string", span));
3204
3205 garbage(working_set, span)
3206 } else {
3207 Expression::new(working_set, Expr::String(token), span, Type::String)
3208 }
3209 } else {
3210 working_set.error(ParseError::Expected("string", span));
3211 garbage(working_set, span)
3212 }
3213}
3214
3215pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
3216 let Some(head_span) = spans.first() else {
3217 working_set.error(ParseError::WrongImportPattern(
3218 "needs at least one component of import pattern".to_string(),
3219 Span::concat(spans),
3220 ));
3221 return garbage(working_set, Span::concat(spans));
3222 };
3223
3224 let head_expr = parse_value(working_set, *head_span, &SyntaxShape::Any);
3225
3226 let (maybe_module_id, head_name) = match eval_constant(working_set, &head_expr) {
3227 Ok(Value::Nothing { .. }) => {
3228 return Expression::new(
3229 working_set,
3230 Expr::Nothing,
3231 Span::concat(spans),
3232 Type::Nothing,
3233 );
3234 }
3235 Ok(val) => match val.coerce_into_string() {
3236 Ok(s) => (working_set.find_module(s.as_bytes()), s.into_bytes()),
3237 Err(err) => {
3238 working_set.error(err.wrap(working_set, Span::concat(spans)));
3239 return garbage(working_set, Span::concat(spans));
3240 }
3241 },
3242 Err(err) => {
3243 working_set.error(err.wrap(working_set, Span::concat(spans)));
3244 return garbage(working_set, Span::concat(spans));
3245 }
3246 };
3247
3248 let mut import_pattern = ImportPattern {
3249 head: ImportPatternHead {
3250 name: head_name,
3251 id: maybe_module_id,
3252 span: *head_span,
3253 },
3254 members: vec![],
3255 hidden: HashSet::new(),
3256 constants: vec![],
3257 };
3258
3259 if spans.len() > 1 {
3260 let mut leaf_member_span = None;
3261
3262 for tail_span in spans[1..].iter() {
3263 if let Some(prev_span) = leaf_member_span {
3264 let what = if working_set.get_span_contents(prev_span) == b"*" {
3265 "glob"
3266 } else {
3267 "list"
3268 };
3269 working_set.error(ParseError::WrongImportPattern(
3270 format!(
3271 "{} member can be only at the end of an import pattern",
3272 what
3273 ),
3274 prev_span,
3275 ));
3276 return Expression::new(
3277 working_set,
3278 Expr::ImportPattern(Box::new(import_pattern)),
3279 prev_span,
3280 Type::List(Box::new(Type::String)),
3281 );
3282 }
3283
3284 let tail = working_set.get_span_contents(*tail_span);
3285
3286 if tail == b"*" {
3287 import_pattern
3288 .members
3289 .push(ImportPatternMember::Glob { span: *tail_span });
3290
3291 leaf_member_span = Some(*tail_span);
3292 } else if tail.starts_with(b"[") {
3293 let result = parse_list_expression(working_set, *tail_span, &SyntaxShape::String);
3294
3295 let mut output = vec![];
3296
3297 if let Expression {
3298 expr: Expr::List(list),
3299 ..
3300 } = result
3301 {
3302 for item in list {
3303 match item {
3304 ListItem::Item(expr) => {
3305 let contents = working_set.get_span_contents(expr.span);
3306 output.push((trim_quotes(contents).to_vec(), expr.span));
3307 }
3308 ListItem::Spread(_, spread) => {
3309 working_set.error(ParseError::WrongImportPattern(
3310 "cannot spread in an import pattern".into(),
3311 spread.span,
3312 ))
3313 }
3314 }
3315 }
3316
3317 import_pattern
3318 .members
3319 .push(ImportPatternMember::List { names: output });
3320 } else {
3321 working_set.error(ParseError::ExportNotFound(result.span));
3322 return Expression::new(
3323 working_set,
3324 Expr::ImportPattern(Box::new(import_pattern)),
3325 Span::concat(spans),
3326 Type::List(Box::new(Type::String)),
3327 );
3328 }
3329
3330 leaf_member_span = Some(*tail_span);
3331 } else {
3332 let tail = trim_quotes(tail);
3333
3334 import_pattern.members.push(ImportPatternMember::Name {
3335 name: tail.to_vec(),
3336 span: *tail_span,
3337 });
3338 }
3339 }
3340 }
3341
3342 Expression::new(
3343 working_set,
3344 Expr::ImportPattern(Box::new(import_pattern)),
3345 Span::concat(&spans[1..]),
3346 Type::List(Box::new(Type::String)),
3347 )
3348}
3349
3350pub fn parse_var_with_opt_type(
3355 working_set: &mut StateWorkingSet,
3356 spans: &[Span],
3357 spans_idx: &mut usize,
3358 mutable: bool,
3359) -> (Expression, Option<Type>) {
3360 let name_span = spans[*spans_idx];
3361 let bytes = working_set.get_span_contents(name_span).to_vec();
3362
3363 if bytes.contains(&b' ')
3364 || bytes.contains(&b'"')
3365 || bytes.contains(&b'\'')
3366 || bytes.contains(&b'`')
3367 {
3368 working_set.error(ParseError::VariableNotValid(spans[*spans_idx]));
3369 return (garbage(working_set, spans[*spans_idx]), None);
3370 }
3371
3372 if bytes.ends_with(b":") {
3373 let name_span = Span::new(name_span.start, name_span.end - 1);
3374 let var_name = bytes[0..(bytes.len() - 1)].to_vec();
3375
3376 if *spans_idx + 1 < spans.len() {
3378 *spans_idx += 1;
3379 let full_span = Span::concat(&spans[*spans_idx..]);
3382 let type_bytes = working_set.get_span_contents(full_span).to_vec();
3383
3384 let (tokens, parse_error) =
3385 lex_signature(&type_bytes, full_span.start, &[b','], &[], true);
3386
3387 if let Some(parse_error) = parse_error {
3388 working_set.error(parse_error);
3389 }
3390
3391 let ty = parse_type(working_set, &type_bytes, tokens[0].span);
3392 *spans_idx = spans.len() - 1;
3393
3394 if !is_variable(&var_name) {
3395 working_set.error(ParseError::Expected(
3396 "valid variable name",
3397 spans[*spans_idx - 1],
3398 ));
3399 return (garbage(working_set, spans[*spans_idx - 1]), None);
3400 }
3401
3402 let id = working_set.add_variable(var_name, spans[*spans_idx - 1], ty.clone(), mutable);
3403
3404 (
3405 Expression::new(working_set, Expr::VarDecl(id), name_span, ty.clone()),
3406 Some(ty),
3407 )
3408 } else {
3409 if !is_variable(&var_name) {
3410 working_set.error(ParseError::Expected(
3411 "valid variable name",
3412 spans[*spans_idx],
3413 ));
3414 return (garbage(working_set, spans[*spans_idx]), None);
3415 }
3416
3417 let id = working_set.add_variable(var_name, spans[*spans_idx], Type::Any, mutable);
3418
3419 working_set.error(ParseError::MissingType(spans[*spans_idx]));
3420 (
3421 Expression::new(working_set, Expr::VarDecl(id), spans[*spans_idx], Type::Any),
3422 None,
3423 )
3424 }
3425 } else {
3426 let var_name = bytes;
3427
3428 if !is_variable(&var_name) {
3429 working_set.error(ParseError::Expected(
3430 "valid variable name",
3431 spans[*spans_idx],
3432 ));
3433 return (garbage(working_set, spans[*spans_idx]), None);
3434 }
3435
3436 let id = working_set.add_variable(
3437 var_name,
3438 Span::concat(&spans[*spans_idx..*spans_idx + 1]),
3439 Type::Any,
3440 mutable,
3441 );
3442
3443 (
3444 Expression::new(working_set, Expr::VarDecl(id), spans[*spans_idx], Type::Any),
3445 None,
3446 )
3447 }
3448}
3449
3450pub fn expand_to_cell_path(
3451 working_set: &mut StateWorkingSet,
3452 expression: &mut Expression,
3453 var_id: VarId,
3454) {
3455 trace!("parsing: expanding to cell path");
3456 if let Expression {
3457 expr: Expr::String(_),
3458 span,
3459 ..
3460 } = expression
3461 {
3462 let new_expression = parse_full_cell_path(working_set, Some(var_id), *span);
3464
3465 *expression = new_expression;
3466 }
3467
3468 if let Expression {
3469 expr: Expr::UnaryNot(inner),
3470 ..
3471 } = expression
3472 {
3473 expand_to_cell_path(working_set, inner, var_id);
3474 }
3475}
3476
3477pub fn parse_input_output_types(
3478 working_set: &mut StateWorkingSet,
3479 spans: &[Span],
3480) -> Vec<(Type, Type)> {
3481 let mut full_span = Span::concat(spans);
3482
3483 let mut bytes = working_set.get_span_contents(full_span);
3484
3485 if bytes.starts_with(b"[") {
3486 bytes = &bytes[1..];
3487 full_span.start += 1;
3488 }
3489
3490 if bytes.ends_with(b"]") {
3491 bytes = &bytes[..(bytes.len() - 1)];
3492 full_span.end -= 1;
3493 }
3494
3495 let (tokens, parse_error) =
3496 lex_signature(bytes, full_span.start, &[b'\n', b'\r', b','], &[], true);
3497
3498 if let Some(parse_error) = parse_error {
3499 working_set.error(parse_error);
3500 }
3501
3502 let mut output = vec![];
3503
3504 let mut idx = 0;
3505 while idx < tokens.len() {
3506 let type_bytes = working_set.get_span_contents(tokens[idx].span).to_vec();
3507 let input_type = parse_type(working_set, &type_bytes, tokens[idx].span);
3508
3509 idx += 1;
3510 if idx >= tokens.len() {
3511 working_set.error(ParseError::Expected(
3512 "arrow (->)",
3513 Span::new(tokens[idx - 1].span.end, tokens[idx - 1].span.end),
3514 ));
3515 break;
3516 }
3517
3518 let arrow = working_set.get_span_contents(tokens[idx].span);
3519 if arrow != b"->" {
3520 working_set.error(ParseError::Expected("arrow (->)", tokens[idx].span));
3521 }
3522
3523 idx += 1;
3524 if idx >= tokens.len() {
3525 working_set.error(ParseError::MissingType(Span::new(
3526 tokens[idx - 1].span.end,
3527 tokens[idx - 1].span.end,
3528 )));
3529 break;
3530 }
3531
3532 let type_bytes = working_set.get_span_contents(tokens[idx].span).to_vec();
3533 let output_type = parse_type(working_set, &type_bytes, tokens[idx].span);
3534
3535 output.push((input_type, output_type));
3536
3537 idx += 1;
3538 }
3539
3540 output
3541}
3542
3543pub fn parse_full_signature(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
3544 match spans.len() {
3545 0 => {
3548 working_set.error(ParseError::InternalError(
3549 "failed to catch missing positional arguments".to_string(),
3550 Span::concat(spans),
3551 ));
3552 garbage(working_set, Span::concat(spans))
3553 }
3554
3555 1 => parse_signature(working_set, spans[0]),
3557
3558 2 if working_set.get_span_contents(spans[1]).starts_with(b"{") => {
3561 parse_signature(working_set, spans[0])
3562 }
3563
3564 _ => {
3569 let (mut arg_signature, input_output_types_pos) =
3570 if working_set.get_span_contents(spans[0]).ends_with(b":") {
3571 (
3572 parse_signature(working_set, Span::new(spans[0].start, spans[0].end - 1)),
3573 1,
3574 )
3575 } else if working_set.get_span_contents(spans[1]) == b":" {
3576 (parse_signature(working_set, spans[0]), 2)
3577 } else {
3578 working_set.error(ParseError::Expected(
3582 "colon (:) before type signature",
3583 Span::concat(&spans[1..]),
3584 ));
3585 (parse_signature(working_set, spans[0]), 1)
3588 };
3589
3590 let input_output_types =
3591 parse_input_output_types(working_set, &spans[input_output_types_pos..]);
3592
3593 if let Expression {
3594 expr: Expr::Signature(sig),
3595 span: expr_span,
3596 ..
3597 } = &mut arg_signature
3598 {
3599 sig.input_output_types = input_output_types;
3600 expr_span.end = Span::concat(&spans[input_output_types_pos..]).end;
3601 }
3602 arg_signature
3603 }
3604 }
3605}
3606
3607pub fn parse_row_condition(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
3608 let pos = spans.first().map(|s| s.start).unwrap_or(0);
3609 let var_id = working_set.add_variable(b"$it".to_vec(), Span::new(pos, pos), Type::Any, false);
3610 let expression = parse_math_expression(working_set, spans, Some(var_id));
3611 let span = Span::concat(spans);
3612
3613 let block_id = match expression.expr {
3614 Expr::Block(block_id) => block_id,
3615 Expr::Closure(block_id) => block_id,
3616 _ => {
3617 let mut block = Block::new();
3619 let mut pipeline = Pipeline::new();
3620 pipeline.elements.push(PipelineElement {
3621 pipe: None,
3622 expr: expression,
3623 redirection: None,
3624 });
3625
3626 block.pipelines.push(pipeline);
3627
3628 block.signature.required_positional.push(PositionalArg {
3629 name: "$it".into(),
3630 desc: "row condition".into(),
3631 shape: SyntaxShape::Any,
3632 var_id: Some(var_id),
3633 default_value: None,
3634 });
3635
3636 compile_block(working_set, &mut block);
3637
3638 working_set.add_block(Arc::new(block))
3639 }
3640 };
3641
3642 Expression::new(working_set, Expr::RowCondition(block_id), span, Type::Bool)
3643}
3644
3645pub fn parse_signature(working_set: &mut StateWorkingSet, span: Span) -> Expression {
3646 let bytes = working_set.get_span_contents(span);
3647
3648 let mut start = span.start;
3649 let mut end = span.end;
3650
3651 let mut has_paren = false;
3652
3653 if bytes.starts_with(b"[") {
3654 start += 1;
3655 } else if bytes.starts_with(b"(") {
3656 has_paren = true;
3657 start += 1;
3658 } else {
3659 working_set.error(ParseError::Expected("[ or (", Span::new(start, start + 1)));
3660 return garbage(working_set, span);
3661 }
3662
3663 if (has_paren && bytes.ends_with(b")")) || (!has_paren && bytes.ends_with(b"]")) {
3664 end -= 1;
3665 } else {
3666 working_set.error(ParseError::Unclosed("] or )".into(), Span::new(end, end)));
3667 }
3668
3669 let sig = parse_signature_helper(working_set, Span::new(start, end));
3670
3671 Expression::new(working_set, Expr::Signature(sig), span, Type::Any)
3672}
3673
3674pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> Box<Signature> {
3675 enum ParseMode {
3676 Arg,
3677 AfterCommaArg,
3678 Type,
3679 AfterType,
3680 DefaultValue,
3681 }
3682
3683 #[derive(Debug)]
3684 enum Arg {
3685 Positional {
3686 arg: PositionalArg,
3687 required: bool,
3688 type_annotated: bool,
3689 },
3690 RestPositional(PositionalArg),
3691 Flag {
3692 flag: Flag,
3693 type_annotated: bool,
3694 },
3695 }
3696
3697 let source = working_set.get_span_contents(span);
3698
3699 let (output, err) = lex_signature(
3700 source,
3701 span.start,
3702 &[b'\n', b'\r'],
3703 &[b':', b'=', b','],
3704 false,
3705 );
3706 if let Some(err) = err {
3707 working_set.error(err);
3708 }
3709
3710 let mut args: Vec<Arg> = vec![];
3711 let mut parse_mode = ParseMode::Arg;
3712
3713 for (index, token) in output.iter().enumerate() {
3714 let last_token = index == output.len() - 1;
3715
3716 match token {
3717 Token {
3718 contents: crate::TokenContents::Item | crate::TokenContents::AssignmentOperator,
3719 span,
3720 } => {
3721 let span = *span;
3722 let contents = working_set.get_span_contents(span).to_vec();
3723
3724 if contents == b":" {
3726 match parse_mode {
3727 ParseMode::Arg if last_token => working_set
3728 .error(ParseError::Expected("type", Span::new(span.end, span.end))),
3729 ParseMode::Arg => {
3730 parse_mode = ParseMode::Type;
3731 }
3732 ParseMode::AfterCommaArg | ParseMode::AfterType => {
3733 working_set.error(ParseError::Expected("parameter or flag", span));
3734 }
3735 ParseMode::Type | ParseMode::DefaultValue => {
3736 working_set.error(ParseError::Expected("type", span));
3738 }
3739 }
3740 }
3741 else if contents == b"=" {
3743 match parse_mode {
3744 ParseMode::Arg | ParseMode::AfterType if last_token => working_set.error(
3745 ParseError::Expected("default value", Span::new(span.end, span.end)),
3746 ),
3747 ParseMode::Arg | ParseMode::AfterType => {
3748 parse_mode = ParseMode::DefaultValue;
3749 }
3750 ParseMode::Type => {
3751 working_set.error(ParseError::Expected("type", span));
3752 }
3753 ParseMode::AfterCommaArg => {
3754 working_set.error(ParseError::Expected("parameter or flag", span));
3755 }
3756 ParseMode::DefaultValue => {
3757 working_set.error(ParseError::Expected("default value", span));
3759 }
3760 }
3761 }
3762 else if contents == b"," {
3764 match parse_mode {
3765 ParseMode::Arg | ParseMode::AfterType => {
3766 parse_mode = ParseMode::AfterCommaArg
3767 }
3768 ParseMode::AfterCommaArg => {
3769 working_set.error(ParseError::Expected("parameter or flag", span));
3770 }
3771 ParseMode::Type => {
3772 working_set.error(ParseError::Expected("type", span));
3773 }
3774 ParseMode::DefaultValue => {
3775 working_set.error(ParseError::Expected("default value", span));
3776 }
3777 }
3778 } else {
3779 match parse_mode {
3780 ParseMode::Arg | ParseMode::AfterCommaArg | ParseMode::AfterType => {
3781 if contents.starts_with(b"--") && contents.len() > 2 {
3783 let flags: Vec<_> =
3786 contents.split(|x| x == &b'(').map(|x| x.to_vec()).collect();
3787
3788 let long = String::from_utf8_lossy(&flags[0][2..]).to_string();
3789 let mut variable_name = flags[0][2..].to_vec();
3790 (0..variable_name.len()).for_each(|idx| {
3792 if variable_name[idx] == b'-' {
3793 variable_name[idx] = b'_';
3794 }
3795 });
3796
3797 if !is_variable(&variable_name) {
3798 working_set.error(ParseError::Expected(
3799 "valid variable name for this long flag",
3800 span,
3801 ))
3802 }
3803
3804 let var_id =
3805 working_set.add_variable(variable_name, span, Type::Any, false);
3806
3807 if flags.len() == 1 {
3809 args.push(Arg::Flag {
3810 flag: Flag {
3811 arg: None,
3812 desc: String::new(),
3813 long,
3814 short: None,
3815 required: false,
3816 var_id: Some(var_id),
3817 default_value: None,
3818 },
3819 type_annotated: false,
3820 });
3821 } else if flags.len() >= 3 {
3822 working_set.error(ParseError::Expected(
3823 "only one short flag alternative",
3824 span,
3825 ));
3826 } else {
3827 let short_flag = &flags[1];
3828 let short_flag = if !short_flag.starts_with(b"-")
3829 || !short_flag.ends_with(b")")
3830 {
3831 working_set.error(ParseError::Expected(
3832 "short flag alternative for the long flag",
3833 span,
3834 ));
3835 short_flag
3836 } else {
3837 &short_flag[1..(short_flag.len() - 1)]
3839 };
3840 let short_flag =
3844 String::from_utf8_lossy(short_flag).to_string();
3845 let chars: Vec<char> = short_flag.chars().collect();
3846 let long = String::from_utf8_lossy(&flags[0][2..]).to_string();
3847 let mut variable_name = flags[0][2..].to_vec();
3848
3849 (0..variable_name.len()).for_each(|idx| {
3850 if variable_name[idx] == b'-' {
3851 variable_name[idx] = b'_';
3852 }
3853 });
3854
3855 if !is_variable(&variable_name) {
3856 working_set.error(ParseError::Expected(
3857 "valid variable name for this short flag",
3858 span,
3859 ))
3860 }
3861
3862 let var_id = working_set.add_variable(
3863 variable_name,
3864 span,
3865 Type::Any,
3866 false,
3867 );
3868
3869 if chars.len() == 1 {
3870 args.push(Arg::Flag {
3871 flag: Flag {
3872 arg: None,
3873 desc: String::new(),
3874 long,
3875 short: Some(chars[0]),
3876 required: false,
3877 var_id: Some(var_id),
3878 default_value: None,
3879 },
3880 type_annotated: false,
3881 });
3882 } else {
3883 working_set.error(ParseError::Expected("short flag", span));
3884 }
3885 }
3886 parse_mode = ParseMode::Arg;
3887 }
3888 else if contents.starts_with(b"-") && contents.len() > 1 {
3890 let short_flag = &contents[1..];
3891 let short_flag = String::from_utf8_lossy(short_flag).to_string();
3892 let chars: Vec<char> = short_flag.chars().collect();
3893
3894 if chars.len() > 1 {
3895 working_set.error(ParseError::Expected("short flag", span));
3896 }
3897
3898 let mut encoded_var_name = vec![0u8; 4];
3899 let len = chars[0].encode_utf8(&mut encoded_var_name).len();
3900 let variable_name = encoded_var_name[0..len].to_vec();
3901
3902 if !is_variable(&variable_name) {
3903 working_set.error(ParseError::Expected(
3904 "valid variable name for this short flag",
3905 span,
3906 ))
3907 }
3908
3909 let var_id =
3910 working_set.add_variable(variable_name, span, Type::Any, false);
3911
3912 args.push(Arg::Flag {
3913 flag: Flag {
3914 arg: None,
3915 desc: String::new(),
3916 long: String::new(),
3917 short: Some(chars[0]),
3918 required: false,
3919 var_id: Some(var_id),
3920 default_value: None,
3921 },
3922 type_annotated: false,
3923 });
3924 parse_mode = ParseMode::Arg;
3925 }
3926 else if contents.starts_with(b"(-") {
3929 if matches!(parse_mode, ParseMode::AfterCommaArg) {
3930 working_set
3931 .error(ParseError::Expected("parameter or flag", span));
3932 }
3933 let short_flag = &contents[2..];
3934
3935 let short_flag = if !short_flag.ends_with(b")") {
3936 working_set.error(ParseError::Expected("short flag", span));
3937 short_flag
3938 } else {
3939 &short_flag[..(short_flag.len() - 1)]
3940 };
3941
3942 let short_flag = String::from_utf8_lossy(short_flag).to_string();
3943 let chars: Vec<char> = short_flag.chars().collect();
3944
3945 if chars.len() == 1 {
3946 match args.last_mut() {
3947 Some(Arg::Flag { flag, .. }) => {
3948 if flag.short.is_some() {
3949 working_set.error(ParseError::Expected(
3950 "one short flag",
3951 span,
3952 ));
3953 } else {
3954 flag.short = Some(chars[0]);
3955 }
3956 }
3957 _ => {
3958 working_set
3959 .error(ParseError::Expected("unknown flag", span));
3960 }
3961 }
3962 } else {
3963 working_set.error(ParseError::Expected("short flag", span));
3964 }
3965 }
3966 else if contents.ends_with(b"?") {
3968 let contents: Vec<_> = contents[..(contents.len() - 1)].into();
3969 let name = String::from_utf8_lossy(&contents).to_string();
3970
3971 if !is_variable(&contents) {
3972 working_set.error(ParseError::Expected(
3973 "valid variable name for this optional parameter",
3974 span,
3975 ))
3976 }
3977
3978 let var_id =
3979 working_set.add_variable(contents, span, Type::Any, false);
3980
3981 args.push(Arg::Positional {
3982 arg: PositionalArg {
3983 desc: String::new(),
3984 name,
3985 shape: SyntaxShape::Any,
3986 var_id: Some(var_id),
3987 default_value: None,
3988 },
3989 required: false,
3990 type_annotated: false,
3991 });
3992 parse_mode = ParseMode::Arg;
3993 }
3994 else if let Some(contents) = contents.strip_prefix(b"...") {
3996 let name = String::from_utf8_lossy(contents).to_string();
3997 let contents_vec: Vec<u8> = contents.to_vec();
3998
3999 if !is_variable(&contents_vec) {
4000 working_set.error(ParseError::Expected(
4001 "valid variable name for this rest parameter",
4002 span,
4003 ))
4004 }
4005
4006 let var_id =
4007 working_set.add_variable(contents_vec, span, Type::Any, false);
4008
4009 args.push(Arg::RestPositional(PositionalArg {
4010 desc: String::new(),
4011 name,
4012 shape: SyntaxShape::Any,
4013 var_id: Some(var_id),
4014 default_value: None,
4015 }));
4016 parse_mode = ParseMode::Arg;
4017 }
4018 else {
4020 let name = String::from_utf8_lossy(&contents).to_string();
4021 let contents_vec = contents.to_vec();
4022
4023 if !is_variable(&contents_vec) {
4024 working_set.error(ParseError::Expected(
4025 "valid variable name for this parameter",
4026 span,
4027 ))
4028 }
4029
4030 let var_id =
4031 working_set.add_variable(contents_vec, span, Type::Any, false);
4032
4033 args.push(Arg::Positional {
4035 arg: PositionalArg {
4036 desc: String::new(),
4037 name,
4038 shape: SyntaxShape::Any,
4039 var_id: Some(var_id),
4040 default_value: None,
4041 },
4042 required: true,
4043 type_annotated: false,
4044 });
4045 parse_mode = ParseMode::Arg;
4046 }
4047 }
4048 ParseMode::Type => {
4049 if let Some(last) = args.last_mut() {
4050 let syntax_shape = parse_shape_name(
4051 working_set,
4052 &contents,
4053 span,
4054 ShapeDescriptorUse::Argument,
4055 );
4056 match last {
4058 Arg::Positional {
4059 arg: PositionalArg { shape, var_id, .. },
4060 required: _,
4061 type_annotated,
4062 } => {
4063 working_set.set_variable_type(var_id.expect("internal error: all custom parameters must have var_ids"), syntax_shape.to_type());
4064 *shape = syntax_shape;
4065 *type_annotated = true;
4066 }
4067 Arg::RestPositional(PositionalArg {
4068 shape, var_id, ..
4069 }) => {
4070 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())));
4071 *shape = syntax_shape;
4072 }
4073 Arg::Flag {
4074 flag: Flag { arg, var_id, .. },
4075 type_annotated,
4076 } => {
4077 working_set.set_variable_type(var_id.expect("internal error: all custom parameters must have var_ids"), syntax_shape.to_type());
4078 if syntax_shape == SyntaxShape::Boolean {
4079 working_set.error(ParseError::LabeledError(
4080 "Type annotations are not allowed for boolean switches.".to_string(),
4081 "Remove the `: bool` type annotation.".to_string(),
4082 span,
4083 ));
4084 }
4085 *arg = Some(syntax_shape);
4086 *type_annotated = true;
4087 }
4088 }
4089 }
4090 parse_mode = ParseMode::AfterType;
4091 }
4092 ParseMode::DefaultValue => {
4093 if let Some(last) = args.last_mut() {
4094 let expression = parse_value(working_set, span, &SyntaxShape::Any);
4095
4096 match last {
4098 Arg::Positional {
4099 arg:
4100 PositionalArg {
4101 shape,
4102 var_id,
4103 default_value,
4104 ..
4105 },
4106 required,
4107 type_annotated,
4108 } => {
4109 let var_id = var_id.expect("internal error: all custom parameters must have var_ids");
4110 let var_type = &working_set.get_variable(var_id).ty;
4111 match var_type {
4112 Type::Any => {
4113 if !*type_annotated {
4114 working_set.set_variable_type(
4115 var_id,
4116 expression.ty.clone(),
4117 );
4118 }
4119 }
4120 _ => {
4121 if !type_compatible(var_type, &expression.ty) {
4122 working_set.error(
4123 ParseError::AssignmentMismatch(
4124 "Default value wrong type".into(),
4125 format!(
4126 "expected default value to be `{var_type}`"
4127 ),
4128 expression.span,
4129 ),
4130 )
4131 }
4132 }
4133 }
4134
4135 *default_value = if let Ok(constant) =
4136 eval_constant(working_set, &expression)
4137 {
4138 Some(constant)
4139 } else {
4140 working_set.error(ParseError::NonConstantDefaultValue(
4141 expression.span,
4142 ));
4143 None
4144 };
4145
4146 if !*type_annotated {
4147 *shape = expression.ty.to_shape();
4148 }
4149 *required = false;
4150 }
4151 Arg::RestPositional(..) => {
4152 working_set.error(ParseError::AssignmentMismatch(
4153 "Rest parameter was given a default value".into(),
4154 "can't have default value".into(),
4155 expression.span,
4156 ))
4157 }
4158 Arg::Flag {
4159 flag:
4160 Flag {
4161 arg,
4162 var_id,
4163 default_value,
4164 ..
4165 },
4166 type_annotated,
4167 } => {
4168 let expression_span = expression.span;
4169
4170 *default_value = if let Ok(value) =
4171 eval_constant(working_set, &expression)
4172 {
4173 Some(value)
4174 } else {
4175 working_set.error(ParseError::NonConstantDefaultValue(
4176 expression_span,
4177 ));
4178 None
4179 };
4180
4181 let var_id = var_id.expect("internal error: all custom parameters must have var_ids");
4182 let var_type = &working_set.get_variable(var_id).ty;
4183 let expression_ty = expression.ty.clone();
4184
4185 match var_type {
4188 Type::Any => {
4189 if !*type_annotated {
4190 *arg = Some(expression_ty.to_shape());
4191 working_set
4192 .set_variable_type(var_id, expression_ty);
4193 }
4194 }
4195 t => {
4196 if !type_compatible(t, &expression_ty) {
4197 working_set.error(
4198 ParseError::AssignmentMismatch(
4199 "Default value is the wrong type"
4200 .into(),
4201 format!(
4202 "expected default value to be `{t}`"
4203 ),
4204 expression_span,
4205 ),
4206 )
4207 }
4208 }
4209 }
4210 }
4211 }
4212 }
4213 parse_mode = ParseMode::Arg;
4214 }
4215 }
4216 }
4217 }
4218 Token {
4219 contents: crate::TokenContents::Comment,
4220 span,
4221 } => {
4222 let contents = working_set.get_span_contents(Span::new(span.start + 1, span.end));
4223
4224 let mut contents = String::from_utf8_lossy(contents).to_string();
4225 contents = contents.trim().into();
4226
4227 if let Some(last) = args.last_mut() {
4228 match last {
4229 Arg::Flag { flag, .. } => {
4230 if !flag.desc.is_empty() {
4231 flag.desc.push('\n');
4232 }
4233 flag.desc.push_str(&contents);
4234 }
4235 Arg::Positional {
4236 arg: positional, ..
4237 } => {
4238 if !positional.desc.is_empty() {
4239 positional.desc.push('\n');
4240 }
4241 positional.desc.push_str(&contents);
4242 }
4243 Arg::RestPositional(positional) => {
4244 if !positional.desc.is_empty() {
4245 positional.desc.push('\n');
4246 }
4247 positional.desc.push_str(&contents);
4248 }
4249 }
4250 }
4251 }
4252 _ => {}
4253 }
4254 }
4255
4256 let mut sig = Signature::new(String::new());
4257
4258 for arg in args {
4259 match arg {
4260 Arg::Positional {
4261 arg: positional,
4262 required,
4263 ..
4264 } => {
4265 if required {
4266 if !sig.optional_positional.is_empty() {
4267 working_set.error(ParseError::RequiredAfterOptional(
4268 positional.name.clone(),
4269 span,
4270 ))
4271 }
4272 sig.required_positional.push(positional)
4273 } else {
4274 sig.optional_positional.push(positional)
4275 }
4276 }
4277 Arg::Flag { flag, .. } => sig.named.push(flag),
4278 Arg::RestPositional(positional) => {
4279 if positional.name.is_empty() {
4280 working_set.error(ParseError::RestNeedsName(span))
4281 } else if sig.rest_positional.is_none() {
4282 sig.rest_positional = Some(PositionalArg {
4283 name: positional.name,
4284 ..positional
4285 })
4286 } else {
4287 working_set.error(ParseError::MultipleRestParams(span))
4289 }
4290 }
4291 }
4292 }
4293
4294 Box::new(sig)
4295}
4296
4297pub fn parse_list_expression(
4298 working_set: &mut StateWorkingSet,
4299 span: Span,
4300 element_shape: &SyntaxShape,
4301) -> Expression {
4302 let bytes = working_set.get_span_contents(span);
4303
4304 let mut start = span.start;
4305 let mut end = span.end;
4306
4307 if bytes.starts_with(b"[") {
4308 start += 1;
4309 }
4310 if bytes.ends_with(b"]") {
4311 end -= 1;
4312 } else {
4313 working_set.error(ParseError::Unclosed("]".into(), Span::new(end, end)));
4314 }
4315
4316 let inner_span = Span::new(start, end);
4317 let source = working_set.get_span_contents(inner_span);
4318
4319 let (output, err) = lex(source, inner_span.start, &[b'\n', b'\r', b','], &[], true);
4320 if let Some(err) = err {
4321 working_set.error(err)
4322 }
4323
4324 let (mut output, err) = lite_parse(&output, working_set);
4325 if let Some(err) = err {
4326 working_set.error(err)
4327 }
4328
4329 let mut args = vec![];
4330
4331 let mut contained_type: Option<Type> = None;
4332
4333 if !output.block.is_empty() {
4334 for mut command in output.block.remove(0).commands {
4335 let mut spans_idx = 0;
4336
4337 while spans_idx < command.parts.len() {
4338 let curr_span = command.parts[spans_idx];
4339 let curr_tok = working_set.get_span_contents(curr_span);
4340 let (arg, ty) = if curr_tok.starts_with(b"...")
4341 && curr_tok.len() > 3
4342 && (curr_tok[3] == b'$' || curr_tok[3] == b'[' || curr_tok[3] == b'(')
4343 {
4344 command.parts[spans_idx] = Span::new(curr_span.start + 3, curr_span.end);
4347 let spread_arg = parse_multispan_value(
4348 working_set,
4349 &command.parts,
4350 &mut spans_idx,
4351 &SyntaxShape::List(Box::new(element_shape.clone())),
4352 );
4353 let elem_ty = match &spread_arg.ty {
4354 Type::List(elem_ty) => *elem_ty.clone(),
4355 _ => Type::Any,
4356 };
4357 let span = Span::new(curr_span.start, curr_span.start + 3);
4358 (ListItem::Spread(span, spread_arg), elem_ty)
4359 } else {
4360 let arg = parse_multispan_value(
4361 working_set,
4362 &command.parts,
4363 &mut spans_idx,
4364 element_shape,
4365 );
4366 let ty = arg.ty.clone();
4367 (ListItem::Item(arg), ty)
4368 };
4369
4370 if let Some(ref ctype) = contained_type {
4371 if *ctype != ty {
4372 contained_type = Some(Type::Any);
4373 }
4374 } else {
4375 contained_type = Some(ty);
4376 }
4377
4378 args.push(arg);
4379
4380 spans_idx += 1;
4381 }
4382 }
4383 }
4384
4385 Expression::new(
4386 working_set,
4387 Expr::List(args),
4388 span,
4389 Type::List(Box::new(if let Some(ty) = contained_type {
4390 ty
4391 } else {
4392 Type::Any
4393 })),
4394 )
4395}
4396
4397fn parse_table_row(
4398 working_set: &mut StateWorkingSet,
4399 span: Span,
4400) -> Result<(Vec<Expression>, Span), Span> {
4401 let list = parse_list_expression(working_set, span, &SyntaxShape::Any);
4402 let Expression {
4403 expr: Expr::List(list),
4404 span,
4405 ..
4406 } = list
4407 else {
4408 unreachable!("the item must be a list")
4409 };
4410
4411 list.into_iter()
4412 .map(|item| match item {
4413 ListItem::Item(expr) => Ok(expr),
4414 ListItem::Spread(_, spread) => Err(spread.span),
4415 })
4416 .collect::<Result<_, _>>()
4417 .map(|exprs| (exprs, span))
4418}
4419
4420fn parse_table_expression(
4421 working_set: &mut StateWorkingSet,
4422 span: Span,
4423 list_element_shape: &SyntaxShape,
4424) -> Expression {
4425 let bytes = working_set.get_span_contents(span);
4426 let inner_span = {
4427 let start = if bytes.starts_with(b"[") {
4428 span.start + 1
4429 } else {
4430 span.start
4431 };
4432
4433 let end = if bytes.ends_with(b"]") {
4434 span.end - 1
4435 } else {
4436 let end = span.end;
4437 working_set.error(ParseError::Unclosed("]".into(), Span::new(end, end)));
4438 span.end
4439 };
4440
4441 Span::new(start, end)
4442 };
4443
4444 let source = working_set.get_span_contents(inner_span);
4445 let (tokens, err) = lex(source, inner_span.start, &[b'\n', b'\r', b','], &[], true);
4446 if let Some(err) = err {
4447 working_set.error(err);
4448 }
4449
4450 let [first, second, rest @ ..] = &tokens[..] else {
4453 return parse_list_expression(working_set, span, list_element_shape);
4454 };
4455 if !working_set.get_span_contents(first.span).starts_with(b"[")
4456 || second.contents != TokenContents::Semicolon
4457 || rest.is_empty()
4458 {
4459 return parse_list_expression(working_set, span, list_element_shape);
4460 };
4461 let head = parse_table_row(working_set, first.span);
4462
4463 let errors = working_set.parse_errors.len();
4464
4465 let (head, rows) = match head {
4466 Ok((head, _)) => {
4467 let rows = rest
4468 .iter()
4469 .filter_map(|it| {
4470 use std::cmp::Ordering;
4471
4472 match working_set.get_span_contents(it.span) {
4473 b"," => None,
4474 text if !text.starts_with(b"[") => {
4475 let err = ParseError::LabeledErrorWithHelp {
4476 error: String::from("Table item not list"),
4477 label: String::from("not a list"),
4478 span: it.span,
4479 help: String::from("All table items must be lists"),
4480 };
4481 working_set.error(err);
4482 None
4483 }
4484 _ => match parse_table_row(working_set, it.span) {
4485 Ok((list, span)) => {
4486 match list.len().cmp(&head.len()) {
4487 Ordering::Less => {
4488 let err = ParseError::MissingColumns(head.len(), span);
4489 working_set.error(err);
4490 }
4491 Ordering::Greater => {
4492 let span = {
4493 let start = list[head.len()].span.start;
4494 let end = span.end;
4495 Span::new(start, end)
4496 };
4497 let err = ParseError::ExtraColumns(head.len(), span);
4498 working_set.error(err);
4499 }
4500 Ordering::Equal => {}
4501 }
4502 Some(list)
4503 }
4504 Err(span) => {
4505 let err = ParseError::LabeledError(
4506 String::from("Cannot spread in a table row"),
4507 String::from("invalid spread here"),
4508 span,
4509 );
4510 working_set.error(err);
4511 None
4512 }
4513 },
4514 }
4515 })
4516 .collect();
4517
4518 (head, rows)
4519 }
4520 Err(span) => {
4521 let err = ParseError::LabeledError(
4522 String::from("Cannot spread in a table row"),
4523 String::from("invalid spread here"),
4524 span,
4525 );
4526 working_set.error(err);
4527 (Vec::new(), Vec::new())
4528 }
4529 };
4530
4531 let ty = if working_set.parse_errors.len() == errors {
4532 let (ty, errs) = table_type(&head, &rows);
4533 working_set.parse_errors.extend(errs);
4534 ty
4535 } else {
4536 Type::table()
4537 };
4538
4539 let table = Table {
4540 columns: head.into(),
4541 rows: rows.into_iter().map(Into::into).collect(),
4542 };
4543
4544 Expression::new(working_set, Expr::Table(table), span, ty)
4545}
4546
4547fn table_type(head: &[Expression], rows: &[Vec<Expression>]) -> (Type, Vec<ParseError>) {
4548 let mut errors = vec![];
4549 let mut rows = rows.to_vec();
4550 let mut mk_ty = || -> Type {
4551 rows.iter_mut()
4552 .map(|row| row.pop().map(|x| x.ty).unwrap_or_default())
4553 .reduce(|acc, ty| -> Type {
4554 if type_compatible(&acc, &ty) {
4555 ty
4556 } else {
4557 Type::Any
4558 }
4559 })
4560 .unwrap_or_default()
4561 };
4562
4563 let mk_error = |span| ParseError::LabeledErrorWithHelp {
4564 error: "Table column name not string".into(),
4565 label: "must be a string".into(),
4566 help: "Table column names should be able to be converted into strings".into(),
4567 span,
4568 };
4569
4570 let mut ty = head
4571 .iter()
4572 .rev()
4573 .map(|expr| {
4574 if let Some(str) = expr.as_string() {
4575 str
4576 } else {
4577 errors.push(mk_error(expr.span));
4578 String::from("{ column }")
4579 }
4580 })
4581 .map(|title| (title, mk_ty()))
4582 .collect_vec();
4583
4584 ty.reverse();
4585
4586 (Type::Table(ty.into()), errors)
4587}
4588
4589pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) -> Expression {
4590 trace!("parsing: block expression");
4591
4592 let bytes = working_set.get_span_contents(span);
4593
4594 let mut start = span.start;
4595 let mut end = span.end;
4596
4597 if bytes.starts_with(b"{") {
4598 start += 1;
4599 } else {
4600 working_set.error(ParseError::Expected("block", span));
4601 return garbage(working_set, span);
4602 }
4603 if bytes.ends_with(b"}") {
4604 end -= 1;
4605 } else {
4606 working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
4607 }
4608
4609 let inner_span = Span::new(start, end);
4610
4611 let source = working_set.get_span_contents(inner_span);
4612
4613 let (output, err) = lex(source, start, &[], &[], false);
4614 if let Some(err) = err {
4615 working_set.error(err);
4616 }
4617
4618 working_set.enter_scope();
4619
4620 let (signature, amt_to_skip): (Option<(Box<Signature>, Span)>, usize) = match output.first() {
4622 Some(Token {
4623 contents: TokenContents::Pipe,
4624 span,
4625 }) => {
4626 working_set.error(ParseError::Expected("block but found closure", *span));
4627 (None, 0)
4628 }
4629 _ => (None, 0),
4630 };
4631
4632 let mut output = parse_block(working_set, &output[amt_to_skip..], span, false, false);
4633
4634 if let Some(signature) = signature {
4635 output.signature = signature.0;
4636 }
4637
4638 output.span = Some(span);
4639
4640 working_set.exit_scope();
4641
4642 let block_id = working_set.add_block(Arc::new(output));
4643
4644 Expression::new(working_set, Expr::Block(block_id), span, Type::Any)
4645}
4646
4647pub fn parse_match_block_expression(working_set: &mut StateWorkingSet, span: Span) -> Expression {
4648 let bytes = working_set.get_span_contents(span);
4649
4650 let mut start = span.start;
4651 let mut end = span.end;
4652
4653 if bytes.starts_with(b"{") {
4654 start += 1;
4655 } else {
4656 working_set.error(ParseError::Expected("closure", span));
4657 return garbage(working_set, span);
4658 }
4659 if bytes.ends_with(b"}") {
4660 end -= 1;
4661 } else {
4662 working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
4663 }
4664
4665 let inner_span = Span::new(start, end);
4666
4667 let source = working_set.get_span_contents(inner_span);
4668
4669 let (output, err) = lex(source, start, &[b' ', b'\r', b'\n', b',', b'|'], &[], true);
4670 if let Some(err) = err {
4671 working_set.error(err);
4672 }
4673
4674 let mut position = 0;
4675
4676 let mut output_matches = vec![];
4677
4678 while position < output.len() {
4679 working_set.enter_scope();
4682
4683 let mut pattern = parse_pattern(working_set, output[position].span);
4685
4686 position += 1;
4687
4688 if position >= output.len() {
4689 working_set.error(ParseError::Mismatch(
4690 "=>".into(),
4691 "end of input".into(),
4692 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4693 ));
4694
4695 working_set.exit_scope();
4696 break;
4697 }
4698
4699 let mut connector = working_set.get_span_contents(output[position].span);
4700
4701 if connector == b"|" && position < output.len() {
4703 let mut or_pattern = vec![pattern];
4704
4705 while connector == b"|" && position < output.len() {
4706 connector = b"";
4707
4708 position += 1;
4709
4710 if position >= output.len() {
4711 working_set.error(ParseError::Mismatch(
4712 "pattern".into(),
4713 "end of input".into(),
4714 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4715 ));
4716 break;
4717 }
4718
4719 let pattern = parse_pattern(working_set, output[position].span);
4720 or_pattern.push(pattern);
4721
4722 position += 1;
4723 if position >= output.len() {
4724 working_set.error(ParseError::Mismatch(
4725 "=>".into(),
4726 "end of input".into(),
4727 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4728 ));
4729 break;
4730 } else {
4731 connector = working_set.get_span_contents(output[position].span);
4732 }
4733 }
4734
4735 let start = or_pattern
4736 .first()
4737 .expect("internal error: unexpected state of or-pattern")
4738 .span
4739 .start;
4740 let end = or_pattern
4741 .last()
4742 .expect("internal error: unexpected state of or-pattern")
4743 .span
4744 .end;
4745
4746 pattern = MatchPattern {
4747 pattern: Pattern::Or(or_pattern),
4748 guard: None,
4749 span: Span::new(start, end),
4750 }
4751 } else if connector == b"if" {
4753 let if_end = {
4754 let end = output[position].span.end;
4755 Span::new(end, end)
4756 };
4757
4758 position += 1;
4759
4760 let mk_err = || ParseError::LabeledErrorWithHelp {
4761 error: "Match guard without an expression".into(),
4762 label: "expected an expression".into(),
4763 help: "The `if` keyword must be followed with an expression".into(),
4764 span: if_end,
4765 };
4766
4767 if output.get(position).is_none() {
4768 working_set.error(mk_err());
4769 return garbage(working_set, span);
4770 };
4771
4772 let (tokens, found) = if let Some((pos, _)) = output[position..]
4773 .iter()
4774 .find_position(|t| working_set.get_span_contents(t.span) == b"=>")
4775 {
4776 if position + pos == position {
4777 working_set.error(mk_err());
4778 return garbage(working_set, span);
4779 }
4780
4781 (&output[position..position + pos], true)
4782 } else {
4783 (&output[position..], false)
4784 };
4785
4786 let mut start = 0;
4787 let guard = parse_multispan_value(
4788 working_set,
4789 &tokens.iter().map(|tok| tok.span).collect_vec(),
4790 &mut start,
4791 &SyntaxShape::MathExpression,
4792 );
4793
4794 pattern.guard = Some(Box::new(guard));
4795 position += if found { start + 1 } else { start };
4796 connector = working_set.get_span_contents(output[position].span);
4797 }
4798 if connector != b"=>" {
4800 working_set.error(ParseError::Mismatch(
4801 "=>".into(),
4802 "end of input".into(),
4803 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4804 ));
4805 } else {
4806 position += 1;
4807 }
4808
4809 if position >= output.len() {
4811 working_set.error(ParseError::Mismatch(
4812 "match result".into(),
4813 "end of input".into(),
4814 Span::new(output[position - 1].span.end, output[position - 1].span.end),
4815 ));
4816
4817 working_set.exit_scope();
4818 break;
4819 }
4820
4821 let result = parse_multispan_value(
4822 working_set,
4823 &[output[position].span],
4824 &mut 0,
4825 &SyntaxShape::OneOf(vec![SyntaxShape::Block, SyntaxShape::Expression]),
4826 );
4827 position += 1;
4828 working_set.exit_scope();
4829
4830 output_matches.push((pattern, result));
4831 }
4832
4833 Expression::new(
4834 working_set,
4835 Expr::MatchBlock(output_matches),
4836 span,
4837 Type::Any,
4838 )
4839}
4840
4841pub fn parse_closure_expression(
4842 working_set: &mut StateWorkingSet,
4843 shape: &SyntaxShape,
4844 span: Span,
4845) -> Expression {
4846 trace!("parsing: closure expression");
4847
4848 let bytes = working_set.get_span_contents(span);
4849
4850 let mut start = span.start;
4851 let mut end = span.end;
4852
4853 if bytes.starts_with(b"{") {
4854 start += 1;
4855 } else {
4856 working_set.error(ParseError::Expected("closure", span));
4857 return garbage(working_set, span);
4858 }
4859 if bytes.ends_with(b"}") {
4860 end -= 1;
4861 } else {
4862 working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
4863 }
4864
4865 let inner_span = Span::new(start, end);
4866
4867 let source = working_set.get_span_contents(inner_span);
4868
4869 let (output, err) = lex(source, start, &[], &[], false);
4870 if let Some(err) = err {
4871 working_set.error(err);
4872 }
4873
4874 working_set.enter_scope();
4875
4876 let (signature, amt_to_skip): (Option<(Box<Signature>, Span)>, usize) = match output.first() {
4878 Some(Token {
4879 contents: TokenContents::Pipe,
4880 span,
4881 }) => {
4882 let start_point = span.start;
4884 let mut token_iter = output.iter().enumerate().skip(1);
4885 let mut end_span = None;
4886 let mut amt_to_skip = 1;
4887
4888 for token in &mut token_iter {
4889 if let Token {
4890 contents: TokenContents::Pipe,
4891 span,
4892 } = token.1
4893 {
4894 end_span = Some(span);
4895 amt_to_skip += token.0;
4896 break;
4897 }
4898 }
4899
4900 let end_point = if let Some(span) = end_span {
4901 span.end
4902 } else {
4903 working_set.error(ParseError::Unclosed("|".into(), Span::new(end, end)));
4904 end
4905 };
4906
4907 let signature_span = Span::new(start_point, end_point);
4908 let signature = parse_signature_helper(working_set, signature_span);
4909
4910 (Some((signature, signature_span)), amt_to_skip)
4911 }
4912 Some(Token {
4913 contents: TokenContents::PipePipe,
4914 span,
4915 }) => (
4916 Some((Box::new(Signature::new("closure".to_string())), *span)),
4917 1,
4918 ),
4919 _ => (None, 0),
4920 };
4921
4922 if let SyntaxShape::Closure(Some(v)) = shape {
4924 if let Some((sig, sig_span)) = &signature {
4925 if sig.num_positionals() > v.len() {
4926 working_set.error(ParseError::ExpectedWithStringMsg(
4927 format!(
4928 "{} closure parameter{}",
4929 v.len(),
4930 if v.len() > 1 { "s" } else { "" }
4931 ),
4932 *sig_span,
4933 ));
4934 }
4935
4936 for (expected, PositionalArg { name, shape, .. }) in
4937 v.iter().zip(sig.required_positional.iter())
4938 {
4939 if expected != shape && *shape != SyntaxShape::Any {
4940 working_set.error(ParseError::ParameterMismatchType(
4941 name.to_owned(),
4942 expected.to_string(),
4943 shape.to_string(),
4944 *sig_span,
4945 ));
4946 }
4947 }
4948 }
4949 }
4950
4951 let mut output = parse_block(working_set, &output[amt_to_skip..], span, false, false);
4952
4953 if let Some(signature) = signature {
4954 output.signature = signature.0;
4955 }
4956
4957 output.span = Some(span);
4958
4959 working_set.exit_scope();
4960
4961 let block_id = working_set.add_block(Arc::new(output));
4962
4963 Expression::new(working_set, Expr::Closure(block_id), span, Type::Closure)
4964}
4965
4966pub fn parse_value(
4967 working_set: &mut StateWorkingSet,
4968 span: Span,
4969 shape: &SyntaxShape,
4970) -> Expression {
4971 trace!("parsing: value: {}", shape);
4972
4973 let bytes = working_set.get_span_contents(span);
4974
4975 if bytes.is_empty() {
4976 working_set.error(ParseError::IncompleteParser(span));
4977 return garbage(working_set, span);
4978 }
4979
4980 match bytes {
4982 b"true" => {
4983 if matches!(shape, SyntaxShape::Boolean) || matches!(shape, SyntaxShape::Any) {
4984 return Expression::new(working_set, Expr::Bool(true), span, Type::Bool);
4985 } else {
4986 working_set.error(ParseError::Expected("non-boolean value", span));
4987 return Expression::garbage(working_set, span);
4988 }
4989 }
4990 b"false" => {
4991 if matches!(shape, SyntaxShape::Boolean) || matches!(shape, SyntaxShape::Any) {
4992 return Expression::new(working_set, Expr::Bool(false), span, Type::Bool);
4993 } else {
4994 working_set.error(ParseError::Expected("non-boolean value", span));
4995 return Expression::garbage(working_set, span);
4996 }
4997 }
4998 b"null" => {
4999 return Expression::new(working_set, Expr::Nothing, span, Type::Nothing);
5000 }
5001 b"-inf" | b"inf" | b"NaN" => {
5002 return parse_float(working_set, span);
5003 }
5004 _ => {}
5005 }
5006
5007 match bytes[0] {
5008 b'$' => return parse_dollar_expr(working_set, span),
5009 b'(' => return parse_paren_expr(working_set, span, shape),
5010 b'{' => return parse_brace_expr(working_set, span, shape),
5011 b'[' => match shape {
5012 SyntaxShape::Any
5013 | SyntaxShape::List(_)
5014 | SyntaxShape::Table(_)
5015 | SyntaxShape::Signature
5016 | SyntaxShape::Filepath
5017 | SyntaxShape::String
5018 | SyntaxShape::GlobPattern
5019 | SyntaxShape::ExternalArgument => {}
5020 SyntaxShape::OneOf(possible_shapes) => {
5021 if !possible_shapes
5022 .iter()
5023 .any(|s| matches!(s, SyntaxShape::List(_)))
5024 {
5025 working_set.error(ParseError::Expected("non-[] value", span));
5026 return Expression::garbage(working_set, span);
5027 }
5028 }
5029 _ => {
5030 working_set.error(ParseError::Expected("non-[] value", span));
5031 return Expression::garbage(working_set, span);
5032 }
5033 },
5034 b'r' if bytes.len() > 1 && bytes[1] == b'#' => {
5035 return parse_raw_string(working_set, span);
5036 }
5037 _ => {}
5038 }
5039
5040 match shape {
5041 SyntaxShape::CompleterWrapper(shape, custom_completion) => {
5042 let mut expression = parse_value(working_set, span, shape);
5043 expression.custom_completion = Some(*custom_completion);
5044 expression
5045 }
5046 SyntaxShape::Number => parse_number(working_set, span),
5047 SyntaxShape::Float => parse_float(working_set, span),
5048 SyntaxShape::Int => parse_int(working_set, span),
5049 SyntaxShape::Duration => parse_duration(working_set, span),
5050 SyntaxShape::DateTime => parse_datetime(working_set, span),
5051 SyntaxShape::Filesize => parse_filesize(working_set, span),
5052 SyntaxShape::Range => {
5053 parse_range(working_set, span).unwrap_or_else(|| garbage(working_set, span))
5054 }
5055 SyntaxShape::Filepath => parse_filepath(working_set, span),
5056 SyntaxShape::Directory => parse_directory(working_set, span),
5057 SyntaxShape::GlobPattern => parse_glob_pattern(working_set, span),
5058 SyntaxShape::String => parse_string(working_set, span),
5059 SyntaxShape::Binary => parse_binary(working_set, span),
5060 SyntaxShape::Signature => {
5061 if bytes.starts_with(b"[") {
5062 parse_signature(working_set, span)
5063 } else {
5064 working_set.error(ParseError::Expected("signature", span));
5065
5066 Expression::garbage(working_set, span)
5067 }
5068 }
5069 SyntaxShape::List(elem) => {
5070 if bytes.starts_with(b"[") {
5071 parse_table_expression(working_set, span, elem)
5072 } else {
5073 working_set.error(ParseError::Expected("list", span));
5074
5075 Expression::garbage(working_set, span)
5076 }
5077 }
5078 SyntaxShape::Table(_) => {
5079 if bytes.starts_with(b"[") {
5080 parse_table_expression(working_set, span, &SyntaxShape::Any)
5081 } else {
5082 working_set.error(ParseError::Expected("table", span));
5083
5084 Expression::garbage(working_set, span)
5085 }
5086 }
5087 SyntaxShape::CellPath => parse_simple_cell_path(working_set, span),
5088 SyntaxShape::Boolean => {
5089 if bytes == b"true" || bytes == b"false" {
5091 Expression::new(working_set, Expr::Bool(true), span, Type::Bool)
5092 } else {
5093 working_set.error(ParseError::Expected("bool", span));
5094
5095 Expression::garbage(working_set, span)
5096 }
5097 }
5098
5099 SyntaxShape::Block | SyntaxShape::Closure(..) | SyntaxShape::Record(_) => {
5102 working_set.error(ParseError::Expected("block, closure or record", span));
5103
5104 Expression::garbage(working_set, span)
5105 }
5106
5107 SyntaxShape::ExternalArgument => parse_regular_external_arg(working_set, span),
5108 SyntaxShape::OneOf(possible_shapes) => {
5109 parse_oneof(working_set, &[span], &mut 0, possible_shapes, false)
5110 }
5111
5112 SyntaxShape::Any => {
5113 if bytes.starts_with(b"[") {
5114 parse_full_cell_path(working_set, None, span)
5116 } else {
5117 let shapes = [
5118 SyntaxShape::Binary,
5119 SyntaxShape::Range,
5120 SyntaxShape::Filesize,
5121 SyntaxShape::Duration,
5122 SyntaxShape::DateTime,
5123 SyntaxShape::Int,
5124 SyntaxShape::Number,
5125 SyntaxShape::String,
5126 ];
5127 for shape in shapes.iter() {
5128 let starting_error_count = working_set.parse_errors.len();
5129
5130 let s = parse_value(working_set, span, shape);
5131
5132 if starting_error_count == working_set.parse_errors.len() {
5133 return s;
5134 } else {
5135 match working_set.parse_errors.get(starting_error_count) {
5136 Some(
5137 ParseError::Expected(_, _)
5138 | ParseError::ExpectedWithStringMsg(_, _),
5139 ) => {
5140 working_set.parse_errors.truncate(starting_error_count);
5141 continue;
5142 }
5143 _ => {
5144 return s;
5145 }
5146 }
5147 }
5148 }
5149 working_set.error(ParseError::Expected("any shape", span));
5150 garbage(working_set, span)
5151 }
5152 }
5153 x => {
5154 working_set.error(ParseError::ExpectedWithStringMsg(
5155 x.to_type().to_string(),
5156 span,
5157 ));
5158 garbage(working_set, span)
5159 }
5160 }
5161}
5162
5163pub fn parse_assignment_operator(working_set: &mut StateWorkingSet, span: Span) -> Expression {
5164 let contents = working_set.get_span_contents(span);
5165
5166 let operator = match contents {
5167 b"=" => Operator::Assignment(Assignment::Assign),
5168 b"+=" => Operator::Assignment(Assignment::AddAssign),
5169 b"-=" => Operator::Assignment(Assignment::SubtractAssign),
5170 b"*=" => Operator::Assignment(Assignment::MultiplyAssign),
5171 b"/=" => Operator::Assignment(Assignment::DivideAssign),
5172 b"++=" => Operator::Assignment(Assignment::ConcatenateAssign),
5173 _ => {
5174 working_set.error(ParseError::Expected("assignment operator", span));
5175 return garbage(working_set, span);
5176 }
5177 };
5178
5179 Expression::new(working_set, Expr::Operator(operator), span, Type::Any)
5180}
5181
5182pub fn parse_assignment_expression(
5183 working_set: &mut StateWorkingSet,
5184 spans: &[Span],
5185) -> Expression {
5186 trace!("parsing: assignment expression");
5187 let expr_span = Span::concat(spans);
5188
5189 let Some(op_index) = spans
5191 .iter()
5192 .position(|span| is_assignment_operator(working_set.get_span_contents(*span)))
5193 else {
5194 working_set.error(ParseError::Expected("assignment expression", expr_span));
5195 return garbage(working_set, expr_span);
5196 };
5197
5198 let lhs_spans = &spans[0..op_index];
5199 let op_span = spans[op_index];
5200 let rhs_spans = &spans[(op_index + 1)..];
5201
5202 if lhs_spans.is_empty() {
5203 working_set.error(ParseError::Expected(
5204 "left hand side of assignment",
5205 op_span,
5206 ));
5207 return garbage(working_set, expr_span);
5208 }
5209
5210 if rhs_spans.is_empty() {
5211 working_set.error(ParseError::Expected(
5212 "right hand side of assignment",
5213 op_span,
5214 ));
5215 return garbage(working_set, expr_span);
5216 }
5217
5218 let mut lhs = parse_expression(working_set, lhs_spans);
5220 match &lhs.expr {
5222 Expr::FullCellPath(p) => {
5223 if let Expr::Var(var_id) = p.head.expr {
5224 if var_id != nu_protocol::ENV_VARIABLE_ID
5225 && !working_set.get_variable(var_id).mutable
5226 {
5227 working_set.error(ParseError::AssignmentRequiresMutableVar(lhs.span))
5228 }
5229 }
5230 }
5231 _ => working_set.error(ParseError::AssignmentRequiresVar(lhs.span)),
5232 }
5233
5234 let mut operator = parse_assignment_operator(working_set, op_span);
5235
5236 let rhs_span = Span::concat(rhs_spans);
5238
5239 let (rhs_tokens, rhs_error) = lex(
5240 working_set.get_span_contents(rhs_span),
5241 rhs_span.start,
5242 &[],
5243 &[],
5244 false,
5245 );
5246 working_set.parse_errors.extend(rhs_error);
5247
5248 trace!("parsing: assignment right-hand side subexpression");
5249 let rhs_block = parse_block(working_set, &rhs_tokens, rhs_span, false, true);
5250 let rhs_ty = rhs_block.output_type();
5251
5252 if let Some(Expr::ExternalCall(head, ..)) = rhs_block
5256 .pipelines
5257 .first()
5258 .and_then(|pipeline| pipeline.elements.first())
5259 .map(|element| &element.expr.expr)
5260 {
5261 let contents = working_set.get_span_contents(Span {
5262 start: head.span.start - 1,
5263 end: head.span.end,
5264 });
5265 if !contents.starts_with(b"^") {
5266 working_set.parse_errors.push(ParseError::LabeledErrorWithHelp {
5267 error: "External command calls must be explicit in assignments".into(),
5268 label: "add a caret (^) before the command name if you intended to run and capture its output".into(),
5269 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(),
5270 span: head.span,
5271 });
5272 }
5273 }
5274
5275 let rhs_block_id = working_set.add_block(Arc::new(rhs_block));
5276 let mut rhs = Expression::new(
5277 working_set,
5278 Expr::Subexpression(rhs_block_id),
5279 rhs_span,
5280 rhs_ty,
5281 );
5282
5283 let (result_ty, err) = math_result_type(working_set, &mut lhs, &mut operator, &mut rhs);
5284 if let Some(err) = err {
5285 working_set.parse_errors.push(err);
5286 }
5287
5288 Expression::new(
5289 working_set,
5290 Expr::BinaryOp(Box::new(lhs), Box::new(operator), Box::new(rhs)),
5291 expr_span,
5292 result_ty,
5293 )
5294}
5295
5296pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expression {
5297 let contents = working_set.get_span_contents(span);
5298
5299 let operator = match contents {
5300 b"==" => Operator::Comparison(Comparison::Equal),
5301 b"!=" => Operator::Comparison(Comparison::NotEqual),
5302 b"<" => Operator::Comparison(Comparison::LessThan),
5303 b"<=" => Operator::Comparison(Comparison::LessThanOrEqual),
5304 b">" => Operator::Comparison(Comparison::GreaterThan),
5305 b">=" => Operator::Comparison(Comparison::GreaterThanOrEqual),
5306 b"=~" | b"like" => Operator::Comparison(Comparison::RegexMatch),
5307 b"!~" | b"not-like" => Operator::Comparison(Comparison::NotRegexMatch),
5308 b"in" => Operator::Comparison(Comparison::In),
5309 b"not-in" => Operator::Comparison(Comparison::NotIn),
5310 b"has" => Operator::Comparison(Comparison::Has),
5311 b"not-has" => Operator::Comparison(Comparison::NotHas),
5312 b"starts-with" => Operator::Comparison(Comparison::StartsWith),
5313 b"ends-with" => Operator::Comparison(Comparison::EndsWith),
5314 b"+" => Operator::Math(Math::Add),
5315 b"-" => Operator::Math(Math::Subtract),
5316 b"*" => Operator::Math(Math::Multiply),
5317 b"/" => Operator::Math(Math::Divide),
5318 b"//" => Operator::Math(Math::FloorDivide),
5319 b"mod" => Operator::Math(Math::Modulo),
5320 b"**" => Operator::Math(Math::Pow),
5321 b"++" => Operator::Math(Math::Concatenate),
5322 b"bit-or" => Operator::Bits(Bits::BitOr),
5323 b"bit-xor" => Operator::Bits(Bits::BitXor),
5324 b"bit-and" => Operator::Bits(Bits::BitAnd),
5325 b"bit-shl" => Operator::Bits(Bits::ShiftLeft),
5326 b"bit-shr" => Operator::Bits(Bits::ShiftRight),
5327 b"or" => Operator::Boolean(Boolean::Or),
5328 b"xor" => Operator::Boolean(Boolean::Xor),
5329 b"and" => Operator::Boolean(Boolean::And),
5330 pow @ (b"^" | b"pow") => {
5332 working_set.error(ParseError::UnknownOperator(
5333 match pow {
5334 b"^" => "^",
5335 b"pow" => "pow",
5336 _ => unreachable!(),
5337 },
5338 "Use '**' for exponentiation or 'bit-xor' for bitwise XOR.",
5339 span,
5340 ));
5341 return garbage(working_set, span);
5342 }
5343 equality @ (b"is" | b"===") => {
5344 working_set.error(ParseError::UnknownOperator(
5345 match equality {
5346 b"is" => "is",
5347 b"===" => "===",
5348 _ => unreachable!(),
5349 },
5350 "Did you mean '=='?",
5351 span,
5352 ));
5353 return garbage(working_set, span);
5354 }
5355 b"contains" => {
5356 working_set.error(ParseError::UnknownOperator(
5357 "contains",
5358 "Did you mean 'has'?",
5359 span,
5360 ));
5361 return garbage(working_set, span);
5362 }
5363 b"%" => {
5364 working_set.error(ParseError::UnknownOperator(
5365 "%",
5366 "Did you mean 'mod'?",
5367 span,
5368 ));
5369 return garbage(working_set, span);
5370 }
5371 b"&" => {
5372 working_set.error(ParseError::UnknownOperator(
5373 "&",
5374 "Did you mean 'bit-and'?",
5375 span,
5376 ));
5377 return garbage(working_set, span);
5378 }
5379 b"<<" => {
5380 working_set.error(ParseError::UnknownOperator(
5381 "<<",
5382 "Did you mean 'bit-shl'?",
5383 span,
5384 ));
5385 return garbage(working_set, span);
5386 }
5387 b">>" => {
5388 working_set.error(ParseError::UnknownOperator(
5389 ">>",
5390 "Did you mean 'bit-shr'?",
5391 span,
5392 ));
5393 return garbage(working_set, span);
5394 }
5395 bits @ (b"bits-and" | b"bits-xor" | b"bits-or" | b"bits-shl" | b"bits-shr") => {
5396 working_set.error(ParseError::UnknownOperator(
5397 match bits {
5398 b"bits-and" => "bits-and",
5399 b"bits-xor" => "bits-xor",
5400 b"bits-or" => "bits-or",
5401 b"bits-shl" => "bits-shl",
5402 b"bits-shr" => "bits-shr",
5403 _ => unreachable!(),
5404 },
5405 match bits {
5406 b"bits-and" => "Did you mean 'bit-and'?",
5407 b"bits-xor" => "Did you mean 'bit-xor'?",
5408 b"bits-or" => "Did you mean 'bit-or'?",
5409 b"bits-shl" => "Did you mean 'bit-shl'?",
5410 b"bits-shr" => "Did you mean 'bit-shr'?",
5411 _ => unreachable!(),
5412 },
5413 span,
5414 ));
5415 return garbage(working_set, span);
5416 }
5417 op if is_assignment_operator(op) => {
5418 working_set.error(ParseError::Expected("a non-assignment operator", span));
5419 return garbage(working_set, span);
5420 }
5421 _ => {
5422 working_set.error(ParseError::Expected("operator", span));
5423 return garbage(working_set, span);
5424 }
5425 };
5426
5427 Expression::new(working_set, Expr::Operator(operator), span, Type::Any)
5428}
5429
5430pub fn parse_math_expression(
5431 working_set: &mut StateWorkingSet,
5432 spans: &[Span],
5433 lhs_row_var_id: Option<VarId>,
5434) -> Expression {
5435 trace!("parsing: math expression");
5436
5437 let mut expr_stack: Vec<Expression> = vec![];
5448
5449 let mut idx = 0;
5450 let mut last_prec = u8::MAX;
5451
5452 let first_span = working_set.get_span_contents(spans[0]);
5453
5454 let mut not_start_spans = vec![];
5455
5456 if first_span == b"if" || first_span == b"match" {
5457 if spans.len() > 1 {
5459 return parse_call(working_set, spans, spans[0]);
5460 } else {
5461 working_set.error(ParseError::Expected(
5462 "expression",
5463 Span::new(spans[0].end, spans[0].end),
5464 ));
5465 return garbage(working_set, spans[0]);
5466 }
5467 } else if first_span == b"not" {
5468 not_start_spans.push(spans[idx].start);
5469 idx += 1;
5470 while idx < spans.len() {
5471 let next_value = working_set.get_span_contents(spans[idx]);
5472
5473 if next_value == b"not" {
5474 not_start_spans.push(spans[idx].start);
5475 idx += 1;
5476 } else {
5477 break;
5478 }
5479 }
5480
5481 if idx == spans.len() {
5482 working_set.error(ParseError::Expected(
5483 "expression",
5484 Span::new(spans[idx - 1].end, spans[idx - 1].end),
5485 ));
5486 return garbage(working_set, spans[idx - 1]);
5487 }
5488 }
5489
5490 let mut lhs = parse_value(working_set, spans[idx], &SyntaxShape::Any);
5491
5492 for not_start_span in not_start_spans.iter().rev() {
5493 lhs = Expression::new(
5500 working_set,
5501 Expr::UnaryNot(Box::new(lhs)),
5502 Span::new(*not_start_span, spans[idx].end),
5503 Type::Bool,
5504 );
5505 }
5506 not_start_spans.clear();
5507
5508 idx += 1;
5509
5510 if idx >= spans.len() {
5511 if let Some(row_var_id) = lhs_row_var_id {
5513 expand_to_cell_path(working_set, &mut lhs, row_var_id);
5514 }
5515 }
5516
5517 expr_stack.push(lhs);
5518
5519 while idx < spans.len() {
5520 let op = parse_operator(working_set, spans[idx]);
5521
5522 let op_prec = op.precedence();
5523
5524 idx += 1;
5525
5526 if idx == spans.len() {
5527 working_set.error(ParseError::IncompleteMathExpression(spans[idx - 1]));
5529
5530 expr_stack.push(Expression::garbage(working_set, spans[idx - 1]));
5531 expr_stack.push(Expression::garbage(working_set, spans[idx - 1]));
5532
5533 break;
5534 }
5535
5536 let content = working_set.get_span_contents(spans[idx]);
5537 if content == b"if" || content == b"match" {
5540 let rhs = parse_call(working_set, &spans[idx..], spans[0]);
5541 expr_stack.push(op);
5542 expr_stack.push(rhs);
5543 break;
5544 } else if content == b"not" {
5545 not_start_spans.push(spans[idx].start);
5546 idx += 1;
5547 while idx < spans.len() {
5548 let next_value = working_set.get_span_contents(spans[idx]);
5549
5550 if next_value == b"not" {
5551 not_start_spans.push(spans[idx].start);
5552 idx += 1;
5553 } else {
5554 break;
5555 }
5556 }
5557
5558 if idx == spans.len() {
5559 working_set.error(ParseError::Expected(
5560 "expression",
5561 Span::new(spans[idx - 1].end, spans[idx - 1].end),
5562 ));
5563 return garbage(working_set, spans[idx - 1]);
5564 }
5565 }
5566 let mut rhs = parse_value(working_set, spans[idx], &SyntaxShape::Any);
5567
5568 for not_start_span in not_start_spans.iter().rev() {
5569 rhs = Expression::new(
5576 working_set,
5577 Expr::UnaryNot(Box::new(rhs)),
5578 Span::new(*not_start_span, spans[idx].end),
5579 Type::Bool,
5580 );
5581 }
5582 not_start_spans.clear();
5583
5584 while op_prec <= last_prec && expr_stack.len() > 1 {
5585 let mut rhs = expr_stack
5588 .pop()
5589 .expect("internal error: expression stack empty");
5590 let mut op = expr_stack
5591 .pop()
5592 .expect("internal error: expression stack empty");
5593
5594 last_prec = op.precedence();
5595
5596 if last_prec < op_prec {
5597 expr_stack.push(op);
5598 expr_stack.push(rhs);
5599 break;
5600 }
5601
5602 let mut lhs = expr_stack
5603 .pop()
5604 .expect("internal error: expression stack empty");
5605
5606 if let Some(row_var_id) = lhs_row_var_id {
5607 expand_to_cell_path(working_set, &mut lhs, row_var_id);
5608 }
5609
5610 let (result_ty, err) = math_result_type(working_set, &mut lhs, &mut op, &mut rhs);
5611 if let Some(err) = err {
5612 working_set.error(err);
5613 }
5614
5615 let op_span = Span::append(lhs.span, rhs.span);
5616 expr_stack.push(Expression::new(
5617 working_set,
5618 Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
5619 op_span,
5620 result_ty,
5621 ));
5622 }
5623 expr_stack.push(op);
5624 expr_stack.push(rhs);
5625
5626 last_prec = op_prec;
5627
5628 idx += 1;
5629 }
5630
5631 while expr_stack.len() != 1 {
5632 let mut rhs = expr_stack
5633 .pop()
5634 .expect("internal error: expression stack empty");
5635 let mut op = expr_stack
5636 .pop()
5637 .expect("internal error: expression stack empty");
5638 let mut lhs = expr_stack
5639 .pop()
5640 .expect("internal error: expression stack empty");
5641
5642 if let Some(row_var_id) = lhs_row_var_id {
5643 expand_to_cell_path(working_set, &mut lhs, row_var_id);
5644 }
5645
5646 let (result_ty, err) = math_result_type(working_set, &mut lhs, &mut op, &mut rhs);
5647 if let Some(err) = err {
5648 working_set.error(err)
5649 }
5650
5651 let binary_op_span = Span::append(lhs.span, rhs.span);
5652 expr_stack.push(Expression::new(
5653 working_set,
5654 Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)),
5655 binary_op_span,
5656 result_ty,
5657 ));
5658 }
5659
5660 expr_stack
5661 .pop()
5662 .expect("internal error: expression stack empty")
5663}
5664
5665pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression {
5666 trace!("parsing: expression");
5667
5668 let mut pos = 0;
5669 let mut shorthand = vec![];
5670
5671 while pos < spans.len() {
5672 let name = working_set.get_span_contents(spans[pos]);
5674
5675 let split = name.splitn(2, |x| *x == b'=');
5676 let split: Vec<_> = split.collect();
5677 if !name.starts_with(b"^")
5678 && split.len() == 2
5679 && !split[0].is_empty()
5680 && !split[0].ends_with(b"..")
5681 {
5683 let point = split[0].len() + 1;
5684
5685 let starting_error_count = working_set.parse_errors.len();
5686
5687 let lhs_span = Span::new(spans[pos].start, spans[pos].start + point - 1);
5688 if !is_identifier(working_set.get_span_contents(lhs_span)) {
5689 break;
5690 }
5691
5692 let lhs = parse_string_strict(working_set, lhs_span);
5693 let rhs = if spans[pos].start + point < spans[pos].end {
5694 let rhs_span = Span::new(spans[pos].start + point, spans[pos].end);
5695
5696 if working_set.get_span_contents(rhs_span).starts_with(b"$") {
5697 parse_dollar_expr(working_set, rhs_span)
5698 } else {
5699 parse_string_strict(working_set, rhs_span)
5700 }
5701 } else {
5702 Expression::new(
5703 working_set,
5704 Expr::String(String::new()),
5705 Span::unknown(),
5706 Type::Nothing,
5707 )
5708 };
5709
5710 if starting_error_count == working_set.parse_errors.len() {
5711 shorthand.push((lhs, rhs));
5712 pos += 1;
5713 } else {
5714 working_set.parse_errors.truncate(starting_error_count);
5715 break;
5716 }
5717 } else {
5718 break;
5719 }
5720 }
5721
5722 if pos == spans.len() {
5723 working_set.error(ParseError::UnknownCommand(spans[0]));
5724 return garbage(working_set, Span::concat(spans));
5725 }
5726
5727 let output = if spans[pos..]
5728 .iter()
5729 .any(|span| is_assignment_operator(working_set.get_span_contents(*span)))
5730 {
5731 parse_assignment_expression(working_set, &spans[pos..])
5732 } else if is_math_expression_like(working_set, spans[pos]) {
5733 parse_math_expression(working_set, &spans[pos..], None)
5734 } else {
5735 let bytes = working_set.get_span_contents(spans[pos]).to_vec();
5736
5737 match bytes.as_slice() {
5739 b"def" | b"extern" | b"for" | b"module" | b"use" | b"source" | b"alias" | b"export"
5740 | b"hide" => {
5741 working_set.error(ParseError::BuiltinCommandInPipeline(
5742 String::from_utf8(bytes)
5743 .expect("builtin commands bytes should be able to convert to string"),
5744 spans[0],
5745 ));
5746
5747 parse_call(working_set, &spans[pos..], spans[0])
5748 }
5749 b"let" | b"const" | b"mut" => {
5750 working_set.error(ParseError::AssignInPipeline(
5751 String::from_utf8(bytes)
5752 .expect("builtin commands bytes should be able to convert to string"),
5753 String::from_utf8_lossy(match spans.len() {
5754 1..=3 => b"value",
5755 _ => working_set.get_span_contents(spans[3]),
5756 })
5757 .to_string(),
5758 String::from_utf8_lossy(match spans.len() {
5759 1 => b"variable",
5760 _ => working_set.get_span_contents(spans[1]),
5761 })
5762 .to_string(),
5763 spans[0],
5764 ));
5765 parse_call(working_set, &spans[pos..], spans[0])
5766 }
5767 b"overlay" => {
5768 if spans.len() > 1 && working_set.get_span_contents(spans[1]) == b"list" {
5769 parse_call(working_set, &spans[pos..], spans[0])
5771 } else {
5772 working_set.error(ParseError::BuiltinCommandInPipeline(
5773 "overlay".into(),
5774 spans[0],
5775 ));
5776
5777 parse_call(working_set, &spans[pos..], spans[0])
5778 }
5779 }
5780 b"where" => parse_where_expr(working_set, &spans[pos..]),
5781 #[cfg(feature = "plugin")]
5782 b"plugin" => {
5783 if spans.len() > 1 && working_set.get_span_contents(spans[1]) == b"use" {
5784 working_set.error(ParseError::BuiltinCommandInPipeline(
5786 "plugin use".into(),
5787 spans[0],
5788 ));
5789 }
5790
5791 parse_call(working_set, &spans[pos..], spans[0])
5792 }
5793
5794 _ => parse_call(working_set, &spans[pos..], spans[0]),
5795 }
5796 };
5797
5798 if !shorthand.is_empty() {
5799 let with_env = working_set.find_decl(b"with-env");
5800 if let Some(decl_id) = with_env {
5801 let mut block = Block::default();
5802 let ty = output.ty.clone();
5803 block.pipelines = vec![Pipeline::from_vec(vec![output])];
5804 block.span = Some(Span::concat(spans));
5805
5806 compile_block(working_set, &mut block);
5807
5808 let block_id = working_set.add_block(Arc::new(block));
5809
5810 let mut env_vars = vec![];
5811 for sh in shorthand {
5812 env_vars.push(RecordItem::Pair(sh.0, sh.1));
5813 }
5814
5815 let arguments = vec![
5816 Argument::Positional(Expression::new(
5817 working_set,
5818 Expr::Record(env_vars),
5819 Span::concat(&spans[..pos]),
5820 Type::Any,
5821 )),
5822 Argument::Positional(Expression::new(
5823 working_set,
5824 Expr::Closure(block_id),
5825 Span::concat(&spans[pos..]),
5826 Type::Closure,
5827 )),
5828 ];
5829
5830 let expr = Expr::Call(Box::new(Call {
5831 head: Span::unknown(),
5832 decl_id,
5833 arguments,
5834 parser_info: HashMap::new(),
5835 }));
5836
5837 Expression::new(working_set, expr, Span::concat(spans), ty)
5838 } else {
5839 output
5840 }
5841 } else {
5842 output
5843 }
5844}
5845
5846pub fn parse_builtin_commands(
5847 working_set: &mut StateWorkingSet,
5848 lite_command: &LiteCommand,
5849) -> Pipeline {
5850 trace!("parsing: builtin commands");
5851 if !is_math_expression_like(working_set, lite_command.parts[0])
5852 && !is_unaliasable_parser_keyword(working_set, &lite_command.parts)
5853 {
5854 trace!("parsing: not math expression or unaliasable parser keyword");
5855 let name = working_set.get_span_contents(lite_command.parts[0]);
5856 if let Some(decl_id) = working_set.find_decl(name) {
5857 let cmd = working_set.get_decl(decl_id);
5858 if cmd.is_alias() {
5859 let call_expr = parse_call(working_set, &lite_command.parts, lite_command.parts[0]);
5862
5863 if let Expression {
5864 expr: Expr::Call(call),
5865 ..
5866 } = call_expr
5867 {
5868 let cmd = working_set.get_decl(call.decl_id);
5870 match cmd.name() {
5871 "overlay hide" => return parse_overlay_hide(working_set, call),
5872 "overlay new" => return parse_overlay_new(working_set, call),
5873 "overlay use" => return parse_overlay_use(working_set, call),
5874 _ => { }
5875 }
5876 }
5877 }
5878 }
5879 }
5880
5881 trace!("parsing: checking for keywords");
5882 let name = lite_command
5883 .command_parts()
5884 .first()
5885 .map(|s| working_set.get_span_contents(*s))
5886 .unwrap_or(b"");
5887
5888 match name {
5889 b"def" => parse_def(working_set, lite_command, None).0,
5891 b"extern" => parse_extern(working_set, lite_command, None),
5892 b"export" => parse_export_in_block(working_set, lite_command),
5894 _ if lite_command.has_attributes() => parse_attribute_block(working_set, lite_command),
5896 b"let" => parse_let(
5897 working_set,
5898 &lite_command
5899 .parts_including_redirection()
5900 .collect::<Vec<Span>>(),
5901 ),
5902 b"const" => parse_const(working_set, &lite_command.parts).0,
5903 b"mut" => parse_mut(
5904 working_set,
5905 &lite_command
5906 .parts_including_redirection()
5907 .collect::<Vec<Span>>(),
5908 ),
5909 b"for" => {
5910 let expr = parse_for(working_set, lite_command);
5911 Pipeline::from_vec(vec![expr])
5912 }
5913 b"alias" => parse_alias(working_set, lite_command, None),
5914 b"module" => parse_module(working_set, lite_command, None).0,
5915 b"use" => parse_use(working_set, lite_command, None).0,
5916 b"overlay" => {
5917 if let Some(redirection) = lite_command.redirection.as_ref() {
5918 working_set.error(redirecting_builtin_error("overlay", redirection));
5919 return garbage_pipeline(working_set, &lite_command.parts);
5920 }
5921 parse_keyword(working_set, lite_command)
5922 }
5923 b"source" | b"source-env" => parse_source(working_set, lite_command),
5924 b"hide" => parse_hide(working_set, lite_command),
5925 b"where" => parse_where(working_set, lite_command),
5926 #[cfg(feature = "plugin")]
5928 b"plugin"
5929 if lite_command
5930 .parts
5931 .get(1)
5932 .is_some_and(|span| working_set.get_span_contents(*span) == b"use") =>
5933 {
5934 if let Some(redirection) = lite_command.redirection.as_ref() {
5935 working_set.error(redirecting_builtin_error("plugin use", redirection));
5936 return garbage_pipeline(working_set, &lite_command.parts);
5937 }
5938 parse_keyword(working_set, lite_command)
5939 }
5940 _ => {
5941 let element = parse_pipeline_element(working_set, lite_command);
5942
5943 if let Expression {
5955 expr: Expr::Call(call),
5956 ..
5957 } = &element.expr
5958 {
5959 let cmd = working_set.get_decl(call.decl_id);
5961 match cmd.name() {
5962 "overlay hide" => return parse_overlay_hide(working_set, call.clone()),
5963 "overlay new" => return parse_overlay_new(working_set, call.clone()),
5964 "overlay use" => return parse_overlay_use(working_set, call.clone()),
5965 _ => { }
5966 }
5967 }
5968 Pipeline {
5969 elements: vec![element],
5970 }
5971 }
5972 }
5973}
5974
5975fn check_record_key_or_value(
5976 working_set: &StateWorkingSet,
5977 expr: &Expression,
5978 position: &str,
5979) -> Option<ParseError> {
5980 let bareword_error = |string_value: &Expression| {
5981 working_set
5982 .get_span_contents(string_value.span)
5983 .iter()
5984 .find_position(|b| **b == b':')
5985 .map(|(i, _)| {
5986 let colon_position = i + string_value.span.start;
5987 ParseError::InvalidLiteral(
5988 "colon".to_string(),
5989 format!("bare word specifying record {}", position),
5990 Span::new(colon_position, colon_position + 1),
5991 )
5992 })
5993 };
5994 let value_span = working_set.get_span_contents(expr.span);
5995 match expr.expr {
5996 Expr::String(_) => {
5997 if ![b'"', b'\'', b'`'].contains(&value_span[0]) {
5998 bareword_error(expr)
5999 } else {
6000 None
6001 }
6002 }
6003 Expr::StringInterpolation(ref expressions) => {
6004 if value_span[0] != b'$' {
6005 expressions
6006 .iter()
6007 .filter(|expr| matches!(expr.expr, Expr::String(_)))
6008 .filter_map(bareword_error)
6009 .next()
6010 } else {
6011 None
6012 }
6013 }
6014 _ => None,
6015 }
6016}
6017
6018pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression {
6019 let bytes = working_set.get_span_contents(span);
6020
6021 let mut start = span.start;
6022 let mut end = span.end;
6023
6024 if bytes.starts_with(b"{") {
6025 start += 1;
6026 } else {
6027 working_set.error(ParseError::Expected("{", Span::new(start, start + 1)));
6028 return garbage(working_set, span);
6029 }
6030
6031 let mut unclosed = false;
6032 let mut extra_tokens = false;
6033 if bytes.ends_with(b"}") {
6034 end -= 1;
6035 } else {
6036 unclosed = true;
6037 }
6038
6039 let inner_span = Span::new(start, end);
6040
6041 let mut lex_state = LexState {
6042 input: working_set.get_span_contents(inner_span),
6043 output: Vec::new(),
6044 error: None,
6045 span_offset: start,
6046 };
6047 while !lex_state.input.is_empty() {
6048 if lex_state.input[0] == b'}' {
6049 extra_tokens = true;
6050 unclosed = false;
6051 break;
6052 }
6053 let additional_whitespace = &[b'\n', b'\r', b','];
6054 if lex_n_tokens(&mut lex_state, additional_whitespace, &[b':'], true, 1) < 1 {
6055 break;
6056 };
6057 let span = lex_state
6058 .output
6059 .last()
6060 .expect("should have gotten 1 token")
6061 .span;
6062 let contents = working_set.get_span_contents(span);
6063 if contents.len() > 3
6064 && contents.starts_with(b"...")
6065 && (contents[3] == b'$' || contents[3] == b'{' || contents[3] == b'(')
6066 {
6067 continue;
6069 }
6070 if lex_n_tokens(&mut lex_state, additional_whitespace, &[b':'], true, 1) < 1 {
6072 break;
6073 };
6074 if lex_n_tokens(&mut lex_state, additional_whitespace, &[], true, 1) < 1 {
6076 break;
6077 };
6078 }
6079 let (tokens, err) = (lex_state.output, lex_state.error);
6080
6081 if unclosed {
6082 working_set.error(ParseError::Unclosed("}".into(), Span::new(end, end)));
6083 } else if extra_tokens {
6084 working_set.error(ParseError::ExtraTokensAfterClosingDelimiter(Span::new(
6085 lex_state.span_offset + 1,
6086 end,
6087 )));
6088 }
6089
6090 if let Some(err) = err {
6091 working_set.error(err);
6092 }
6093
6094 let mut output = vec![];
6095 let mut idx = 0;
6096
6097 let mut field_types = Some(vec![]);
6098 while idx < tokens.len() {
6099 let curr_span = tokens[idx].span;
6100 let curr_tok = working_set.get_span_contents(curr_span);
6101 if curr_tok.starts_with(b"...")
6102 && curr_tok.len() > 3
6103 && (curr_tok[3] == b'$' || curr_tok[3] == b'{' || curr_tok[3] == b'(')
6104 {
6105 let inner = parse_value(
6107 working_set,
6108 Span::new(curr_span.start + 3, curr_span.end),
6109 &SyntaxShape::Record(vec![]),
6110 );
6111 idx += 1;
6112
6113 match &inner.ty {
6114 Type::Record(inner_fields) => {
6115 if let Some(fields) = &mut field_types {
6116 for (field, ty) in inner_fields.as_ref() {
6117 fields.push((field.clone(), ty.clone()));
6118 }
6119 }
6120 }
6121 _ => {
6122 field_types = None;
6125 }
6126 }
6127 output.push(RecordItem::Spread(
6128 Span::new(curr_span.start, curr_span.start + 3),
6129 inner,
6130 ));
6131 } else {
6132 let field_token = &tokens[idx];
6134 let field = if field_token.contents != TokenContents::Item {
6135 working_set.error(ParseError::Expected(
6136 "item in record key position",
6137 Span::new(field_token.span.start, field_token.span.end),
6138 ));
6139 garbage(working_set, curr_span)
6140 } else {
6141 let field = parse_value(working_set, curr_span, &SyntaxShape::Any);
6142 if let Some(error) = check_record_key_or_value(working_set, &field, "key") {
6143 working_set.error(error);
6144 garbage(working_set, field.span)
6145 } else {
6146 field
6147 }
6148 };
6149
6150 idx += 1;
6151 if idx == tokens.len() {
6152 working_set.error(ParseError::Expected(
6153 "':'",
6154 Span::new(curr_span.end, curr_span.end),
6155 ));
6156 output.push(RecordItem::Pair(
6157 garbage(working_set, curr_span),
6158 garbage(working_set, Span::new(curr_span.end, curr_span.end)),
6159 ));
6160 break;
6161 }
6162 let colon_span = tokens[idx].span;
6163 let colon = working_set.get_span_contents(colon_span);
6164 idx += 1;
6165 if colon != b":" {
6166 working_set.error(ParseError::Expected(
6167 "':'",
6168 Span::new(colon_span.start, colon_span.start),
6169 ));
6170 output.push(RecordItem::Pair(
6171 field,
6172 garbage(
6173 working_set,
6174 Span::new(colon_span.start, tokens[tokens.len() - 1].span.end),
6175 ),
6176 ));
6177 break;
6178 }
6179 if idx == tokens.len() {
6180 working_set.error(ParseError::Expected(
6181 "value for record field",
6182 Span::new(colon_span.end, colon_span.end),
6183 ));
6184 output.push(RecordItem::Pair(
6185 garbage(working_set, Span::new(curr_span.start, colon_span.end)),
6186 garbage(
6187 working_set,
6188 Span::new(colon_span.end, tokens[tokens.len() - 1].span.end),
6189 ),
6190 ));
6191 break;
6192 }
6193
6194 let value_token = &tokens[idx];
6195 let value = if value_token.contents != TokenContents::Item {
6196 working_set.error(ParseError::Expected(
6197 "item in record value position",
6198 Span::new(value_token.span.start, value_token.span.end),
6199 ));
6200 garbage(
6201 working_set,
6202 Span::new(value_token.span.start, value_token.span.end),
6203 )
6204 } else {
6205 let value = parse_value(working_set, tokens[idx].span, &SyntaxShape::Any);
6206 if let Some(parse_error) = check_record_key_or_value(working_set, &value, "value") {
6207 working_set.error(parse_error);
6208 garbage(working_set, value.span)
6209 } else {
6210 value
6211 }
6212 };
6213 idx += 1;
6214
6215 if let Some(field) = field.as_string() {
6216 if let Some(fields) = &mut field_types {
6217 fields.push((field, value.ty.clone()));
6218 }
6219 } else {
6220 field_types = None;
6223 }
6224 output.push(RecordItem::Pair(field, value));
6225 }
6226 }
6227
6228 Expression::new(
6229 working_set,
6230 Expr::Record(output),
6231 span,
6232 if let Some(fields) = field_types {
6233 Type::Record(fields.into())
6234 } else {
6235 Type::Any
6236 },
6237 )
6238}
6239
6240fn parse_redirection_target(
6241 working_set: &mut StateWorkingSet,
6242 target: &LiteRedirectionTarget,
6243) -> RedirectionTarget {
6244 match target {
6245 LiteRedirectionTarget::File {
6246 connector,
6247 file,
6248 append,
6249 } => RedirectionTarget::File {
6250 expr: parse_value(working_set, *file, &SyntaxShape::Any),
6251 append: *append,
6252 span: *connector,
6253 },
6254 LiteRedirectionTarget::Pipe { connector } => RedirectionTarget::Pipe { span: *connector },
6255 }
6256}
6257
6258pub(crate) fn parse_redirection(
6259 working_set: &mut StateWorkingSet,
6260 target: &LiteRedirection,
6261) -> PipelineRedirection {
6262 match target {
6263 LiteRedirection::Single { source, target } => PipelineRedirection::Single {
6264 source: *source,
6265 target: parse_redirection_target(working_set, target),
6266 },
6267 LiteRedirection::Separate { out, err } => PipelineRedirection::Separate {
6268 out: parse_redirection_target(working_set, out),
6269 err: parse_redirection_target(working_set, err),
6270 },
6271 }
6272}
6273
6274fn parse_pipeline_element(
6275 working_set: &mut StateWorkingSet,
6276 command: &LiteCommand,
6277) -> PipelineElement {
6278 trace!("parsing: pipeline element");
6279
6280 let expr = parse_expression(working_set, &command.parts);
6281
6282 let redirection = command
6283 .redirection
6284 .as_ref()
6285 .map(|r| parse_redirection(working_set, r));
6286
6287 PipelineElement {
6288 pipe: command.pipe,
6289 expr,
6290 redirection,
6291 }
6292}
6293
6294pub(crate) fn redirecting_builtin_error(
6295 name: &'static str,
6296 redirection: &LiteRedirection,
6297) -> ParseError {
6298 match redirection {
6299 LiteRedirection::Single { target, .. } => {
6300 ParseError::RedirectingBuiltinCommand(name, target.connector(), None)
6301 }
6302 LiteRedirection::Separate { out, err } => ParseError::RedirectingBuiltinCommand(
6303 name,
6304 out.connector().min(err.connector()),
6305 Some(out.connector().max(err.connector())),
6306 ),
6307 }
6308}
6309
6310pub fn parse_pipeline(working_set: &mut StateWorkingSet, pipeline: &LitePipeline) -> Pipeline {
6311 if pipeline.commands.len() > 1 {
6312 let elements: Vec<_> = pipeline
6314 .commands
6315 .iter()
6316 .enumerate()
6317 .map(|(index, element)| {
6318 let element = parse_pipeline_element(working_set, element);
6319 if index > 0 && element.has_in_variable(working_set) {
6321 wrap_element_with_collect(working_set, element.clone())
6322 } else {
6323 element
6324 }
6325 })
6326 .collect();
6327
6328 Pipeline { elements }
6329 } else {
6330 parse_builtin_commands(working_set, &pipeline.commands[0])
6332 }
6333}
6334
6335pub fn parse_block(
6336 working_set: &mut StateWorkingSet,
6337 tokens: &[Token],
6338 span: Span,
6339 scoped: bool,
6340 is_subexpression: bool,
6341) -> Block {
6342 let (lite_block, err) = lite_parse(tokens, working_set);
6343 if let Some(err) = err {
6344 working_set.error(err);
6345 }
6346
6347 trace!("parsing block: {:?}", lite_block);
6348
6349 if scoped {
6350 working_set.enter_scope();
6351 }
6352
6353 for pipeline in &lite_block.block {
6356 if pipeline.commands.len() == 1 {
6357 parse_def_predecl(working_set, pipeline.commands[0].command_parts())
6358 }
6359 }
6360
6361 let mut block = Block::new_with_capacity(lite_block.block.len());
6362 block.span = Some(span);
6363
6364 for lite_pipeline in &lite_block.block {
6365 let pipeline = parse_pipeline(working_set, lite_pipeline);
6366 block.pipelines.push(pipeline);
6367 }
6368
6369 if !is_subexpression
6372 && block
6373 .pipelines
6374 .iter()
6375 .flat_map(|pipeline| pipeline.elements.first())
6376 .any(|element| element.has_in_variable(working_set))
6377 {
6378 let inner_block = std::mem::take(&mut block);
6380 block.span = inner_block.span;
6381 let ty = inner_block.output_type();
6382 let block_id = working_set.add_block(Arc::new(inner_block));
6383
6384 let subexpression = Expression::new(working_set, Expr::Subexpression(block_id), span, ty);
6386 let collect = wrap_expr_with_collect(working_set, subexpression);
6387
6388 block.pipelines.push(Pipeline {
6389 elements: vec![PipelineElement {
6390 pipe: None,
6391 expr: collect,
6392 redirection: None,
6393 }],
6394 });
6395 }
6396
6397 if scoped {
6398 working_set.exit_scope();
6399 }
6400
6401 let errors = type_check::check_block_input_output(working_set, &block);
6402 if !errors.is_empty() {
6403 working_set.parse_errors.extend_from_slice(&errors);
6404 }
6405
6406 if !is_subexpression && working_set.parse_errors.is_empty() {
6409 compile_block(working_set, &mut block);
6410 }
6411
6412 block
6413}
6414
6415fn compile_block(working_set: &mut StateWorkingSet<'_>, block: &mut Block) {
6417 match nu_engine::compile(working_set, block) {
6418 Ok(ir_block) => {
6419 block.ir_block = Some(ir_block);
6420 }
6421 Err(err) => working_set.compile_errors.push(err),
6422 }
6423}
6424
6425pub fn discover_captures_in_closure(
6426 working_set: &StateWorkingSet,
6427 block: &Block,
6428 seen: &mut Vec<VarId>,
6429 seen_blocks: &mut HashMap<BlockId, Vec<(VarId, Span)>>,
6430 output: &mut Vec<(VarId, Span)>,
6431) -> Result<(), ParseError> {
6432 for flag in &block.signature.named {
6433 if let Some(var_id) = flag.var_id {
6434 seen.push(var_id);
6435 }
6436 }
6437
6438 for positional in &block.signature.required_positional {
6439 if let Some(var_id) = positional.var_id {
6440 seen.push(var_id);
6441 }
6442 }
6443 for positional in &block.signature.optional_positional {
6444 if let Some(var_id) = positional.var_id {
6445 seen.push(var_id);
6446 }
6447 }
6448 if let Some(positional) = &block.signature.rest_positional {
6449 if let Some(var_id) = positional.var_id {
6450 seen.push(var_id);
6451 }
6452 }
6453
6454 for pipeline in &block.pipelines {
6455 discover_captures_in_pipeline(working_set, pipeline, seen, seen_blocks, output)?;
6456 }
6457
6458 Ok(())
6459}
6460
6461fn discover_captures_in_pipeline(
6462 working_set: &StateWorkingSet,
6463 pipeline: &Pipeline,
6464 seen: &mut Vec<VarId>,
6465 seen_blocks: &mut HashMap<BlockId, Vec<(VarId, Span)>>,
6466 output: &mut Vec<(VarId, Span)>,
6467) -> Result<(), ParseError> {
6468 for element in &pipeline.elements {
6469 discover_captures_in_pipeline_element(working_set, element, seen, seen_blocks, output)?;
6470 }
6471
6472 Ok(())
6473}
6474
6475pub fn discover_captures_in_pipeline_element(
6477 working_set: &StateWorkingSet,
6478 element: &PipelineElement,
6479 seen: &mut Vec<VarId>,
6480 seen_blocks: &mut HashMap<BlockId, Vec<(VarId, Span)>>,
6481 output: &mut Vec<(VarId, Span)>,
6482) -> Result<(), ParseError> {
6483 discover_captures_in_expr(working_set, &element.expr, seen, seen_blocks, output)?;
6484
6485 if let Some(redirection) = element.redirection.as_ref() {
6486 match redirection {
6487 PipelineRedirection::Single { target, .. } => {
6488 if let Some(expr) = target.expr() {
6489 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6490 }
6491 }
6492 PipelineRedirection::Separate { out, err } => {
6493 if let Some(expr) = out.expr() {
6494 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6495 }
6496 if let Some(expr) = err.expr() {
6497 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6498 }
6499 }
6500 }
6501 }
6502
6503 Ok(())
6504}
6505
6506pub fn discover_captures_in_pattern(pattern: &MatchPattern, seen: &mut Vec<VarId>) {
6507 match &pattern.pattern {
6508 Pattern::Variable(var_id) => seen.push(*var_id),
6509 Pattern::List(items) => {
6510 for item in items {
6511 discover_captures_in_pattern(item, seen)
6512 }
6513 }
6514 Pattern::Record(items) => {
6515 for item in items {
6516 discover_captures_in_pattern(&item.1, seen)
6517 }
6518 }
6519 Pattern::Or(patterns) => {
6520 for pattern in patterns {
6521 discover_captures_in_pattern(pattern, seen)
6522 }
6523 }
6524 Pattern::Rest(var_id) => seen.push(*var_id),
6525 Pattern::Expression(_)
6526 | Pattern::Value(_)
6527 | Pattern::IgnoreValue
6528 | Pattern::IgnoreRest
6529 | Pattern::Garbage => {}
6530 }
6531}
6532
6533pub fn discover_captures_in_expr(
6535 working_set: &StateWorkingSet,
6536 expr: &Expression,
6537 seen: &mut Vec<VarId>,
6538 seen_blocks: &mut HashMap<BlockId, Vec<(VarId, Span)>>,
6539 output: &mut Vec<(VarId, Span)>,
6540) -> Result<(), ParseError> {
6541 match &expr.expr {
6542 Expr::AttributeBlock(ab) => {
6543 discover_captures_in_expr(working_set, &ab.item, seen, seen_blocks, output)?;
6544 }
6545 Expr::BinaryOp(lhs, _, rhs) => {
6546 discover_captures_in_expr(working_set, lhs, seen, seen_blocks, output)?;
6547 discover_captures_in_expr(working_set, rhs, seen, seen_blocks, output)?;
6548 }
6549 Expr::UnaryNot(expr) => {
6550 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6551 }
6552 Expr::Closure(block_id) => {
6553 let block = working_set.get_block(*block_id);
6554 let results = {
6555 let mut seen = vec![];
6556 let mut results = vec![];
6557
6558 discover_captures_in_closure(
6559 working_set,
6560 block,
6561 &mut seen,
6562 seen_blocks,
6563 &mut results,
6564 )?;
6565
6566 for (var_id, span) in results.iter() {
6567 if !seen.contains(var_id) {
6568 if let Some(variable) = working_set.get_variable_if_possible(*var_id) {
6569 if variable.mutable {
6570 return Err(ParseError::CaptureOfMutableVar(*span));
6571 }
6572 }
6573 }
6574 }
6575
6576 results
6577 };
6578 seen_blocks.insert(*block_id, results.clone());
6579 for (var_id, span) in results.into_iter() {
6580 if !seen.contains(&var_id) {
6581 output.push((var_id, span))
6582 }
6583 }
6584 }
6585 Expr::Block(block_id) => {
6586 let block = working_set.get_block(*block_id);
6587 let results = {
6589 let mut seen = vec![];
6590 let mut results = vec![];
6591 discover_captures_in_closure(
6592 working_set,
6593 block,
6594 &mut seen,
6595 seen_blocks,
6596 &mut results,
6597 )?;
6598 results
6599 };
6600
6601 seen_blocks.insert(*block_id, results.clone());
6602 for (var_id, span) in results.into_iter() {
6603 if !seen.contains(&var_id) {
6604 output.push((var_id, span))
6605 }
6606 }
6607 }
6608 Expr::Binary(_) => {}
6609 Expr::Bool(_) => {}
6610 Expr::Call(call) => {
6611 let decl = working_set.get_decl(call.decl_id);
6612 if let Some(block_id) = decl.block_id() {
6613 match seen_blocks.get(&block_id) {
6614 Some(capture_list) => {
6615 for capture in capture_list {
6617 if !seen.contains(&capture.0) {
6618 output.push(*capture);
6619 }
6620 }
6621 }
6622 None => {
6623 let block = working_set.get_block(block_id);
6624 if !block.captures.is_empty() {
6625 for (capture, span) in &block.captures {
6626 if !seen.contains(capture) {
6627 output.push((*capture, *span));
6628 }
6629 }
6630 } else {
6631 let result = {
6632 let mut seen = vec![];
6633 seen_blocks.insert(block_id, output.clone());
6634
6635 let mut result = vec![];
6636 discover_captures_in_closure(
6637 working_set,
6638 block,
6639 &mut seen,
6640 seen_blocks,
6641 &mut result,
6642 )?;
6643
6644 result
6645 };
6646 for capture in &result {
6648 if !seen.contains(&capture.0) {
6649 output.push(*capture);
6650 }
6651 }
6652
6653 seen_blocks.insert(block_id, result);
6654 }
6655 }
6656 }
6657 }
6658
6659 for arg in &call.arguments {
6660 match arg {
6661 Argument::Named(named) => {
6662 if let Some(arg) = &named.2 {
6663 discover_captures_in_expr(working_set, arg, seen, seen_blocks, output)?;
6664 }
6665 }
6666 Argument::Positional(expr)
6667 | Argument::Unknown(expr)
6668 | Argument::Spread(expr) => {
6669 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6670 }
6671 }
6672 }
6673 }
6674 Expr::CellPath(_) => {}
6675 Expr::DateTime(_) => {}
6676 Expr::ExternalCall(head, args) => {
6677 discover_captures_in_expr(working_set, head, seen, seen_blocks, output)?;
6678
6679 for ExternalArgument::Regular(expr) | ExternalArgument::Spread(expr) in args.as_ref() {
6680 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6681 }
6682 }
6683 Expr::Filepath(_, _) => {}
6684 Expr::Directory(_, _) => {}
6685 Expr::Float(_) => {}
6686 Expr::FullCellPath(cell_path) => {
6687 discover_captures_in_expr(working_set, &cell_path.head, seen, seen_blocks, output)?;
6688 }
6689 Expr::ImportPattern(_) => {}
6690 Expr::Overlay(_) => {}
6691 Expr::Garbage => {}
6692 Expr::Nothing => {}
6693 Expr::GlobPattern(_, _) => {}
6694 Expr::Int(_) => {}
6695 Expr::Keyword(kw) => {
6696 discover_captures_in_expr(working_set, &kw.expr, seen, seen_blocks, output)?;
6697 }
6698 Expr::List(list) => {
6699 for item in list {
6700 discover_captures_in_expr(working_set, item.expr(), seen, seen_blocks, output)?;
6701 }
6702 }
6703 Expr::Operator(_) => {}
6704 Expr::Range(range) => {
6705 if let Some(from) = &range.from {
6706 discover_captures_in_expr(working_set, from, seen, seen_blocks, output)?;
6707 }
6708 if let Some(next) = &range.next {
6709 discover_captures_in_expr(working_set, next, seen, seen_blocks, output)?;
6710 }
6711 if let Some(to) = &range.to {
6712 discover_captures_in_expr(working_set, to, seen, seen_blocks, output)?;
6713 }
6714 }
6715 Expr::Record(items) => {
6716 for item in items {
6717 match item {
6718 RecordItem::Pair(field_name, field_value) => {
6719 discover_captures_in_expr(
6720 working_set,
6721 field_name,
6722 seen,
6723 seen_blocks,
6724 output,
6725 )?;
6726 discover_captures_in_expr(
6727 working_set,
6728 field_value,
6729 seen,
6730 seen_blocks,
6731 output,
6732 )?;
6733 }
6734 RecordItem::Spread(_, record) => {
6735 discover_captures_in_expr(working_set, record, seen, seen_blocks, output)?;
6736 }
6737 }
6738 }
6739 }
6740 Expr::Signature(sig) => {
6741 for pos in &sig.required_positional {
6743 if let Some(var_id) = pos.var_id {
6744 seen.push(var_id);
6745 }
6746 }
6747 for pos in &sig.optional_positional {
6748 if let Some(var_id) = pos.var_id {
6749 seen.push(var_id);
6750 }
6751 }
6752 if let Some(rest) = &sig.rest_positional {
6753 if let Some(var_id) = rest.var_id {
6754 seen.push(var_id);
6755 }
6756 }
6757 for named in &sig.named {
6758 if let Some(var_id) = named.var_id {
6759 seen.push(var_id);
6760 }
6761 }
6762 }
6763 Expr::String(_) => {}
6764 Expr::RawString(_) => {}
6765 Expr::StringInterpolation(exprs) | Expr::GlobInterpolation(exprs, _) => {
6766 for expr in exprs {
6767 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?;
6768 }
6769 }
6770 Expr::MatchBlock(match_block) => {
6771 for match_ in match_block {
6772 discover_captures_in_pattern(&match_.0, seen);
6773 discover_captures_in_expr(working_set, &match_.1, seen, seen_blocks, output)?;
6774 }
6775 }
6776 Expr::Collect(var_id, expr) => {
6777 seen.push(*var_id);
6778 discover_captures_in_expr(working_set, expr, seen, seen_blocks, output)?
6779 }
6780 Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
6781 let block = working_set.get_block(*block_id);
6782
6783 let results = {
6784 let mut results = vec![];
6785 let mut seen = vec![];
6786 discover_captures_in_closure(
6787 working_set,
6788 block,
6789 &mut seen,
6790 seen_blocks,
6791 &mut results,
6792 )?;
6793 results
6794 };
6795
6796 seen_blocks.insert(*block_id, results.clone());
6797 for (var_id, span) in results.into_iter() {
6798 if !seen.contains(&var_id) {
6799 output.push((var_id, span))
6800 }
6801 }
6802 }
6803 Expr::Table(table) => {
6804 for header in table.columns.as_ref() {
6805 discover_captures_in_expr(working_set, header, seen, seen_blocks, output)?;
6806 }
6807 for row in table.rows.as_ref() {
6808 for cell in row.as_ref() {
6809 discover_captures_in_expr(working_set, cell, seen, seen_blocks, output)?;
6810 }
6811 }
6812 }
6813 Expr::ValueWithUnit(value) => {
6814 discover_captures_in_expr(working_set, &value.expr, seen, seen_blocks, output)?;
6815 }
6816 Expr::Var(var_id) => {
6817 if (*var_id > ENV_VARIABLE_ID || *var_id == IN_VARIABLE_ID) && !seen.contains(var_id) {
6818 output.push((*var_id, expr.span));
6819 }
6820 }
6821 Expr::VarDecl(var_id) => {
6822 seen.push(*var_id);
6823 }
6824 }
6825 Ok(())
6826}
6827
6828fn wrap_redirection_with_collect(
6829 working_set: &mut StateWorkingSet,
6830 target: RedirectionTarget,
6831) -> RedirectionTarget {
6832 match target {
6833 RedirectionTarget::File { expr, append, span } => RedirectionTarget::File {
6834 expr: wrap_expr_with_collect(working_set, expr),
6835 span,
6836 append,
6837 },
6838 RedirectionTarget::Pipe { span } => RedirectionTarget::Pipe { span },
6839 }
6840}
6841
6842fn wrap_element_with_collect(
6843 working_set: &mut StateWorkingSet,
6844 element: PipelineElement,
6845) -> PipelineElement {
6846 PipelineElement {
6847 pipe: element.pipe,
6848 expr: wrap_expr_with_collect(working_set, element.expr),
6849 redirection: element.redirection.map(|r| match r {
6850 PipelineRedirection::Single { source, target } => PipelineRedirection::Single {
6851 source,
6852 target: wrap_redirection_with_collect(working_set, target),
6853 },
6854 PipelineRedirection::Separate { out, err } => PipelineRedirection::Separate {
6855 out: wrap_redirection_with_collect(working_set, out),
6856 err: wrap_redirection_with_collect(working_set, err),
6857 },
6858 }),
6859 }
6860}
6861
6862fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: Expression) -> Expression {
6863 let span = expr.span;
6864
6865 let var_id = working_set.add_variable(
6868 b"$in".into(),
6869 Span::new(span.start, span.start),
6870 Type::Any,
6871 false,
6872 );
6873 let mut expr = expr.clone();
6874 expr.replace_in_variable(working_set, var_id);
6875
6876 let ty = expr.ty.clone();
6878 Expression::new(
6879 working_set,
6880 Expr::Collect(var_id, Box::new(expr)),
6881 span,
6882 ty,
6884 )
6885}
6886
6887pub fn parse(
6891 working_set: &mut StateWorkingSet,
6892 fname: Option<&str>,
6893 contents: &[u8],
6894 scoped: bool,
6895) -> Arc<Block> {
6896 trace!("parse");
6897 let name = match fname {
6898 Some(fname) => {
6899 nu_path::expand_to_real_path(fname)
6901 .to_string_lossy()
6902 .to_string()
6903 }
6904 None => "source".to_string(),
6905 };
6906
6907 let file_id = working_set.add_file(name, contents);
6908 let new_span = working_set.get_span_for_file(file_id);
6909
6910 let previously_parsed_block = working_set.find_block_by_span(new_span);
6911
6912 let mut output = {
6913 if let Some(block) = previously_parsed_block {
6914 return block;
6915 } else {
6916 let (output, err) = lex(contents, new_span.start, &[], &[], false);
6917 if let Some(err) = err {
6918 working_set.error(err)
6919 }
6920
6921 Arc::new(parse_block(working_set, &output, new_span, scoped, false))
6922 }
6923 };
6924
6925 let mut seen = vec![];
6926 let mut seen_blocks = HashMap::new();
6927
6928 let mut captures = vec![];
6929 match discover_captures_in_closure(
6930 working_set,
6931 &output,
6932 &mut seen,
6933 &mut seen_blocks,
6934 &mut captures,
6935 ) {
6936 Ok(_) => {
6937 Arc::make_mut(&mut output).captures = captures;
6938 }
6939 Err(err) => working_set.error(err),
6940 }
6941
6942 let mut errors = vec![];
6944 for (block_idx, block) in working_set.delta.blocks.iter().enumerate() {
6945 let block_id = block_idx + working_set.permanent_state.num_blocks();
6946 let block_id = BlockId::new(block_id);
6947
6948 if !seen_blocks.contains_key(&block_id) {
6949 let mut captures = vec![];
6950
6951 match discover_captures_in_closure(
6952 working_set,
6953 block,
6954 &mut seen,
6955 &mut seen_blocks,
6956 &mut captures,
6957 ) {
6958 Ok(_) => {
6959 seen_blocks.insert(block_id, captures);
6960 }
6961 Err(err) => {
6962 errors.push(err);
6963 }
6964 }
6965 }
6966 }
6967 for err in errors {
6968 working_set.error(err)
6969 }
6970
6971 for (block_id, captures) in seen_blocks.into_iter() {
6972 let block = working_set.get_block(block_id);
6977 let block_captures_empty = block.captures.is_empty();
6978 if !captures.is_empty()
6988 && block_captures_empty
6989 && block_id.get() >= working_set.permanent_state.num_blocks()
6990 {
6991 let block = working_set.get_block_mut(block_id);
6992 block.captures = captures;
6993 }
6994 }
6995
6996 output
6997}