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