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