Domain-Specific Languages

I'm quite attracted by the idea of domain-specific languages, but so far I haven't found a satisfactory way to create them.

For a while I was writing a lot of MSBuild tasks.  I found the programming model for a MSBuild tasks to be a bit awkward.  You have to write properties where fields should be sufficient.  For MSBuild to see a property accessor, it has to be 'public', even though you don't want anyone else to ever use the accessor (not even yourself!).  

So, I wrote a tool that generates the boilerplate MSBuild task code.  (I also took the opportunity to convert T[] to List<T> in your code, which is usually nicer to code against.) I wrote it as an MSBuild task, which is convenient when it comes time to hook it in to the build system. The input language is MSBuild, which is XML.  XML is an awkward language for humans to read & write, though, so it wasn't quite satisfactory. 

(Yes, the task is built with itself.  Not the latest version, but a last-known-good ("LKG") version.)

I later needed to write a lot of Windows Workflow Activities.  When you want to add a property to an activity, you have to write a lot of code.  You want to express a simple idea (type, name, and comment:) and you have to write all this:

        /// <summary>

        /// DependencyProperties allow input parameters to be bound at runtime to any class member property

        /// of compatible type in the workflow/activity hierarchy.

        /// </summary>

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2211:NonConstantFieldsShouldNotBeVisible", Justification = "WF requires this.")]

        public static DependencyProperty SkuNameProperty = System.Workflow.ComponentModel.DependencyProperty.Register("SkuName", typeof(string), typeof(ComputeRpsInputsActivity));

        /// <summary>

        /// Input parameter. The name of the SKU that is being tested. E.g., 'vs_vsts'.

        /// </summary>

        [Description("The name of the SKU that is being tested. E.g., 'vs_vsts'.")]

        [Browsable(true)]

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

        public string SkuName

        {

            get

            {

                return (string)base.GetValue(MyActivity.SkuNameProperty);

            }

            set

            {

                base.SetValue(MyActivity.SkuNameProperty, value);

    }

        }

So, using my task-generating task, I wrote a new MSBuild task that would generate this sort of property definition code.  It went pretty quickly, since I already had the task generator code in hand, and CodeCom still fresh in my mind. It was a big win, cleaning up the activity code dramatically.  However, I'm still disappointed by the use of XML as an input language. 

In both cases, the work of writing the DSL tool was difficult to justify.  In a general-purpose programming language, it makes sense to make a big investment in the tools & design of the language.  You want the use of the language to go smoothly, the language should be powerful, and the result should be readable.  However, in a DSL, you have to balance those goals against the need to make the DSL cheap.  Cost of entry is a big deal in DSLs.

In a couple places (his book, his interview), Bruce Payette talks about using PowerShell to create a DSL.  I'm hopeful that this technique can meet the goals above. 

What have you used to create DSLs?