@@ -29,6 +29,7 @@ pub fn to_bash(cmd: &Command) -> String {
2929}
3030
3131/// Write a command to the output string
32+ #[ allow( clippy:: too_many_lines) ]
3233fn write_command ( cmd : & Command , out : & mut String ) {
3334 match cmd {
3435 Command :: Simple {
@@ -47,7 +48,7 @@ fn write_command(cmd: &Command, out: &mut String) {
4748 Command :: List {
4849 op, left, right, ..
4950 } => {
50- write_list ( op, left, right, out) ;
51+ write_list ( * op, left, right, out) ;
5152 }
5253 Command :: For {
5354 variable,
@@ -81,7 +82,13 @@ fn write_command(cmd: &Command, out: &mut String) {
8182 redirects,
8283 ..
8384 } => {
84- write_if ( condition, then_branch, else_branch. as_ref ( ) , redirects, out) ;
85+ write_if (
86+ condition,
87+ then_branch,
88+ else_branch. as_deref ( ) ,
89+ redirects,
90+ out,
91+ ) ;
8592 }
8693 Command :: Case {
8794 word,
@@ -143,15 +150,12 @@ fn write_simple(
143150) {
144151 // Check if the command is a builtin that takes assignments as arguments
145152 // (like local, export, declare, readonly, typeset)
146- let is_assignment_builtin = words
147- . first ( )
148- . map ( |w| {
149- matches ! (
150- w. word. as_str( ) ,
151- "local" | "export" | "declare" | "readonly" | "typeset"
152- )
153- } )
154- . unwrap_or ( false ) ;
153+ let is_assignment_builtin = words. first ( ) . is_some_and ( |w| {
154+ matches ! (
155+ w. word. as_str( ) ,
156+ "local" | "export" | "declare" | "readonly" | "typeset"
157+ )
158+ } ) ;
155159
156160 if is_assignment_builtin {
157161 // For assignment builtins: cmd assignments...
@@ -279,12 +283,10 @@ fn write_redirect(redirect: &Redirect, out: &mut String) {
279283 RedirectType :: HereString => out. push_str ( "<<<" ) ,
280284 RedirectType :: InputOutput => out. push_str ( "<>" ) ,
281285 RedirectType :: Clobber => out. push_str ( ">|" ) ,
282- RedirectType :: DupInput => out. push_str ( "<&" ) ,
283- RedirectType :: DupOutput => out. push_str ( ">&" ) ,
286+ RedirectType :: DupInput | RedirectType :: MoveInput => out. push_str ( "<&" ) ,
287+ RedirectType :: DupOutput | RedirectType :: MoveOutput => out. push_str ( ">&" ) ,
284288 RedirectType :: ErrAndOut => out. push_str ( "&>" ) ,
285289 RedirectType :: AppendErrAndOut => out. push_str ( "&>>" ) ,
286- RedirectType :: MoveInput => out. push_str ( "<&" ) ,
287- RedirectType :: MoveOutput => out. push_str ( ">&" ) ,
288290 RedirectType :: HereDoc | RedirectType :: Close => unreachable ! ( ) , // Handled above
289291 }
290292
@@ -320,7 +322,7 @@ fn write_pipeline(commands: &[Command], negated: bool, out: &mut String) {
320322}
321323
322324/// Write a list (cmd1 && cmd2, cmd1 || cmd2, etc.)
323- fn write_list ( op : & ListOp , left : & Command , right : & Command , out : & mut String ) {
325+ fn write_list ( op : ListOp , left : & Command , right : & Command , out : & mut String ) {
324326 write_command ( left, out) ;
325327
326328 match op {
@@ -381,7 +383,7 @@ fn write_until(test: &Command, body: &Command, redirects: &[Redirect], out: &mut
381383fn write_if (
382384 condition : & Command ,
383385 then_branch : & Command ,
384- else_branch : Option < & Box < Command > > ,
386+ else_branch : Option < & Command > ,
385387 redirects : & [ Redirect ] ,
386388 out : & mut String ,
387389) {
@@ -397,7 +399,7 @@ fn write_if(
397399 then_branch : elif_then,
398400 else_branch : elif_else,
399401 ..
400- } = else_cmd. as_ref ( )
402+ } = else_cmd
401403 {
402404 out. push_str ( "; elif " ) ;
403405 write_command ( elif_cond, out) ;
@@ -619,15 +621,15 @@ mod tests {
619621 init ( ) ;
620622 }
621623
622- /// Helper to test round-trip: parse -> to_bash -> parse -> compare structure
624+ /// Helper to test round-trip: parse -> ` to_bash` -> parse -> compare structure
623625 fn assert_round_trip ( script : & str ) {
624626 setup ( ) ;
625- let ast1 = parse ( script) . expect ( & format ! ( "Failed to parse original: {}" , script) ) ;
627+ let ast1 =
628+ parse ( script) . unwrap_or_else ( |e| panic ! ( "Failed to parse original: {script}: {e}" ) ) ;
626629 let regenerated = to_bash ( & ast1) ;
627- let ast2 = parse ( & regenerated) . expect ( & format ! (
628- "Failed to parse regenerated script: {}\n Original: {}" ,
629- regenerated, script
630- ) ) ;
630+ let ast2 = parse ( & regenerated) . unwrap_or_else ( |e| {
631+ panic ! ( "Failed to parse regenerated script: {regenerated}\n Original: {script}: {e}" )
632+ } ) ;
631633
632634 // Compare JSON representations (ignoring line numbers)
633635 let json1 = serde_json:: to_string ( & ast1) . unwrap ( ) ;
@@ -639,8 +641,7 @@ mod tests {
639641
640642 assert_eq ! (
641643 json1_no_lines, json2_no_lines,
642- "AST mismatch!\n Original: {}\n Regenerated: {}\n AST1: {}\n AST2: {}" ,
643- script, regenerated, json1, json2
644+ "AST mismatch!\n Original: {script}\n Regenerated: {regenerated}\n AST1: {json1}\n AST2: {json2}"
644645 ) ;
645646 }
646647
@@ -651,8 +652,8 @@ mod tests {
651652 let mut chars = json. chars ( ) . peekable ( ) ;
652653
653654 while let Some ( c) = chars. next ( ) {
655+ result. push ( c) ;
654656 if c == '"' {
655- result. push ( c) ;
656657 // Read the key
657658 let mut key = String :: new ( ) ;
658659 while let Some ( & nc) = chars. peek ( ) {
@@ -682,8 +683,6 @@ mod tests {
682683 let line_len = "\" line\" " . len ( ) ;
683684 result. truncate ( result. len ( ) - line_len) ;
684685 }
685- } else {
686- result. push ( c) ;
687686 }
688687 }
689688
0 commit comments