Skip to content

Commit d17fd2d

Browse files
committed
unified/swift: add variable/property/accessor and enum mappings
1 parent 4e9c3fb commit d17fd2d

6 files changed

Lines changed: 414 additions & 27 deletions

File tree

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

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,209 @@ fn translation_rules() -> Vec<yeast::Rule> {
8383
// Blocks contain statement* directly.
8484
rule!((block statement: _+ @stmts) => (block stmt: {..stmts})),
8585
rule!((block) => (block)),
86+
// ---- Variables ----
87+
// property_binding rules — these produce variable_declaration and/or accessor_declaration
88+
// nodes for individual declarators. The outer property_declaration rule splices these out
89+
// and attaches binding/modifiers from the parent.
90+
91+
// Computed property with explicit accessors (get/set/modify) →
92+
// a sequence of accessor_declaration nodes, each with the property name
93+
// attached. Subsequent accessors will be tagged chained_declaration by
94+
// the outer property_declaration rule.
95+
rule!(
96+
(property_binding
97+
name: @pattern
98+
type: _? @ty
99+
computed_value: (computed_property accessor: _+ @accessors))
100+
=>
101+
{..{
102+
let name_text = __yeast_ctx.ast.source_text(pattern.into());
103+
let ty_ids: Vec<usize> = ty.iter().map(|&t| t.into()).collect();
104+
let acc_ids: Vec<usize> = accessors.iter().map(|&a| a.into()).collect();
105+
for &acc_id in &acc_ids {
106+
let ident = __yeast_ctx.literal("identifier", &name_text);
107+
__yeast_ctx.prepend_field(acc_id, "name", ident);
108+
for &ty_id in ty_ids.iter().rev() {
109+
__yeast_ctx.prepend_field(acc_id, "type", ty_id);
110+
}
111+
}
112+
acc_ids
113+
}}
114+
),
115+
// Computed property: shorthand getter (no explicit get/set, just statements) →
116+
// a single accessor_declaration with kind "get".
117+
rule!(
118+
(property_binding
119+
name: (pattern bound_identifier: @name)
120+
type: _? @ty
121+
computed_value: (computed_property statement: _* @body))
122+
=>
123+
(accessor_declaration
124+
name: (identifier #{name})
125+
type: {..ty}
126+
accessor_kind: (accessor_kind "get")
127+
body: (block stmt: {..body}))
128+
),
129+
// Stored property with willSet/didSet observers (initializer optional) →
130+
// variable_declaration followed by one accessor_declaration per observer,
131+
// each carrying the property name. Subsequent items are tagged
132+
// chained_declaration by the outer property_declaration rule.
133+
rule!(
134+
(property_binding
135+
name: (pattern bound_identifier: @name)
136+
type: _? @ty
137+
value: _? @val
138+
observers: (willset_didset_block willset: _? @ws didset: _? @ds))
139+
=>
140+
{..{
141+
let name_text = __yeast_ctx.ast.source_text(name.into());
142+
let val_ids: Vec<usize> = val.iter().map(|&v| v.into()).collect();
143+
let ty_ids: Vec<usize> = ty.iter().map(|&t| t.into()).collect();
144+
let mut obs_ids: Vec<usize> = Vec::new();
145+
obs_ids.extend(ws.iter().map(|&o| { let id: usize = o.into(); id }));
146+
obs_ids.extend(ds.iter().map(|&o| { let id: usize = o.into(); id }));
147+
let ident_for_var = __yeast_ctx.literal("identifier", &name_text);
148+
let pat = __yeast_ctx.node("name_pattern", vec![("identifier", vec![ident_for_var])]);
149+
let mut var_fields: Vec<(&str, Vec<usize>)> = vec![("pattern", vec![pat])];
150+
if !ty_ids.is_empty() {
151+
var_fields.push(("type", ty_ids));
152+
}
153+
if !val_ids.is_empty() {
154+
var_fields.push(("value", val_ids));
155+
}
156+
let var_id = __yeast_ctx.node("variable_declaration", var_fields);
157+
let mut result = vec![var_id];
158+
for obs_id in obs_ids {
159+
let ident = __yeast_ctx.literal("identifier", &name_text);
160+
__yeast_ctx.prepend_field(obs_id, "name", ident);
161+
result.push(obs_id);
162+
}
163+
result
164+
}}
165+
),
166+
// property_binding with any pattern name (identifier or destructuring)
167+
rule!(
168+
(property_binding
169+
name: @pattern
170+
type: _? @ty
171+
value: _? @val)
172+
=>
173+
(variable_declaration
174+
pattern: {pattern}
175+
type: {..ty}
176+
value: {..val})
177+
),
178+
// property_declaration: splice declarators (each may translate to multiple nodes —
179+
// variable_declaration and/or accessor_declaration), and attach the binding modifier
180+
// (let/var) and any outer modifiers to each. All children after the first additionally
181+
// get a synthetic chained_declaration modifier so the grouping can be recovered.
182+
rule!(
183+
(property_declaration
184+
binding: (value_binding_pattern mutability: @binding_kind)
185+
declarator: _* @decls
186+
(modifiers)* @mods)
187+
=>
188+
{..{
189+
let binding_text = __yeast_ctx.ast.source_text(binding_kind.into());
190+
let mod_ids: Vec<usize> = mods.iter().map(|&m| m.into()).collect();
191+
let decl_ids: Vec<usize> = decls.iter().map(|&d| d.into()).collect();
192+
for (i, &decl_id) in decl_ids.iter().enumerate() {
193+
if i > 0 {
194+
let chained = __yeast_ctx.literal("modifier", "chained_declaration");
195+
__yeast_ctx.prepend_field(decl_id, "modifier", chained);
196+
}
197+
for &mod_id in mod_ids.iter().rev() {
198+
__yeast_ctx.prepend_field(decl_id, "modifier", mod_id);
199+
}
200+
let binding_mod = __yeast_ctx.literal("modifier", &binding_text);
201+
__yeast_ctx.prepend_field(decl_id, "modifier", binding_mod);
202+
}
203+
decl_ids
204+
}}
205+
),
206+
// ---- Enums ----
207+
// enum_type_parameter → parameter (with optional name as pattern).
208+
rule!(
209+
(enum_type_parameter name: @name type: @ty)
210+
=>
211+
(parameter
212+
pattern: (name_pattern identifier: (identifier #{name}))
213+
type: {ty})
214+
),
215+
rule!(
216+
(enum_type_parameter type: @ty)
217+
=>
218+
(parameter type: {ty})
219+
),
220+
// enum_case_entry with associated values → class_like_declaration containing
221+
// a constructor whose parameters are the data parameters.
222+
rule!(
223+
(enum_case_entry
224+
name: @name
225+
data_contents: (enum_type_parameters parameter: _* @params))
226+
=>
227+
(class_like_declaration
228+
modifier: (modifier "enum_case")
229+
name: (identifier #{name})
230+
member: (constructor_declaration parameter: {..params} body: (block)))
231+
),
232+
// enum_case_entry with explicit raw value → variable_declaration with that value.
233+
rule!(
234+
(enum_case_entry name: @name raw_value: @val)
235+
=>
236+
(variable_declaration
237+
modifier: (modifier "enum_case")
238+
pattern: (name_pattern identifier: (identifier #{name}))
239+
value: {val})
240+
),
241+
// enum_case_entry without associated values → variable_declaration tagged enum_case.
242+
rule!(
243+
(enum_case_entry name: @name)
244+
=>
245+
(variable_declaration
246+
modifier: (modifier "enum_case")
247+
pattern: (name_pattern identifier: (identifier #{name})))
248+
),
249+
// enum_entry: flatten case entries; attach outer modifiers to each, and
250+
// chained_declaration on every entry after the first.
251+
rule!(
252+
(enum_entry case: _+ @cases (modifiers)* @mods)
253+
=>
254+
{..{
255+
let mod_ids: Vec<usize> = mods.iter().map(|&m| m.into()).collect();
256+
let case_ids: Vec<usize> = cases.iter().map(|&c| c.into()).collect();
257+
for (i, &case_id) in case_ids.iter().enumerate() {
258+
if i > 0 {
259+
let chained = __yeast_ctx.literal("modifier", "chained_declaration");
260+
__yeast_ctx.prepend_field(case_id, "modifier", chained);
261+
}
262+
for &mod_id in mod_ids.iter().rev() {
263+
__yeast_ctx.prepend_field(case_id, "modifier", mod_id);
264+
}
265+
}
266+
case_ids
267+
}}
268+
),
269+
// Plain assignment: `x = expr`
270+
rule!(
271+
(assignment operator: "=" target: (directly_assignable_expression expr: @target) result: @value)
272+
=>
273+
(assign_expr target: {target} value: {value})
274+
),
275+
// Compound assignment: `x += expr` etc.
276+
rule!(
277+
(assignment operator: @op target: (directly_assignable_expression expr: @target) result: @value)
278+
=>
279+
(compound_assign_expr target: {target} operator: (infix_operator #{op}) value: {value})
280+
),
281+
// Unwrap `type` wrapper node
282+
rule!((type name: @inner) => {inner}),
283+
// `directly_assignable_expression` is just a wrapper; unwrap it
284+
rule!((directly_assignable_expression expr: @inner) => {inner}),
285+
// Pattern with bound_identifier → name_pattern
286+
rule!((pattern bound_identifier: @name) => (name_pattern identifier: (identifier #{name}))),
287+
// Tuple pattern (destructuring)
288+
rule!((pattern (pattern)* @elems) => (tuple_pattern element: {..elems})),
86289
// ---- Fallbacks ----
87290
rule!(
88291
(_)

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

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ source_file
5151
top_level
5252
body:
5353
block
54-
stmt: unsupported_node "let f = { (x: Int) -> Int in x * 2 }"
54+
stmt:
55+
variable_declaration
56+
modifier: modifier "let"
57+
pattern:
58+
name_pattern
59+
identifier: identifier "f"
60+
value: unsupported_node "{ (x: Int) -> Int in x * 2 }"
5561

5662
===
5763
Closure with shorthand parameters
@@ -85,7 +91,13 @@ source_file
8591
top_level
8692
body:
8793
block
88-
stmt: unsupported_node "let f = { $0 + $1 }"
94+
stmt:
95+
variable_declaration
96+
modifier: modifier "let"
97+
pattern:
98+
name_pattern
99+
identifier: identifier "f"
100+
value: unsupported_node "{ $0 + $1 }"
89101

90102
===
91103
Trailing closure
@@ -170,7 +182,13 @@ source_file
170182
top_level
171183
body:
172184
block
173-
stmt: unsupported_node "let f = { [weak self] in self?.doThing() }"
185+
stmt:
186+
variable_declaration
187+
modifier: modifier "let"
188+
pattern:
189+
name_pattern
190+
identifier: identifier "f"
191+
value: unsupported_node "{ [weak self] in self?.doThing() }"
174192

175193
===
176194
Multi-statement closure
@@ -245,4 +263,10 @@ source_file
245263
top_level
246264
body:
247265
block
248-
stmt: unsupported_node "let f = { (x: Int) -> Int in\n let y = x + 1\n return y * 2\n}"
266+
stmt:
267+
variable_declaration
268+
modifier: modifier "let"
269+
pattern:
270+
name_pattern
271+
identifier: identifier "f"
272+
value: unsupported_node "{ (x: Int) -> Int in\n let y = x + 1\n return y * 2\n}"

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

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ source_file
2929
top_level
3030
body:
3131
block
32-
stmt: unsupported_node "let xs = [1, 2, 3]"
32+
stmt:
33+
variable_declaration
34+
modifier: modifier "let"
35+
pattern:
36+
name_pattern
37+
identifier: identifier "xs"
38+
value: unsupported_node "[1, 2, 3]"
3339

3440
===
3541
Empty array literal with type
@@ -71,7 +77,14 @@ source_file
7177
top_level
7278
body:
7379
block
74-
stmt: unsupported_node "let xs: [Int] = []"
80+
stmt:
81+
variable_declaration
82+
modifier: modifier "let"
83+
pattern:
84+
name_pattern
85+
identifier: identifier "xs"
86+
type: unsupported_node ": [Int]"
87+
value: unsupported_node "[]"
7588

7689
===
7790
Dictionary literal
@@ -111,7 +124,13 @@ source_file
111124
top_level
112125
body:
113126
block
114-
stmt: unsupported_node "let d = [\"a\": 1, \"b\": 2]"
127+
stmt:
128+
variable_declaration
129+
modifier: modifier "let"
130+
pattern:
131+
name_pattern
132+
identifier: identifier "d"
133+
value: unsupported_node "[\"a\": 1, \"b\": 2]"
115134

116135
===
117136
Set literal
@@ -162,7 +181,14 @@ source_file
162181
top_level
163182
body:
164183
block
165-
stmt: unsupported_node "let s: Set<Int> = [1, 2, 3]"
184+
stmt:
185+
variable_declaration
186+
modifier: modifier "let"
187+
pattern:
188+
name_pattern
189+
identifier: identifier "s"
190+
type: unsupported_node ": Set<Int>"
191+
value: unsupported_node "[1, 2, 3]"
166192

167193
===
168194
Tuple literal
@@ -200,7 +226,13 @@ source_file
200226
top_level
201227
body:
202228
block
203-
stmt: unsupported_node "let t = (1, \"two\", 3.0)"
229+
stmt:
230+
variable_declaration
231+
modifier: modifier "let"
232+
pattern:
233+
name_pattern
234+
identifier: identifier "t"
235+
value: tuple_expr "(1, \"two\", 3.0)"
204236

205237
===
206238
Subscript access
@@ -243,7 +275,13 @@ source_file
243275
top_level
244276
body:
245277
block
246-
stmt: unsupported_node "let first = xs[0]"
278+
stmt:
279+
variable_declaration
280+
modifier: modifier "let"
281+
pattern:
282+
name_pattern
283+
identifier: identifier "first"
284+
value: unsupported_node "xs[0]"
247285

248286
===
249287
Dictionary subscript
@@ -286,7 +324,13 @@ source_file
286324
top_level
287325
body:
288326
block
289-
stmt: unsupported_node "let v = d[\"key\"]"
327+
stmt:
328+
variable_declaration
329+
modifier: modifier "let"
330+
pattern:
331+
name_pattern
332+
identifier: identifier "v"
333+
value: unsupported_node "d[\"key\"]"
290334

291335
===
292336
Tuple member access
@@ -319,4 +363,10 @@ source_file
319363
top_level
320364
body:
321365
block
322-
stmt: unsupported_node "let n = t.0"
366+
stmt:
367+
variable_declaration
368+
modifier: modifier "let"
369+
pattern:
370+
name_pattern
371+
identifier: identifier "n"
372+
value: unsupported_node "t.0"

0 commit comments

Comments
 (0)