Domain specific languages often serve the purpose they were designed for better than a general scripting language.
At work we use a tool call ‘m’ every day. In fact it’s a vital part of our infrastructure. Generally one of the first milestones of a new platform is getting ‘m’ generating files for the tool chain. The ins and outs of the whole thing aren’t really that important to illustrate my point, and the bulk of the tool resides in the back-end generation and processing rather than the language parsing — which is just short of 300 lines of code.
The tool itself is a make tool in the same vein as CMake, PreMake and BakeFile but probably predating them all by a fair old margin. It started life many years ago as a way to configure Visual Studio projects automatically and hierarchically. The idea was that each directory contained a configuration file in which you could specify options to set in the project file. Configuration files inherited settings from the parent directory configuration file, thus allowing you to turn compiler flags on and off from a root configuration file without having to edit every single project file in the code base.
The syntax evolved to make it easy to specify different settings for different configurations, and eventually different platforms. It became convenient to specify source files in the configuration files as well. Now the tool outputs native build files for around seven platforms and it will also by default kick off the using the native tools after generating the files.
The syntax is very simple. It contains just a few constructs: items, lists, compounds and variables.
# list items can be separated with white space, or semi-colons
list: entry1 entry2 entry3
list: entry1; entry2; entry3
# items are just entries in any compound
item1
item2
"item3"
# variables are themselves lists
variable1 = a;
variable2 += b;
variable2 -= b;
# compounds have a type and id
Type(Id)
{
}
These elements are used to describe a build. Compounds actually act like permutations so we can completely describe a build for all platforms and configurations without branching for different combinations and parsing multiple times.
Platform(Win32)
{
Configuration(Release)
{
variable = "I'm only for win32 release"
}
variable = "I'm for any win32 build"
}
Configuration(Release)
{
variable = "I'm for any release build on any platform"
}
Platform(Win32,Xenon)
{
variable = "I'm for Win32 and Xenon builds"
}
Mixed into this is some macro manipulation so you can access the environment or variables in strings, and some nice path logic that makes specifying paths more intuitive. The most interesting part of the latter being that every variable and item remembers the file where it was first defined or last modified so paths can always be specified relatively.
Preprocessor += "#(ENVIRONMENT_VARIABLE)"
Preprocessor += "%(another_variable)"
Preprocessor += "%(another_variable:a_modifier)"
Source("MyStuff")
{
"../common_source/afile.cpp"
}
Anyhow, it’s not perfect and has some crufty aspects which make me unhappy such as using ‘,’ instead of ‘.’ for joining compounds or calling what are effectively procedures ‘pseudo_projects’ and so on — but it’s intuitive, simple and new people pick it up real quick.
Onto my point.
Every now and again I have a go at redesigning the front end and replacing it with something like Python, JavaScript, Lua or even XML-with-juicy-bits. The idea being that we will get more mileage out of using a standard syntax as people will pick it up more easily and will be able to do much more with it than our mini-language. Also I secretly want to describe release processes and packaging operations which can’t be done well in the current syntax, so using a general syntax makes should allow this — in a vague hand waving type way.
The results of these attempts are perfectly serviceable in that they produce the same results but they’re never as good as what we already have. You always end up typing a lot more to do anything, and it never looks or feels as fluid. You can’t describe a build as well or as concisely and it feels like you’re jumping through hoops to achieve what was previously really simple. The idea is that you shouldn’t have to think about describing your build. It’s called ‘m’ so you only have one letter to type at the command prompt (if you use one). It’s unobtrusive, you tell it what you need and off you go — getting on with the more important task of shipping your product on a myriad of platforms.
My point is that when you’ve got Lua/XML/Python/C#/etc. every problem has a tendency to look like a Lua/XML/Python/C#/etc. hole that of course Lua/XML/Python/C#/etc. can neatly fill. When you only have a hammer, everything looks like a nail.
2 Comments
So - you ARE indeed alive (and somewhat recently). Brian got a hold of me on Facebook. What have you been up to in the past 7-8 years or so?
Ciao,
- Joe (Vastator/#coders)
Yep indeedy, I’m alive! I’ll drop you an email!
Post a Comment