You don’t have to be a compiler to manipulate a syntax tree

There was an interesting post this week which talked about using macros with JavaScript to implement new language features. In the post, the author references a GitHub project where he has been implementing some of the language features of ES6. Of course, JavaScript the language doesn’t offer macros, so this work is all based on sweet.js, a Mozilla project which takes JavaScript with macros and transcompiles it down to straight JavaScript. For a sense of the kind of transformations you can do, take a look at the documentation here.

Having used macros a lot in my days as a Common Lisp programmer, I’m a fan. They are certainly a good way to allow you to author an internal DSL and then get the compiler to transform it down into the base language. Keeping everything in the same language means that you can use your usual debugging tools both to debug the transformation and to debug the code that is produced. In a Common Lisp system the compiler can often track how code in the original DSL is pushed into the final implementation code, and therefore can link them up when you are source code debugging.

The big advantage of languages like Common Lisp and its derivatives like Clojure, are that the syntax tree is presented to the macro function in a form that uses the base datatypes of the language and more specially in the actual datatypes that you, the user, use to express your program – atoms, lists and vectors. You don’t get this in other languages, where parsing is a lot more complicated, and here you need to use accessors to navigate around the syntax tree which  feels a lot less natural.

The thesis of the post is that macros might well be a better way of adding new language features, when compared to the current method of writing yet another transcompiler which takes a modified version of the language and  converts it to JavaScript. Macros seem to be a good way to go, as long as the syntax of the derived language doesn’t differ too much from standard JavaScript, which is certainly the case for the internal DSL use case. The post emphasises hygienic macros, but as the documentation shows case macros allow you to take more control of the expansion allowing you to implement things like the classic  anaphoric if example.

Macros started in early versions of Lisp, but have been making their way into other languages too. Scala, for example, has had them for some time with a design that fits in well with an emphasis on domain specific languages (though that example doesn’t actually use macros).

This entry was posted in Computers and Internet. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s