@@ -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 ( _)
0 commit comments