From 22af5fd6232612428b424d5d09aafb7ec4efb06a Mon Sep 17 00:00:00 2001 From: pagedmov Date: Wed, 4 Mar 2026 18:27:40 -0500 Subject: [PATCH] improvement on parsing accuracy for case patterns --- src/expand.rs | 6 +++++- src/parse/lex.rs | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/expand.rs b/src/expand.rs index 161550b..3471f6e 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -500,6 +500,7 @@ pub fn expand_var(chars: &mut Peekable>) -> ShResult { let mut idx_brace_depth: i32 = 0; let mut idx_raw = String::new(); let mut idx = None; + let mut in_operator = false; while let Some(&ch) = chars.peek() { match ch { markers::SUBSH if var_name.is_empty() => { @@ -555,7 +556,7 @@ pub fn expand_var(chars: &mut Peekable>) -> ShResult { }; return Ok(val); } - '[' if brace_depth > 0 && bracket_depth == 0 && inner_brace_depth == 0 => { + '[' if brace_depth > 0 && bracket_depth == 0 && inner_brace_depth == 0 && !in_operator => { chars.next(); // consume the bracket bracket_depth += 1; } @@ -590,6 +591,9 @@ pub fn expand_var(chars: &mut Peekable>) -> ShResult { if ch == '}' { inner_brace_depth -= 1; } + if !in_operator && matches!(ch, '#' | '%' | ':' | '/' | '-' | '+' | '=' | '?' | '!') { + in_operator = true; + } var_name.push(ch); } ch if var_name.is_empty() && PARAMETERS.contains(&ch) => { diff --git a/src/parse/lex.rs b/src/parse/lex.rs index f6e9d92..35e9718 100644 --- a/src/parse/lex.rs +++ b/src/parse/lex.rs @@ -1087,11 +1087,26 @@ pub fn case_pat_lookahead(mut chars: Peekable) -> Option { while let Some(ch) = chars.next() { pos += ch.len_utf8(); match ch { - _ if is_hard_sep(ch) => return None, + _ if qt_state.outside() && is_hard_sep(ch) => return None, '\\' => { if let Some(esc) = chars.next() { pos += esc.len_utf8(); } + } + '$' if qt_state.outside() && chars.peek() == Some(&'\'') => { + // $'...' ANSI-C quoting — skip through to closing quote + chars.next(); // consume opening ' + pos += 1; + while let Some(c) = chars.next() { + pos += c.len_utf8(); + if c == '\\' { + if let Some(esc) = chars.next() { + pos += esc.len_utf8(); + } + } else if c == '\'' { + break; + } + } } '\'' => { qt_state.toggle_single();