@@ -7516,10 +7516,67 @@ impl Interpreter {
75167516 return String :: new ( ) ;
75177517 }
75187518
7519+ // Check for parameter expansion operators (%, %%, #, ##, :-, etc.)
7520+ // If present, handle expansion with the operator applied.
7521+ let has_operator = inner. contains ( "%%" )
7522+ || inner. contains ( '%' )
7523+ || ( inner. contains ( '#' ) && !inner. starts_with ( '#' ) )
7524+ || inner. contains ( ":-" ) ;
7525+ if has_operator {
7526+ return self . expand_param_op_in_arithmetic ( inner) ;
7527+ }
7528+
75197529 // ${var} — plain variable
75207530 self . expand_variable ( inner)
75217531 }
75227532
7533+ /// Expand a parameter expansion with operators inside arithmetic context.
7534+ /// Handles common cases like ${var%%-*}, ${var##prefix}, etc.
7535+ fn expand_param_op_in_arithmetic ( & self , inner : & str ) -> String {
7536+ // ${var%%pattern} — remove longest suffix
7537+ if let Some ( pos) = inner. find ( "%%" ) {
7538+ let name = & inner[ ..pos] ;
7539+ let pattern = & inner[ pos + 2 ..] ;
7540+ let value = self . expand_variable ( name) ;
7541+ return self . remove_pattern ( & value, pattern, false , true ) ;
7542+ }
7543+ // ${var%pattern} — remove shortest suffix
7544+ if let Some ( pos) = inner. find ( '%' ) {
7545+ let name = & inner[ ..pos] ;
7546+ let pattern = & inner[ pos + 1 ..] ;
7547+ let value = self . expand_variable ( name) ;
7548+ return self . remove_pattern ( & value, pattern, false , false ) ;
7549+ }
7550+ // ${var##pattern} — remove longest prefix
7551+ if let Some ( pos) = inner. find ( "##" ) {
7552+ let name = & inner[ ..pos] ;
7553+ let pattern = & inner[ pos + 2 ..] ;
7554+ let value = self . expand_variable ( name) ;
7555+ return self . remove_pattern ( & value, pattern, true , true ) ;
7556+ }
7557+ // ${var#pattern} — remove shortest prefix (but not ${#var} length)
7558+ if let Some ( pos) = inner. find ( '#' ) {
7559+ if pos > 0 {
7560+ let name = & inner[ ..pos] ;
7561+ let pattern = & inner[ pos + 1 ..] ;
7562+ let value = self . expand_variable ( name) ;
7563+ return self . remove_pattern ( & value, pattern, true , false ) ;
7564+ }
7565+ }
7566+ // ${var:-default}
7567+ if let Some ( pos) = inner. find ( ":-" ) {
7568+ let name = & inner[ ..pos] ;
7569+ let default = & inner[ pos + 2 ..] ;
7570+ let value = self . expand_variable ( name) ;
7571+ if value. is_empty ( ) {
7572+ return default. to_string ( ) ;
7573+ }
7574+ return value;
7575+ }
7576+ // Fallback
7577+ self . expand_variable ( inner)
7578+ }
7579+
75237580 /// Parse and evaluate a simple arithmetic expression with depth tracking.
75247581 /// THREAT[TM-DOS-026]: `arith_depth` prevents stack overflow from deeply nested expressions.
75257582 /// Parse an arithmetic atom: unary operators, parenthesized expressions, and literals.
0 commit comments