Hello, I'm Nick Fitzgerald. This is my weblog. You can also check out my shared items from Reader, moments on Twitter, and code on GitHub. Feel free to contact me about whatever.
September 21st, 2009
Edit: I submitted this post to Hacker News to get some feedback and there is some small discussion over there.
It seems people other than myself would like to have macros in JavaScript, which makes me happy. Not as happy as if macros were part of the ECMAScript standard, but it is nice to know I'm not alone.
I have been wondering about how macros in JavaScript would work for a while now, and since I had the day off from work today, I made a little proof-of-concept.
<html>
<head>
<style>
.pass {
color:green;
}
.fail {
color:red;
}
</style>
</head>
<body>
<ul id="results">
</ul>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/macroJS" id="macroJS">
-> assert(val, desc) {
<< $("#results").append(
"<li class=\"" + (~> {
<< !!val ?
"pass" :
"fail";
}()) + "\">" + desc + "</li>");
}
assert(typeof(~> {}) === "function",
"The '~>' syntax is a function with one argument called '_'.");
assert(typeof(->() {}) === "function",
"The '->' syntax is short for 'function'.");
assert((~> {
<< true;
}()), "The '<<' syntax is short for 'return'.");
assert((~> {
var a = "broken";
unless (false) {
a = "works";
}
<< a === "works";
}()), "'Unless' is the opposite of 'if'.");
</script>
<script type="text/javascript">
eval((function (str) {
return str.replace(/unless[\s]*?\(/g, "if (!")
.replace(/->/g, "function")
.replace(/~>/g, "function (_)")
.replace(/<</g, "return");
}($("#macroJS").html())));
</script>
</body>
</html>
Of course, when you run the demo the descriptions in the assertions have been manipulated by the macro-expansion as well as the actual code, but the point is that the macros expand successfully.
I took the "->" and "~>" syntax from this interesting blog post, I came up with the "<<" syntax all by myself (!), and the "unless" statement is from the example in Peter Michaux's blog post.
The macros here are very simple syntax-hacks, and just a proof-of-concept, but I think it shouldn't be too hard to expand on these further. Since the replace method can take a function as a second argument that can access the grouped matches in your regexes, it is very possible to create more powerful macros.
Finally, would I consider using this technique for the code that I write at work or for my side projects? No, because the pain of debugging from inside an eval outweighs the potential benefits in this case. If you really want macros in JavaScript, your best bet is probably ParenScript.
Source Code Cartography on December 23rd, 2011
Pycco Needs a Loving Home on August 17th, 2011
Operational Transformation Part 2: Operations on April 5th, 2011
Operational Transformation: An Introduction on March 26th, 2011
JavaScript Timer Congestion on March 8th, 2011
OOP The Good Parts: Message Passing, Duck Typing, Object Composition, and not Inheritance on December 31st, 2010
Pythonic JavaScript Methods on November 16th, 2010
Pycco and Zoolander now on PyPi on October 13th, 2010
Implementing Multiple Value Returns in JavaScript on October 8th, 2010
setTimeout Patterns in JavaScript on August 10th, 2010
blog comments powered by Disqus