Procedural Macros vs. Macros

11 June 2016

I’m using rustc 1.11.0-nightly (915b003e3 2016-06-02) for this post

Starting not one, but two projects revolving around procedural macros is a great way to learn a thing or two about them. One thing that bugged me was that they didn’t work easily when the code that should be manipulated involved macros. Luckily, stackoverflow user ker helped me out, and I wanted to share the technique here.

The idea is that we don’t care about macros – we do care about the expanded code coming out of it. Macros we care about can appear in Item position and in Expr position. For both, we want to expand the macros and apply whatever transformation we implement on the resulting Expr s or Item s.

Without further ado, here’s the code:

impl < 'a , 'cx > Folder for Overflower < 'a , 'cx > { fn fold_item ( & mut self , item : P < Item > ) -> SmallVector < P < Item >> { if let ItemKind :: Mac ( _ ) = item .node { let expanded = expand_item ( item , & mut self .cx .expander ()); expanded .into_iter () .flat_map (| i | self .fold_item ( i ) .into_iter ()) .collect () } else { fold :: noop_fold_item ( item , self ) } } fn fold_expr ( & mut self , expr : P < Expr > ) -> P < Expr > { if self .mode == Mode :: DontCare { return expr ; } if let ExprKind :: Mac ( _ ) = expr .node { let expanded = expand_expr ( expr .unwrap (), & mut self .cx .expander ()); self .fold_expr ( expanded ) } else { .. } } .. }