Skip to content

Commit 790d4f1

Browse files
committed
unified/swift: add closure and capture mappings
1 parent 8f747a3 commit 790d4f1

2 files changed

Lines changed: 164 additions & 5 deletions

File tree

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,70 @@ fn translation_rules() -> Vec<yeast::Rule> {
386386
rule!((control_transfer_statement kind: "continue" result: @lbl) => (continue_expr label: (identifier #{lbl}))),
387387
rule!((control_transfer_statement kind: "continue") => (continue_expr)),
388388
rule!((control_transfer_statement kind: (throw_keyword) result: @val) => (throw_expr value: {val})),
389+
// ---- Closures ----
390+
// Lambda literal with optional type header (parameters + optional return type).
391+
// The return_type capture is optional, so this rule covers both cases.
392+
rule!(
393+
(lambda_literal
394+
attribute: _* @attrs
395+
captures: (capture_list item: _* @captures)?
396+
type: (lambda_function_type
397+
params: (lambda_function_type_parameters parameter: _* @params)
398+
return_type: _? @ret)?
399+
statement: _* @body)
400+
=>
401+
(function_expr
402+
modifier: {..attrs}
403+
capture_declaration: {..captures}
404+
parameter: {..params}
405+
return_type: {..ret}
406+
body: (block stmt: {..body}))
407+
),
408+
// capture_list_item with ownership modifier (e.g. [weak self], [unowned x])
409+
rule!(
410+
(capture_list_item ownership: _? @ownership name: @name value: _? @val)
411+
=>
412+
(variable_declaration
413+
modifier: {..ownership}
414+
pattern: (name_pattern identifier: (identifier #{name}))
415+
value: {..val})
416+
),
417+
// Lambda parameter with type and optional external name
418+
rule!(
419+
(lambda_parameter external_name: @ext name: @name type: @ty)
420+
=>
421+
(parameter
422+
external_name: (identifier #{ext})
423+
pattern: (name_pattern identifier: (identifier #{name}))
424+
type: {ty})
425+
),
426+
rule!(
427+
(lambda_parameter name: @name type: @ty)
428+
=>
429+
(parameter
430+
pattern: (name_pattern identifier: (identifier #{name}))
431+
type: {ty})
432+
),
433+
rule!(
434+
(lambda_parameter external_name: @ext name: @name)
435+
=>
436+
(parameter
437+
external_name: (identifier #{ext})
438+
pattern: (name_pattern identifier: (identifier #{name})))
439+
),
440+
rule!(
441+
(lambda_parameter name: @name)
442+
=>
443+
(parameter pattern: (name_pattern identifier: (identifier #{name})))
444+
),
445+
// Call expression with trailing closure (no value_arguments)
446+
rule!(
447+
(call_expression function: @func suffix: (call_suffix lambda: (lambda_literal) @closure))
448+
=>
449+
(call_expr
450+
callee: {func}
451+
argument: (argument value: {closure}))
452+
),
389453
// ---- Fallbacks ----
390454
rule!(
391455
(_)

unified/extractor/tests/corpus/swift/closures.txt

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,24 @@ top_level
5757
pattern:
5858
name_pattern
5959
identifier: identifier "f"
60-
value: unsupported_node "{ (x: Int) -> Int in x * 2 }"
60+
value:
61+
function_expr
62+
body:
63+
block
64+
stmt:
65+
binary_expr
66+
operator: infix_operator "*"
67+
left:
68+
name_expr
69+
identifier: identifier "x"
70+
right: int_literal "2"
71+
parameter:
72+
parameter
73+
pattern:
74+
name_pattern
75+
identifier: identifier "x"
76+
type: unsupported_node "Int"
77+
return_type: unsupported_node "Int"
6178

6279
===
6380
Closure with shorthand parameters
@@ -97,7 +114,19 @@ top_level
97114
pattern:
98115
name_pattern
99116
identifier: identifier "f"
100-
value: unsupported_node "{ $0 + $1 }"
117+
value:
118+
function_expr
119+
body:
120+
block
121+
stmt:
122+
binary_expr
123+
operator: infix_operator "+"
124+
left:
125+
name_expr
126+
identifier: identifier "$0"
127+
right:
128+
name_expr
129+
identifier: identifier "$1"
101130

102131
===
103132
Trailing closure
@@ -131,7 +160,27 @@ source_file
131160
top_level
132161
body:
133162
block
134-
stmt: unsupported_node "xs.map { $0 * 2 }"
163+
stmt:
164+
call_expr
165+
argument:
166+
argument
167+
value:
168+
function_expr
169+
body:
170+
block
171+
stmt:
172+
binary_expr
173+
operator: infix_operator "*"
174+
left:
175+
name_expr
176+
identifier: identifier "$0"
177+
right: int_literal "2"
178+
callee:
179+
member_access_expr
180+
base:
181+
name_expr
182+
identifier: identifier "xs"
183+
member: identifier "map"
135184

136185
===
137186
Closure with capture list
@@ -188,7 +237,22 @@ top_level
188237
pattern:
189238
name_pattern
190239
identifier: identifier "f"
191-
value: unsupported_node "{ [weak self] in self?.doThing() }"
240+
value:
241+
function_expr
242+
body:
243+
block
244+
stmt:
245+
call_expr
246+
callee:
247+
member_access_expr
248+
base: unsupported_node "self?"
249+
member: identifier "doThing"
250+
capture_declaration:
251+
variable_declaration
252+
modifier: unsupported_node "weak" <-- ERROR: The field variable_declaration.modifier should contain modifier, but got unsupported_node
253+
pattern:
254+
name_pattern
255+
identifier: identifier "self"
192256

193257
===
194258
Multi-statement closure
@@ -269,4 +333,35 @@ top_level
269333
pattern:
270334
name_pattern
271335
identifier: identifier "f"
272-
value: unsupported_node "{ (x: Int) -> Int in\n let y = x + 1\n return y * 2\n}"
336+
value:
337+
function_expr
338+
body:
339+
block
340+
stmt:
341+
variable_declaration
342+
modifier: modifier "let"
343+
pattern:
344+
name_pattern
345+
identifier: identifier "y"
346+
value:
347+
binary_expr
348+
operator: infix_operator "+"
349+
left:
350+
name_expr
351+
identifier: identifier "x"
352+
right: int_literal "1"
353+
return_expr
354+
value:
355+
binary_expr
356+
operator: infix_operator "*"
357+
left:
358+
name_expr
359+
identifier: identifier "y"
360+
right: int_literal "2"
361+
parameter:
362+
parameter
363+
pattern:
364+
name_pattern
365+
identifier: identifier "x"
366+
type: unsupported_node "Int"
367+
return_type: unsupported_node "Int"

0 commit comments

Comments
 (0)