Skip to content

Commit d9484e6

Browse files
committed
unified/swift: Propagate property_declaration modifiers via context
Gets rid of the final uses of mutation (via prepend_field). The approach is the same as in the preceding commits: we set the appropriate fields on the context when processing the outer node, and then access these fields on the inner nodes. The repeated use of `modifier` fields is a _bit_ clunky, but since we're likely moving to an out-of-band modifier mechanism at some point, I think it's good enough for now.
1 parent 7793702 commit d9484e6

1 file changed

Lines changed: 90 additions & 32 deletions

File tree

  • unified/extractor/src/languages/swift

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

Lines changed: 90 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@ struct SwiftContext {
2727
default_value: Option<yeast::Id>,
2828
/// Translated outer modifiers (e.g. visibility, attributes) to
2929
/// attach to each child of a flattening outer rule. Set by
30-
/// `protocol_property_declaration` (and, later,
31-
/// `property_declaration`/`enum_entry`).
30+
/// `property_declaration`, `enum_entry`, and
31+
/// `protocol_property_declaration`.
3232
outer_modifiers: Vec<yeast::Id>,
33+
/// The `let`/`var` binding modifier for a `property_declaration`.
34+
/// Set by `property_declaration`; read by the inner declaration
35+
/// rules (`property_binding` variants, accessor rules) so they
36+
/// emit it as part of the output node's `modifier:` field.
37+
binding_modifier: Option<yeast::Id>,
3338
/// True when the current child of a flattening outer rule is not
3439
/// the first one — its inner rule should emit a
3540
/// `chained_declaration` modifier so the original grouping can be
@@ -143,6 +148,12 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
143148
// (`computed_getter`/`computed_setter`/`computed_modify`) builds
144149
// its `accessor_declaration` with `name` and `type` set from the
145150
// start — no schema-invalid intermediate state.
151+
//
152+
// Toggles `ctx.is_chained` per accessor iteration: the first
153+
// accessor inherits the outer rule's chained state (i.e. whether
154+
// this whole property_binding is itself a non-first declarator
155+
// of a containing property_declaration); subsequent accessors
156+
// always emit `chained_declaration`.
146157
manual_rule!(
147158
(property_binding
148159
name: @pattern
@@ -160,21 +171,29 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
160171
ctx.property_type = translated_ty;
161172

162173
let mut result = Vec::new();
163-
for acc in &accessors {
164-
result.extend(ctx.translate(*acc)?);
174+
for (i, acc) in accessors.into_iter().enumerate() {
175+
if i > 0 {
176+
ctx.is_chained = true;
177+
}
178+
result.extend(ctx.translate(acc)?);
165179
}
166180
Ok(result)
167181
}
168182
),
169-
// Computed property: shorthand getter (no explicit get/set, just statements) →
170-
// a single accessor_declaration with kind "get".
183+
// Computed property: shorthand getter (no explicit get/set, just
184+
// statements) → a single accessor_declaration with kind "get".
185+
// Reads outer modifiers / chained tag from `ctx` (set by the
186+
// outer `property_declaration` rule).
171187
rule!(
172188
(property_binding
173189
name: (pattern bound_identifier: @name)
174190
type: _? @ty
175191
computed_value: (computed_property statement: _* @body))
176192
=>
177193
(accessor_declaration
194+
modifier: {..ctx.binding_modifier}
195+
modifier: {..ctx.outer_modifiers.clone()}
196+
modifier: {..chained_modifier(&mut ctx)}
178197
name: (identifier #{name})
179198
type: {..ty}
180199
accessor_kind: (accessor_kind "get")
@@ -187,6 +206,10 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
187206
// into `ctx` before translating the observer children so the
188207
// inner `willset_clause` / `didset_clause` rules construct
189208
// valid `accessor_declaration` nodes from the start.
209+
//
210+
// The `variable_declaration` itself inherits the outer rule's
211+
// chained state; observers always get `chained_declaration`
212+
// because they're subsequent outputs of this flattening rule.
190213
manual_rule!(
191214
(property_binding
192215
name: (pattern bound_identifier: @name)
@@ -201,13 +224,19 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
201224

202225
let var_decl = tree!(
203226
(variable_declaration
227+
modifier: {..ctx.binding_modifier}
228+
modifier: {..ctx.outer_modifiers.clone()}
229+
modifier: {..chained_modifier(&mut ctx)}
204230
pattern: (name_pattern identifier: (identifier #{name}))
205231
type: {..translated_ty}
206232
value: {..translated_val})
207233
);
208234

209235
// Publish the property name for the observer rules.
210236
ctx.property_name = Some(tree!((identifier #{name})));
237+
// Observers are subsequent outputs of this flattening
238+
// rule, so they always get `chained_declaration`.
239+
ctx.is_chained = true;
211240

212241
let mut result = vec![var_decl];
213242
for obs in ws.into_iter().chain(ds) {
@@ -216,45 +245,53 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
216245
Ok(result)
217246
}
218247
),
219-
// property_binding with any pattern name (identifier or destructuring)
248+
// property_binding with any pattern name (identifier or
249+
// destructuring). Reads outer modifiers / chained tag from `ctx`.
220250
rule!(
221251
(property_binding
222252
name: @pattern
223253
type: _? @ty
224254
value: _? @val)
225255
=>
226256
(variable_declaration
257+
modifier: {..ctx.binding_modifier}
258+
modifier: {..ctx.outer_modifiers.clone()}
259+
modifier: {..chained_modifier(&mut ctx)}
227260
pattern: {pattern}
228261
type: {..ty}
229262
value: {..val})
230263
),
231-
// property_declaration: splice declarators (each may translate to multiple nodes —
232-
// variable_declaration and/or accessor_declaration), and attach the binding modifier
233-
// (let/var) and any outer modifiers to each. All children after the first additionally
234-
// get a synthetic chained_declaration modifier so the grouping can be recovered.
235-
rule!(
264+
// property_declaration: flatten declarators (each may translate
265+
// to multiple nodes — variable_declaration and/or
266+
// accessor_declaration) and attach the binding modifier
267+
// (let/var), outer modifiers, and `chained_declaration` for
268+
// non-first declarations. Manual rule: publishes
269+
// binding/outer modifiers into `ctx` and translates each
270+
// declarator with `ctx.is_chained` toggled per iteration. The
271+
// inner declaration rules (`property_binding` variants,
272+
// accessor inner rules) read these fields and emit complete
273+
// `modifier:` lists from the start.
274+
manual_rule!(
236275
(property_declaration
237276
binding: (value_binding_pattern mutability: @binding_kind)
238277
declarator: _* @decls
239278
(modifiers)* @mods)
240-
=>
241-
{..{
242-
let binding_text = ctx.ast.source_text(binding_kind.into());
243-
let mod_ids: Vec<usize> = mods.iter().map(|&m| m.into()).collect();
244-
let decl_ids: Vec<usize> = decls.iter().map(|&d| d.into()).collect();
245-
for (i, &decl_id) in decl_ids.iter().enumerate() {
246-
if i > 0 {
247-
let chained = ctx.literal("modifier", "chained_declaration");
248-
ctx.prepend_field(decl_id, "modifier", chained);
249-
}
250-
for &mod_id in mod_ids.iter().rev() {
251-
ctx.prepend_field(decl_id, "modifier", mod_id);
252-
}
253-
let binding_mod = ctx.literal("modifier", &binding_text);
254-
ctx.prepend_field(decl_id, "modifier", binding_mod);
279+
{
280+
let binding_text = ctx.ast.source_text(binding_kind.0);
281+
ctx.binding_modifier = Some(ctx.literal("modifier", &binding_text));
282+
let mut modifiers = Vec::new();
283+
for m in mods {
284+
modifiers.extend(ctx.translate(m)?);
255285
}
256-
decl_ids
257-
}}
286+
ctx.outer_modifiers = modifiers;
287+
288+
let mut result = Vec::new();
289+
for (i, decl) in decls.into_iter().enumerate() {
290+
ctx.is_chained = i > 0;
291+
result.extend(ctx.translate(decl)?);
292+
}
293+
Ok(result)
294+
}
258295
),
259296
// ---- Enums ----
260297
// enum_type_parameter → parameter (with optional name as pattern).
@@ -996,12 +1033,16 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
9961033
// protocol_property_requirements wrapper — should be consumed by above; fallback
9971034
rule!((protocol_property_requirements accessor: _* @accs) => {..accs}),
9981035
// Computed getter → accessor_declaration (body optional).
999-
// Reads `ctx.property_name`/`ctx.property_type` set by the outer
1000-
// property_binding manual rule.
1036+
// Reads property name/type from the outer property_binding rule
1037+
// and binding/outer modifiers + chained tag from the outer
1038+
// property_declaration rule.
10011039
rule!(
10021040
(computed_getter body: (block statement: _* @body)?)
10031041
=>
10041042
(accessor_declaration
1043+
modifier: {..ctx.binding_modifier}
1044+
modifier: {..ctx.outer_modifiers.clone()}
1045+
modifier: {..chained_modifier(&mut ctx)}
10051046
name: {ctx.property_name.ok_or("computed_getter outside property_binding context")?}
10061047
type: {..ctx.property_type}
10071048
accessor_kind: (accessor_kind "get")
@@ -1012,6 +1053,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10121053
(computed_setter parameter: @param body: (block statement: _* @body))
10131054
=>
10141055
(accessor_declaration
1056+
modifier: {..ctx.binding_modifier}
1057+
modifier: {..ctx.outer_modifiers.clone()}
1058+
modifier: {..chained_modifier(&mut ctx)}
10151059
name: {ctx.property_name.ok_or("computed_setter outside property_binding context")?}
10161060
type: {..ctx.property_type}
10171061
accessor_kind: (accessor_kind "set")
@@ -1023,6 +1067,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10231067
(computed_setter body: (block statement: _* @body)?)
10241068
=>
10251069
(accessor_declaration
1070+
modifier: {..ctx.binding_modifier}
1071+
modifier: {..ctx.outer_modifiers.clone()}
1072+
modifier: {..chained_modifier(&mut ctx)}
10261073
name: {ctx.property_name.ok_or("computed_setter outside property_binding context")?}
10271074
type: {..ctx.property_type}
10281075
accessor_kind: (accessor_kind "set")
@@ -1033,6 +1080,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10331080
(computed_modify body: (block statement: _* @body))
10341081
=>
10351082
(accessor_declaration
1083+
modifier: {..ctx.binding_modifier}
1084+
modifier: {..ctx.outer_modifiers.clone()}
1085+
modifier: {..chained_modifier(&mut ctx)}
10361086
name: {ctx.property_name.ok_or("computed_modify outside property_binding context")?}
10371087
type: {..ctx.property_type}
10381088
accessor_kind: (accessor_kind "modify")
@@ -1043,11 +1093,16 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10431093
// captures the willset/didset clauses directly).
10441094
rule!((willset_didset_block _* @clauses) => {..clauses}),
10451095
// willset clause → accessor_declaration (body optional). Reads
1046-
// `ctx.property_name` set by the outer property_binding rule.
1096+
// `ctx.property_name` set by the outer property_binding rule and
1097+
// binding/outer modifiers + chained tag from the outer
1098+
// property_declaration rule.
10471099
rule!(
10481100
(willset_clause body: (block statement: _* @body)?)
10491101
=>
10501102
(accessor_declaration
1103+
modifier: {..ctx.binding_modifier}
1104+
modifier: {..ctx.outer_modifiers.clone()}
1105+
modifier: {..chained_modifier(&mut ctx)}
10511106
name: {ctx.property_name.ok_or("willset_clause outside property_binding context")?}
10521107
accessor_kind: (accessor_kind "willSet")
10531108
body: (block stmt: {..body}))
@@ -1057,6 +1112,9 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
10571112
(didset_clause body: (block statement: _* @body)?)
10581113
=>
10591114
(accessor_declaration
1115+
modifier: {..ctx.binding_modifier}
1116+
modifier: {..ctx.outer_modifiers.clone()}
1117+
modifier: {..chained_modifier(&mut ctx)}
10601118
name: {ctx.property_name.ok_or("didset_clause outside property_binding context")?}
10611119
accessor_kind: (accessor_kind "didSet")
10621120
body: (block stmt: {..body}))

0 commit comments

Comments
 (0)