[racket] Racket macros that run on files

From: Neil Van Dyke (neil at neilvandyke.org)
Date: Sun Nov 4 22:34:10 EST 2012

So you would like to be able to do things like rename an identifier, 
change "(if X Y)" to "(and X Y)", change "(if (not X) Y Z)" to "(if X Z 
Y)", etc.?

If so, I would probably start by letting user specify transformation 
rules like for "syntax-case" or "syntax-parse", do "read-syntax", do 
some simple tree traversal of the syntax objects that tries the rules at 
each step, have a matching rule add to a list of "progedit" "replace" 
operations, and then finally feed those operations through "progedit".

And alternative would be to use parse info from Check Syntax, perhaps 
with the user's transformation rules in effect.  I haven't thought that 
through, so it might be overkill.  If you go that direction, you might 
think of a different rules language, rather than "syntax-case" or 
"syntax-parse".

One gotcha with "progedit" with syntax objects, depending on how you use 
it: comments are not usually in the syntax objects, and can get deleted 
if you are not careful, or left in the wrong place if you don't do 
additional work.  For example of changing "if" forms to "and" forms, you 
want to replace only the "if" keyword, not the entire form, so that:

     (if X
         ;; hi
         Y)

ends up looking like this:

     (and X
         ;; hi
         Y)

If the replace operation is for the entire "if" form, you will lose the 
comment:

     (and X Y)

For example of comments in wrong place, let's say you are getting rid of 
"not" around the condition of an "if" form by swapping the order of the 
arms.  Like in previous example, to preserve comments, you want your 
progedit replace operations to focus on small pieces that don't have 
important comments within them, so if you do that, then this:

     (if (not X)
         ;; X is false, so Y
         Y
         ;; X is true, so Z
         Z)

becomes:

     (if X
         ;; X is false, so Y
         Z
         ;; X is true, so Z
         Y)

The problem is that the comments are in the wrong places.  The current 
version of progedit doesn't have any magic for moving comments around -- 
you'll have to figure out how you want comments moved, and then probably 
move the comments using progedit delete and insert operations, in 
addition to the syntax changes you are making.  An alternative way would 
be to have the syntax reader include syntax objects for comments, and 
then deal with it in pattern-matching and transformation that way.

(I plan to add these notes about comments to the progedit 
documentation.  No promises on building in smarter handling of comments 
into progedit itself anytime soon, unless a get a chance to think more 
about a good approach for it.)

Neil V.


Posted on the users mailing list.