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