Domain Specific Languages with Boo: AST Macros
If any code snippets or content appear broken or missing, you can find this same post with its full content at blog.foundev.pro.
For those of you who don’t know what Boo is its a statically typed CLR language with Python like syntax that lets you extend it’s compiler, and the language itself easily by giving you access to the AST (Abstract Syntax Tree) and compiler’s context directly. This gives you very powerful tools for building your own language or Domain Specific Language or DSL from here on out. Some examples of DSL’s include rSpec and Fluent NHibernate. In fact the entire subject of what is a DSL and what types of DSL there are and how to create a proper DSL could be a book itself and a fascinating one at that.
Which is why I’ve been reading Ayende’s book DSLs in Boo: Domain Specific Languages in .NET. To make sure I understood the concepts I’ve taken to building a toy BDD DSL called bSpec, it’s got a long way to go to be something useful and I may not care to take it that far, however I did get my brain wrapped around a really cool thing called AST Macros.
AST macros give you FULL access to the compiler context and full AST of the code. I could describe this in more detail but a code sample goes light years to making this helpful.
Let’s say I want to have a “shouldFail” method that fails my spec immediately how would I do that?
macro should_fail:
#create code using Quasi Quotation ( ”[|” and ”|]” )
codeblock = [|
raise AssertionError(“failed by request”)
|] #exit macro statement
return codeblock #now replace ”should_fail” with ”raise AssertionError() ”
#client code
should_fail #throws AssertionError
<p>
 
</p>
<p>
In reflector in C# the code looks like so:
</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<div style="font-family:consolas,lucida console,courier,monospace">
<span style="color:#008000"><b>throw</b></span> <span style="color:#008000"><b>new</b></span> <span style="color:#0000FF">AssertionError</span>(<span style="color:#BA2121">“automatic failure as requested by ’should fail call'”</span>);
</div>
</div>
<p>
So how did this happen?  Well as part of Boo’s compiler pipeline it will run the macros first and replace the macro statement itself with what the macro returns. So far this doesn’t seem particularly interesting until you try and actually manipulate and work with the AST itself or get access to compiler objects.   For a simple example lets look at what I did with the “describe” macro.
</p>
<div style="padding-bottom: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;float: none;padding-top: 0px" class="wlWriterEditableSmartContent">
<div style="font-family:consolas,lucida console,courier,monospace">
<span style="color:#408080"><i>#Describe Macro </i></span></p>
<p>
macro describe:<br />         <span style="color:#408080"><i>#creates a reference to the first argument</i></span><br />         itemtodescribe <span style="color:#666666">=</span> <span style="color:#008000"><b>cast</b></span>(ReferenceExpression, describe.Arguments[<span style="color:#666666"></span>])<br />        
</p>
<p>
        <span style="color:#408080"><i>#using a simple trick to prevent compiler errors. I just want access to the body of ”block” so</i></span><br />         <span style="color:#408080"><i># you can safely ignore block in my example</i></span><br />         <span style="color:#408080"><i>#note the key is using $itemtodescribe . this is how you pass in macro variables to the AST</i></span><br />         logdescribe <span style="color:#666666">=</span> [<span style="color:#666666">|</span><br />                 block:<br />                         _spechash[$itemtodescribe] <span style="color:#666666">=</span> <span style="color:#008000">null</span><br />         <span style="color:#666666">|</span>].Body<br />         <span style="color:#008000"><b>yield</b></span> logdescribe   <span style="color:#408080"><i>#this will become the first statement</i></span><br />         <span style="color:#008000"><b>yield</b></span> describe.Body <span style="color:#408080"><i>#the specified code block after ”describe FooBart: ” will now be placed</i></span>
</p>
<p>
<span style="color:#408080"><i>#Unit Test Code with asserts removed</i></span>
</p>
<p>
<span style="color:#008000"><b>class</b></span> <span style="color:#0000FF"><b>DescribeSpecs_When_Not_Nested</b></span>:
</p>
<p>
        <span style="color:#008000"><b>private</b></span> _spechash <span style="color:#008000"><b>as</b></span> Hash<br />         <span style="color:#008000"><b>private</b></span> _called <span style="color:#008000"><b>as</b></span> List[<span style="color:#008000"><b>of</b></span> string]
</p>
<p>
        <span style="color:#008000"><b>public</b></span> <span style="color:#008000"><b>def</b></span> <span style="color:#0000FF">constructor</span>():<br />                 _spechash <span style="color:#666666">=</span> {}<br />                 <span style="color:#008000">self</span>._called <span style="color:#666666">=</span> List[<span style="color:#008000"><b>of</b></span> string]()<br />                 describe FooBart:<br />                         _called.Add(<span style="color:#BA2121">“called from FooBart spec”</span>) <br />         
</p>
<p>
<span style="color:#408080"><i>#compiled output via reflector</i></span>
</p>
<p>
<span style="color:#008000"><b>class</b></span> <span style="color:#0000FF"><b>DescribeSpecs_When_Not_Nested</b></span>:
</p>
<p>
        <span style="color:#008000"><b>private</b></span> _spechash <span style="color:#008000"><b>as</b></span> Hash<br />         <span style="color:#008000"><b>private</b></span> _called <span style="color:#008000"><b>as</b></span> List[<span style="color:#008000"><b>of</b></span> string]
</p>
<p>
        <span style="color:#008000"><b>public</b></span> <span style="color:#008000"><b>def</b></span> <span style="color:#0000FF">constructor</span>():<br />                 _spechash <span style="color:#666666">=</span> {}<br />                 <span style="color:#008000">self</span>._spechash[<span style="color:#008000">typeof</span>(FooBart)] <span style="color:#666666">=</span> <span style="color:#008000">null</span>;  <span style="color:#408080"><i>#this is the key change</i></span><br />                 <span style="color:#008000">self</span>._called <span style="color:#666666">=</span> List[<span style="color:#008000"><b>of</b></span> string]()
</p>
</div>
</div>
<p>
So our macro has replaced code again, but this time references a field in a class that it had no prior knowledge of, yet it safely compiles. However, it would not have if there had been no field called “_spechash”. Amazingly this simple trick is only one of many ways you can extend the Boo language in a late binding fashion yet still get all the benefits of the CLR and compile time error checking.  Follow my blog in the coming weeks for more of the Boo language.
</p>
