Skip to content

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

crates/nu-parser/src/parser.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2004,7 +2004,11 @@ pub fn parse_paren_expr(
20042004
if fcp_error_count > starting_error_count {
20052005
let malformed_subexpr = working_set.parse_errors[starting_error_count..]
20062006
.first()
2007-
.is_some_and(|e| matches!(e, ParseError::Unclosed(right, _) if right == ")" ));
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+
});
20082012
if malformed_subexpr {
20092013
working_set.parse_errors.truncate(starting_error_count);
20102014
parse_string_interpolation(working_set, span)

crates/nu-parser/tests/test_parser.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,46 @@ mod string {
16361636
assert_eq!(subexprs[3], &Expr::String("bar".to_string()));
16371637
}
16381638

1639+
/// PR with summary of the issue: https://github.com/nushell/nushell/pull/16235
1640+
/// Release Notes Mention: https://www.nushell.sh/blog/2025-07-23-nushell_0_106_0.html#regression-bare-word-interpolation-on-both-sides-does-not-work-toc
1641+
#[test]
1642+
pub fn parse_string_interpolation_bare_starting_and_ending_subexpr() {
1643+
let engine_state = EngineState::new();
1644+
let mut working_set = StateWorkingSet::new(&engine_state);
1645+
1646+
let block = parse(
1647+
&mut working_set,
1648+
None,
1649+
b"(100 + 20 + 3)/bar/(300 + 20 + 1)",
1650+
true,
1651+
);
1652+
1653+
assert!(working_set.parse_errors.is_empty(),);
1654+
1655+
let [pipeline] = block.pipelines.as_slice() else {
1656+
panic!("expected 1 pipeline")
1657+
};
1658+
let [element] = pipeline.elements.as_slice() else {
1659+
panic!("expected 1 pipeline element")
1660+
};
1661+
assert!(element.redirection.is_none());
1662+
1663+
let Expr::StringInterpolation(expressions) = &element.expr.expr else {
1664+
panic!("Expected an `Expr::StringInterpolation`")
1665+
};
1666+
let subexprs: Vec<_> = expressions.iter().map(|e| &e.expr).collect();
1667+
1668+
let [
1669+
Expr::FullCellPath(..),
1670+
Expr::String(s),
1671+
Expr::FullCellPath(..),
1672+
] = subexprs.as_slice()
1673+
else {
1674+
panic!("AST does not have the expected structure")
1675+
};
1676+
assert_eq!(s, "/bar/");
1677+
}
1678+
16391679
#[test]
16401680
pub fn parse_string_interpolation_bare_starting_subexpr_external_arg() {
16411681
let engine_state = EngineState::new();

0 commit comments

Comments
 (0)