diff --git a/unified/extractor/ast_types.yml b/unified/extractor/ast_types.yml index a04e1d38e95..7ed6f9cf854 100644 --- a/unified/extractor/ast_types.yml +++ b/unified/extractor/ast_types.yml @@ -18,6 +18,7 @@ supertypes: condition: - expr_condition - let_pattern_condition + - sequence_condition - unsupported_node pattern: - var_pattern @@ -92,6 +93,13 @@ named: expr_condition: expr: expr + # A series of statements that are executed before evaluating the trailing condition. + # Useful for languages where a conditional clause may be preceded by side-effecting + # syntactic elements (e.g. binding clauses) that don't themselves form a condition. + sequence_condition: + stmt*: stmt + condition: condition + # Evaluate 'expr' and match its result against 'pattern', and return true if it matches. # Variables bound by the pattern will be in scope within the 'true' branch controlled by this condition. let_pattern_condition: diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs index 9a7d18c8321..47bfe437ef2 100644 --- a/unified/extractor/src/languages/swift/swift.rs +++ b/unified/extractor/src/languages/swift/swift.rs @@ -157,29 +157,33 @@ fn translation_rules() -> Vec { ), // ---- Guard statement ---- // `guard let x = e else { ... }` — currently only handles the - // let-binding form, since plain `guard cond else { ... }` is not - // exercised by any existing corpus test. + // let-binding form. The Swift parser models the `let` keyword as a + // `value_binding_pattern` child of `condition`, followed by an + // unnamed `=` and the source expression. rule!( (guard_statement bound_identifier: (simple_identifier) @id - condition: (_)* @cond_children + condition: (value_binding_pattern) + condition: (_) @value (else) (statements) @else_branch) => (guard_if_stmt condition: (let_pattern_condition pattern: (var_pattern identifier: (identifier #{id})) - value: {*cond_children.last().unwrap()}) + value: {value}) else: {else_branch}) ), // ---- If statement ---- // if-let binding (with optional else branch). The Swift parser puts - // the bound name in `bound_identifier` and the source expression as - // the last child of the multi-child `condition` field. + // the bound name in `bound_identifier`, the `let` keyword as a + // `value_binding_pattern` child of `condition`, and the source + // expression as a separate child of `condition`. rule!( (if_statement bound_identifier: (simple_identifier) @id - condition: (_)* @cond_children + condition: (value_binding_pattern) + condition: (_) @value (statements) @then (else) (_) @else_branch) @@ -187,20 +191,21 @@ fn translation_rules() -> Vec { (if_stmt condition: (let_pattern_condition pattern: (var_pattern identifier: (identifier #{id})) - value: {*cond_children.last().unwrap()}) + value: {value}) then: {then} else: {else_branch}) ), rule!( (if_statement bound_identifier: (simple_identifier) @id - condition: (_)* @cond_children + condition: (value_binding_pattern) + condition: (_) @value (statements) @then) => (if_stmt condition: (let_pattern_condition pattern: (var_pattern identifier: (identifier #{id})) - value: {*cond_children.last().unwrap()}) + value: {value}) then: {then}) ), // With explicit else branch (block or chained if).