Unified: add tuple_pattern and sequence_condition; refine if-let/guard mapping

ast_types.yml additions:
- tuple_pattern { element*: pattern } in the pattern supertype.
- sequence_condition { stmt*: stmt, condition: condition } in the
  condition supertype.

swift.rs:
- Map Swift tuple destructuring (e.g. `let (a, b) = pair`) to the new
  tuple_pattern instead of synthesizing an apply_pattern.
- if-let / guard-let: explicitly match the value_binding_pattern
  (the `let` keyword) and bind the source expression as the next
  condition child, so `let` no longer leaks into the output.
This commit is contained in:
Asger F
2026-05-11 14:39:29 +02:00
parent 3b7a53f678
commit cbe4c81ca6
2 changed files with 23 additions and 10 deletions

View File

@@ -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:

View File

@@ -157,29 +157,33 @@ fn translation_rules() -> Vec<yeast::Rule> {
),
// ---- 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<yeast::Rule> {
(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).