Revision as of 00:34, 26 January 2011

JMacro is a library for the programmatic generation of Javascript
code. It is designed to be multipurpose -- it is useful whether you
are writing nearly vanilla Javascript or you are programmatically
generating Javascript either in an ad-hoc fashion or as the backend to
a compiler or EDSL.

It provides support for hygienic names, as well as sharing of names
between the generated Javascript and embedded Haskell antiquotation.

The jmacro package also provides a standalone executable, which may be used to compile JMacro syntax directly to Javascript.

JMacro provides a simple, lightweight quasiquoted syntax that is
mainly compatible with standard Javascript. Most Javascript code in
the wild can be used as JMacro code with no or minimal modification.
However, JMacro extends Javascript syntax in a number of
Haskell-friendly ways, including whitespace function application and
single character lambdas. Syntax is statically checked at compile
time. JMacro expressions may contain antiquoted Haskell code. This
code may generate further JMacro code, or it may generate any of a
range of standard Haskell types, which are able to be marshalled into
JMacro through typeclass methods.

Note that jmacro itself is untyped, which means that the generated javascript may not be typesafe. This is a feature, as a great deal of useful javascript code is either hard to type, or simply not statically typeable. Take, for example, the commonly used jQuery library. Depending on the string argument to the $ function, the returned value can vary over a range of types.

1.2 Functional Syntax

Jmacro provides a mixed-functional syntax. Nearly all valid javascript code is also valid jmacro code. Code from the documentation of an existing library can be copied and pasted directly into Haskell as a jmacro block. However, jmacro also provides a great deal of syntactic sugar that allows code to be written in a considerably more functional style, akin to Haskell or ML. Notably, anonymous functions may be introduced with a single backslash, and function application may be denoted by simple whitespace. Hence, this is valid jmacro describing a function which doubles a number:

\x -> x + x

1.3 Hygienic Names, Proper Scoping

It is common, when generating Javascript, to want to compose blocks of code which operate on different parts of a page. These blocks of code may find it necessary to introduce top-level variables for sharing state. Typically, this is resolved by placing these blocks of code within an anonymous function to provide namespacing. When two blocks of jmacro code are composed, however, variable declarations within each will *automatically* be named in the generated code so as not to overlap. This additionally allows jmacro to provide proper block-level scoping, which does not exist in standard Javascript.

Thus, in the following example, the two declarations of `var x` produce *different* identifiers in the generated javascript:

1.4 Antiquotation, Marshalling and Unmarshalling, Shared Scope

The ability to provide hygienic names becomes particularly useful when coupled with antiquotation. Within a Haskell program, quoted jmacro code blocks may contain antiquotations, which themselves contain Haskell code. The antiquoted Haskell code may either produce a jmacro expression or statement itself, or it may produce a Haskell value which can be marshalled to jmacro (i.e., is an instance of the ToJExpr class).