Overview of creating custom DSL with Boo

Thursday, July 3rd, 2008 | Articles, How To, Snippets

Here’s a short overview of creating custom DSL with Boo. It will serve as technical intro point to the Capture business requirements with Boo-based DSL series.

Basically, when we create custom DSL with Boo, we just add our own steps to the Boo compiler pipeline. These steps inform the compiler how to transform our DSL to valid Boo syntax. Then, the actual compilation steps kick off and compile the results into .NET code.

Since Boo syntax itself is also quite flexible and customizable, later on we can take advantage of this too and make our DSL even more expressive.

One of the transformation approaches (I think Ayende came up with it, although not 100% sure about that) works like this:

  • We take existing Boo compiler and add custom step that will know about some abstract BaseClass (it has to have overridable InitializeMethod) and will process your script files.
  • This compiler step will do the following for every script file:
    • Create new class declaration named as the script file
    • Inherit this class declaration from the BaseClass
    • Put all the script code into override DerivedClass.InitializeMethod
    • Pass the derived class down to the compiler chain.
  • We create our actual BaseClass code and:
    • Add InitializeMethod
    • Add other methods that represent custom syntax
    • Add expression transformations decorated with the MetaAttribute

Let’s talk about “methods that represent custom syntax”.

Basically, if we want to have something like this in our MyFirstWorkflow.boo script:

define_workflow "My custom workflow"

step "Start"
step "Finish"

then we have to write our base class as:

public abstract class BaseClass
{
  public abstract void InitializeMethod();

  protected string workflowName;
  protected List<string> steps = new List<string>();

  protected void define_workflow(string name)
  {
    workflowName = name;
  }

  protected void step(string name)
  {
    steps.Add(name);
  }

  public void Execute()
  {
    Console.WriteLine("My name is '{0}'", workflowName);
    Console.WriteLine("I have steps:");
    foreach (var step in steps)
    {
        Console.WriteLine("  {0}",step);
    }
  }
}

And then the code above will be translated into (picture from the .NET Reflector):

Translated Boo DSL

When you grab the instance of this class and do something like this:

BaseClass instance = new MyFirstWorkflow();
instance.InitializeMethod();
instance.Execute();

it will output:

My name is 'Program Change'
I have steps:
  Start
  Finish

Adding another script file MySecondWorkflow.boo will result in another class inheriting from the BaseClass. And contents of its InitializeMethod will be specific to the that script.

Obviously, there is much more that could be done with this simple workflow (and there should be done more to make it useful), but the core principle of extending Boo compiler will stay the same.

Now, if you want to go into the code, I refer you (again) to Rhino DSL that has all the code required for pushing this sample into work (and there are way more samples). Additionally the Boo+DSL+Business series will get more articles and resources as the time goes on.

Tags:

1 Comment to Overview of creating custom DSL with Boo

[...] About « Overview of creating custom DSL with Boo [...]

Leave a comment

RSS

Search

Archives