Skip to content

Commit 938396a

Browse files
committed
unified/swift: add control-flow and loop mappings
1 parent 790d4f1 commit 938396a

3 files changed

Lines changed: 498 additions & 14 deletions

File tree

unified/extractor/src/languages/swift/swift.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,114 @@ fn translation_rules() -> Vec<yeast::Rule> {
450450
callee: {func}
451451
argument: (argument value: {closure}))
452452
),
453+
// ---- Control flow ----
454+
rule!(
455+
(if_statement condition: _* @cond body: @then_body else_branch: _? @else_stmts)
456+
=>
457+
(if_expr
458+
condition: {..cond}.reduce_left(first -> {first}, acc, elem -> (binary_expr operator: (infix_operator "&&") left: {acc} right: {elem}))
459+
then: {then_body}
460+
else: {..else_stmts})
461+
),
462+
// Guard statement
463+
rule!(
464+
(guard_statement condition: _* @cond body: (block statement: _* @else_stmts))
465+
=>
466+
(guard_if_stmt
467+
condition: {..cond}.reduce_left(first -> {first}, acc, elem -> (binary_expr operator: (infix_operator "&&") left: {acc} right: {elem}))
468+
else: (block stmt: {..else_stmts}))
469+
),
470+
// Ternary expression → if_expr
471+
rule!(
472+
(ternary_expression condition: @cond if_true: @then_val if_false: @else_val)
473+
=>
474+
(if_expr condition: {cond} then: {then_val} else: {else_val})
475+
),
476+
// Switch statement
477+
rule!(
478+
(switch_statement expr: @val entry: (switch_entry)* @cases)
479+
=>
480+
(switch_expr value: {val} case: {..cases})
481+
),
482+
// Switch entry with patterns and body
483+
rule!(
484+
(switch_entry pattern: (switch_pattern)* @pats statement: _* @body)
485+
=>
486+
(switch_case pattern: {..pats} body: (block stmt: {..body}))
487+
),
488+
// Switch entry: default case (no patterns)
489+
rule!(
490+
(switch_entry default: (default_keyword) statement: _* @body)
491+
=>
492+
(switch_case body: (block stmt: {..body}))
493+
),
494+
// Switch pattern — unwrap to inner pattern
495+
rule!((switch_pattern (pattern)* @inner) => {..inner}),
496+
// if case let x = expr — the pattern is taken as-is (no Optional wrapping)
497+
rule!(
498+
(if_let_binding "case" (value_binding_pattern) bound_identifier: @name _ @val)
499+
=>
500+
(pattern_guard_expr
501+
value: {val}
502+
pattern: (name_pattern identifier: (identifier #{name})))
503+
),
504+
rule!(
505+
(if_let_binding
506+
pattern: (pattern binding: (value_binding_pattern) bound_identifier: @name)
507+
value: @val)
508+
=>
509+
(pattern_guard_expr
510+
value: {val}
511+
pattern: (constructor_pattern
512+
constructor: (member_access_expr base: (named_type_expr name: (identifier "Optional")) member: (identifier "some"))
513+
element: (pattern_element pattern: (name_pattern identifier: (identifier #{name})))))
514+
),
515+
// Shorthand if let x (Swift 5.7+) — also semantically .some(x)
516+
rule!(
517+
(if_let_binding
518+
pattern: (pattern binding: (value_binding_pattern) bound_identifier: @name))
519+
=>
520+
(pattern_guard_expr
521+
value: (name_expr identifier: (identifier #{name}))
522+
pattern: (constructor_pattern
523+
constructor: (member_access_expr base: (named_type_expr name: (identifier "Optional")) member: (identifier "some"))
524+
element: (pattern_element pattern: (name_pattern identifier: (identifier #{name})))))
525+
),
526+
// If-condition — unwrap (pass through the inner expression/pattern)
527+
rule!((if_condition kind: @inner) => {inner}),
528+
// ---- Loops ----
529+
// For-in loop with optional where-clause guard.
530+
rule!(
531+
(for_statement
532+
item: @pat
533+
collection: @iter
534+
where: (where_clause expr: @guard)?
535+
body: (block statement: _* @body))
536+
=>
537+
(for_each_stmt
538+
pattern: {pat}
539+
iterable: {iter}
540+
guard: {..guard}
541+
body: (block stmt: {..body}))
542+
),
543+
// While loop
544+
rule!(
545+
(while_statement condition: _* @cond body: (block statement: _* @body))
546+
=>
547+
(while_stmt condition: {..cond}.reduce_left(first -> {first}, acc, elem -> (binary_expr operator: (infix_operator "&&") left: {acc} right: {elem})) body: (block stmt: {..body}))
548+
),
549+
// Repeat-while loop
550+
rule!(
551+
(repeat_while_statement condition: _* @cond body: (block statement: _* @body))
552+
=>
553+
(do_while_stmt condition: {..cond}.reduce_left(first -> {first}, acc, elem -> (binary_expr operator: (infix_operator "&&") left: {acc} right: {elem})) body: (block stmt: {..body}))
554+
),
555+
// Labeled statement (e.g. `outer: for ...`). Strip the trailing ':' from the label token.
556+
rule!((labeled_statement label: (statement_label) @lbl statement: @stmt) => {..{
557+
let text = __yeast_ctx.ast.source_text(lbl.into());
558+
let name = __yeast_ctx.literal("identifier", &text[..text.len() - 1]);
559+
vec![__yeast_ctx.node("labeled_stmt", vec![("label", vec![name]), ("stmt", vec![stmt.into()])])]
560+
}}),
453561
// ---- Fallbacks ----
454562
rule!(
455563
(_)

0 commit comments

Comments
 (0)