Scrap Your BoilerPlate and Data.Generics for the Win!

Posted on October 23, 2008. Filed under: Uncategorized | Tags: , , , , |

I just updated as3tohaxe with a pretty significant change to allow transforming and querying of the AST. I was working in the translator code to add the ability to convert variable bindings with Number types a little more intelligently.

I wanted to convert this AS3:

        public function s(s:String = "hi", a:Number = -1.0, b:Number = 1):void{
            var c:Number = 0;
            var d:Number = 10.0;
            var o:Dynamic = {}; 

to this haXe:

        public function s(?s:String = "hi", ?a:Float = -1.0, ?b:Int = 1):Void{
            var c:Int = 0;
            var d:Float = 10.0;
            var o:Dynamic = {}; 

Notice how the Number types are changed to Int or Float depending on the initializer.

So I was about to embark on writing a bunch of tedious, error-prone, boilerplate code to deconstruct the nested and recursive AST nodes. The idea was to perform tests to get down to the bottom of the expression syntax tree to see if there was a float somewhere.

I wanted the code to look something like this pseudo Haskell:

hasFloat e = 
    case e of
        ACond a -> case a of
        .... more nested cases till we get to 
            TokenDouble _ -> True ... 
        otherwise -> False

But I stopped myself after taking a minute to look at the craziness of the AST just for a simple expression for -1.

ACond (CondE (AEUnary (UEMinus ([(TPos "" 8 63,TokenOp "-")],[]) (UEPrimary (PFFull (FPFPrimary (PELit ([(TPos "" 8 64,TokenNum (TokenDouble "1.0"))],[])) []) Nothing)))) Nothing)))


I realized and was hoping someone had dealt with this problem before and found a better way. So I started searching and landed on JP Moresmau’s blog where he talked about issues with nested records. My problem being nested/recursive constructors seemed to be on a similar boat. After more googling I came across “Scrap Your Boilerplate” which looked like a solution amongst others like polyP and Generic Haskell. I don’t know enough about Haskell to make an informed opinion on those, but SYB did the trick. And after more digging I found JP had posted about haskell’s Data.Generics.

Now I can write tests like:

hasFloat = everything (||) (False `mkQ` isFloat)
isFloat (TokenDouble x) = True
isFloat _ = False

which traverses the AST looking for floats.

I wish this were documented in the haskell tutorials. SYB is a lifesaver!

Read Full Post | Make a Comment ( 2 so far )

Liked it here?
Why not try sites on the blogroll...