Skip to content

Commit 4e56cd5

Browse files
authored
fix(parser): external argument with subexpressions (nushell#16346)
Fixes: nushell#16040 # Description TBH, I not a fan of this whole `parse_external_string` idea. Maybe I lack some of the background knowledge here, but I don't see why we choose not to 1. parse external arguments the same way as internal ones 2. treat them literally at runtime if necessary Tests: +1
1 parent 0e3ca7b commit 4e56cd5

File tree

2 files changed

+35
-0
lines changed

2 files changed

+35
-0
lines changed

crates/nu-parser/src/parser.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@ fn parse_external_string(working_set: &mut StateWorkingSet, span: Span) -> Expre
264264
quote_char: u8,
265265
escaped: bool,
266266
},
267+
Parenthesized {
268+
from: usize,
269+
depth: usize,
270+
},
267271
}
268272
// Find the spans of parts of the string that can be parsed as their own strings for
269273
// concatenation.
@@ -315,6 +319,15 @@ fn parse_external_string(working_set: &mut StateWorkingSet, span: Span) -> Expre
315319
}
316320
state = State::BackTickQuote { from: index }
317321
}
322+
b'(' => {
323+
if index != *from {
324+
spans.push(make_span(*from, index))
325+
}
326+
state = State::Parenthesized {
327+
from: index,
328+
depth: 1,
329+
}
330+
}
318331
// Continue to consume
319332
_ => (),
320333
},
@@ -343,6 +356,18 @@ fn parse_external_string(working_set: &mut StateWorkingSet, span: Span) -> Expre
343356
state = State::Bare { from: index + 1 };
344357
}
345358
}
359+
State::Parenthesized { from, depth } => {
360+
if ch == b')' {
361+
if *depth == 1 {
362+
spans.push(make_span(*from, index + 1));
363+
state = State::Bare { from: index + 1 };
364+
} else {
365+
*depth -= 1;
366+
}
367+
} else if ch == b'(' {
368+
*depth += 1;
369+
}
370+
}
346371
}
347372
index += 1;
348373
}
@@ -351,6 +376,7 @@ fn parse_external_string(working_set: &mut StateWorkingSet, span: Span) -> Expre
351376
match state {
352377
State::Bare { from }
353378
| State::Quote { from, .. }
379+
| State::Parenthesized { from, .. }
354380
| State::BackTickQuote { from, .. } => {
355381
if from < contents.len() {
356382
spans.push(make_span(from, contents.len()));

tests/repl/test_parser.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,3 +1027,12 @@ fn not_panic_with_recursive_call() {
10271027
);
10281028
assert!(result.status.success());
10291029
}
1030+
1031+
// https://github.com/nushell/nushell/issues/16040
1032+
#[test]
1033+
fn external_argument_with_subexpressions() -> TestResult {
1034+
run_test(r#"^echo foo( ('bar') | $in ++ 'baz' )"#, "foobarbaz")?;
1035+
run_test(r#"^echo foo( 'bar' )('baz')"#, "foobarbaz")?;
1036+
run_test(r#"^echo ")('foo')(""#, ")('foo')(")?;
1037+
fail_test(r#"^echo foo( 'bar'"#, "Unexpected end of code")
1038+
}

0 commit comments

Comments
 (0)