@@ -54,6 +54,41 @@ fn chained_modifier(ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>) -> Optio
5454 }
5555}
5656
57+ /// Combine a list of boolean sub-conditions into a single expression by
58+ /// left-folding with the infix `&&` operator. Used by control-flow
59+ /// rules (`if`, `guard`, `while`, `repeat-while`) whose tree-sitter
60+ /// nodes carry one or more comma-separated conditions that the target
61+ /// AST represents as a single `condition:` field. Panics on an empty
62+ /// input because every caller's grammar guarantees at least one
63+ /// condition.
64+ fn and_chain (
65+ ctx : & mut yeast:: build:: BuildCtx < ' _ , SwiftContext > ,
66+ conds : Vec < yeast:: NodeRef > ,
67+ ) -> yeast:: Id {
68+ conds. into_iter ( )
69+ . map ( yeast:: Id :: from)
70+ . reduce ( |acc, elem| {
71+ tree ! ( ( binary_expr operator: ( infix_operator "&&" ) left: { acc} right: { elem} ) )
72+ } )
73+ . expect ( "control-flow statement must have at least one condition" )
74+ }
75+
76+ /// Translate a multi-part identifier (for example `Foo.Bar.Baz`) into a
77+ /// `member_access_expr` chain rooted at a `name_expr` over the first
78+ /// part. Panics on an empty input because the grammar's `_+` quantifier
79+ /// guarantees at least one part.
80+ fn member_chain (
81+ ctx : & mut yeast:: build:: BuildCtx < ' _ , SwiftContext > ,
82+ parts : Vec < yeast:: NodeRef > ,
83+ ) -> yeast:: Id {
84+ let mut iter = parts. into_iter ( ) ;
85+ let first = iter. next ( ) . expect ( "identifier with `part:` must have at least one part" ) ;
86+ let init = tree ! ( ( name_expr identifier: ( identifier #{ first} ) ) ) ;
87+ iter. fold ( init, |acc, elem| {
88+ tree ! ( ( member_access_expr base: { acc} member: ( identifier #{ elem} ) ) )
89+ } )
90+ }
91+
5792fn translation_rules ( ) -> Vec < Rule < SwiftContext > > {
5893 vec ! [
5994 // ---- Top-level ----
@@ -585,11 +620,12 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
585620 argument: ( argument value: { closure} ) )
586621 ) ,
587622 // ---- Control flow ----
623+ // If statement
588624 rule!(
589625 ( if_statement condition: _* @cond body: @then_body else_branch: _? @else_stmts)
590626 =>
591627 ( if_expr
592- condition: { ..cond } . reduce_left ( first -> { first } , acc , elem -> ( binary_expr operator : ( infix_operator "&&" ) left : { acc } right : { elem } ) )
628+ condition: { and_chain ( & mut ctx , cond ) }
593629 then: { then_body}
594630 else: { ..else_stmts} )
595631 ) ,
@@ -598,7 +634,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
598634 ( guard_statement condition: _* @cond body: ( block statement: _* @else_stmts) )
599635 =>
600636 ( guard_if_stmt
601- condition: { ..cond } . reduce_left ( first -> { first } , acc , elem -> ( binary_expr operator : ( infix_operator "&&" ) left : { acc } right : { elem } ) )
637+ condition: { and_chain ( & mut ctx , cond ) }
602638 else: ( block stmt: { ..else_stmts} ) )
603639 ) ,
604640 // Ternary expression → if_expr
@@ -676,13 +712,17 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
676712 rule!(
677713 ( while_statement condition: _* @cond body: ( block statement: _* @body) )
678714 =>
679- ( while_stmt condition: { ..cond} . reduce_left( first -> { first} , acc, elem -> ( binary_expr operator: ( infix_operator "&&" ) left: { acc} right: { elem} ) ) body: ( block stmt: { ..body} ) )
715+ ( while_stmt
716+ condition: { and_chain( & mut ctx, cond) }
717+ body: ( block stmt: { ..body} ) )
680718 ) ,
681719 // Repeat-while loop
682720 rule!(
683721 ( repeat_while_statement condition: _* @cond body: ( block statement: _* @body) )
684722 =>
685- ( do_while_stmt condition: { ..cond} . reduce_left( first -> { first} , acc, elem -> ( binary_expr operator: ( infix_operator "&&" ) left: { acc} right: { elem} ) ) body: ( block stmt: { ..body} ) )
723+ ( do_while_stmt
724+ condition: { and_chain( & mut ctx, cond) }
725+ body: ( block stmt: { ..body} ) )
686726 ) ,
687727 // Labeled statement (e.g. `outer: for ...`). Strip the trailing ':' from the label token.
688728 rule!( ( labeled_statement label: ( statement_label) @lbl statement: @stmt) => { ..{
@@ -770,9 +810,7 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
770810 rule!(
771811 ( identifier part: _+ @parts)
772812 =>
773- { parts} . reduce_left(
774- first -> ( name_expr identifier: ( identifier #{ first} ) ) ,
775- acc, elem -> ( member_access_expr base: { acc} member: ( identifier #{ elem} ) ) )
813+ { member_chain( & mut ctx, parts) }
776814 ) ,
777815 // Scoped import declaration (for example `import struct Foo.Bar`):
778816 // flatten the identifier parts into a member_access_expr and bind the
0 commit comments