@@ -185,16 +185,127 @@ fn write_visit_trait(file: &mut File, config: &Config) -> Result<(), Box<dyn std
185185 writeln ! ( file, "}}" ) ?;
186186 writeln ! ( file) ?;
187187
188+ // Map C field types (e.g. `rbs_type_name`) to the corresponding
189+ // visitor method name (e.g. `type_name` -> `visit_type_name_node`).
190+ let visitor_method_names: std:: collections:: HashMap < String , String > = config
191+ . nodes
192+ . iter ( )
193+ . map ( |node| {
194+ let c_type = convert_name ( & node. name , CIdentifier :: Type ) ;
195+ let c_type = c_type. strip_suffix ( "_t" ) . unwrap_or ( & c_type) . to_string ( ) ;
196+ let method = convert_name ( node. variant_name ( ) , CIdentifier :: Method ) ;
197+ ( c_type, method)
198+ } )
199+ . collect ( ) ;
200+
201+ let is_visitable = |c_type : & str | -> bool {
202+ matches ! ( c_type, "rbs_node" | "rbs_node_list" | "rbs_hash" )
203+ || visitor_method_names. contains_key ( c_type)
204+ } ;
205+
188206 for node in & config. nodes {
189207 let node_variant_name = node. variant_name ( ) ;
190208 let method_name = convert_name ( node_variant_name, CIdentifier :: Method ) ;
191209
192- writeln ! ( file, "#[allow(unused_variables)]" ) ?; // TODO: Remove this once all nodes that need visitor are implemented
210+ let has_visitable_fields = node
211+ . fields
212+ . iter ( )
213+ . flatten ( )
214+ . any ( |field| is_visitable ( & field. c_type ) ) ;
215+
216+ if !has_visitable_fields {
217+ writeln ! ( file, "#[allow(unused_variables)]" ) ?;
218+ }
193219 writeln ! (
194220 file,
195221 "pub fn visit_{}_node<V: Visit + ?Sized>(visitor: &mut V, node: &{}Node) {{" ,
196222 method_name, node_variant_name
197223 ) ?;
224+
225+ if let Some ( fields) = & node. fields {
226+ for field in fields {
227+ let field_method_name = if field. name == "type" {
228+ "type_"
229+ } else {
230+ field. name . as_str ( )
231+ } ;
232+
233+ match field. c_type . as_str ( ) {
234+ "rbs_node" => {
235+ if field. optional {
236+ writeln ! (
237+ file,
238+ " if let Some(item) = node.{field_method_name}() {{"
239+ ) ?;
240+ writeln ! ( file, " visitor.visit(&item);" ) ?;
241+ writeln ! ( file, " }}" ) ?;
242+ } else {
243+ writeln ! ( file, " visitor.visit(&node.{field_method_name}());" ) ?;
244+ }
245+ }
246+
247+ "rbs_node_list" => {
248+ if field. optional {
249+ writeln ! (
250+ file,
251+ " if let Some(list) = node.{field_method_name}() {{"
252+ ) ?;
253+ writeln ! ( file, " for item in list.iter() {{" ) ?;
254+ writeln ! ( file, " visitor.visit(&item);" ) ?;
255+ writeln ! ( file, " }}" ) ?;
256+ writeln ! ( file, " }}" ) ?;
257+ } else {
258+ writeln ! ( file, " for item in node.{field_method_name}().iter() {{" ) ?;
259+ writeln ! ( file, " visitor.visit(&item);" ) ?;
260+ writeln ! ( file, " }}" ) ?;
261+ }
262+ }
263+
264+ "rbs_hash" => {
265+ if field. optional {
266+ writeln ! (
267+ file,
268+ " if let Some(hash) = node.{field_method_name}() {{"
269+ ) ?;
270+ writeln ! ( file, " for (key, value) in hash.iter() {{" ) ?;
271+ writeln ! ( file, " visitor.visit(&key);" ) ?;
272+ writeln ! ( file, " visitor.visit(&value);" ) ?;
273+ writeln ! ( file, " }}" ) ?;
274+ writeln ! ( file, " }}" ) ?;
275+ } else {
276+ writeln ! (
277+ file,
278+ " for (key, value) in node.{field_method_name}().iter() {{"
279+ ) ?;
280+ writeln ! ( file, " visitor.visit(&key);" ) ?;
281+ writeln ! ( file, " visitor.visit(&value);" ) ?;
282+ writeln ! ( file, " }}" ) ?;
283+ }
284+ }
285+
286+ _ => {
287+ if let Some ( visit_method_name) = visitor_method_names. get ( & field. c_type ) {
288+ if field. optional {
289+ writeln ! (
290+ file,
291+ " if let Some(item) = node.{field_method_name}() {{"
292+ ) ?;
293+ writeln ! (
294+ file,
295+ " visitor.visit_{visit_method_name}_node(&item);"
296+ ) ?;
297+ writeln ! ( file, " }}" ) ?;
298+ } else {
299+ writeln ! (
300+ file,
301+ " visitor.visit_{visit_method_name}_node(&node.{field_method_name}());"
302+ ) ?;
303+ }
304+ }
305+ }
306+ }
307+ }
308+ }
198309 writeln ! ( file, "}}" ) ?;
199310 writeln ! ( file) ?;
200311 }
@@ -226,6 +337,12 @@ fn generate(config: &Config) -> Result<(), Box<dyn Error>> {
226337 writeln ! ( file, "}}\n " ) ?;
227338
228339 writeln ! ( file, "impl {} {{" , node. rust_name) ?;
340+ writeln ! ( file, " /// Converts this node to a generic node." ) ?;
341+ writeln ! ( file, " #[must_use]" ) ?;
342+ writeln ! ( file, " pub fn as_node(self) -> Node {{" ) ?;
343+ writeln ! ( file, " Node::{}(self)" , node. variant_name( ) ) ?;
344+ writeln ! ( file, " }}" ) ?;
345+
229346 if let Some ( fields) = & node. fields {
230347 for field in fields {
231348 match field. c_type . as_str ( ) {
0 commit comments