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>

Demo

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.