cl-interpol and parenscript

Cl-interpol adds Perl style interpolated strings to Common Lisp. For example:

#?"The result is ${(let ((y 2)) (+ x y))}"
"The result is 42"

Cl-interpol works by defining a reader macro, i.e. #?”…”. For personal reasons I don’t like reader macros so I wrote a quick macro to avoid them.

(defun interp% (str)
  "Avoid the need to use a unique read table."
  (assert (stringp str))
  (with-input-from-string (s str)
    (cl-interpol::interpol-reader s #\? nil)))

(defmacro interpolate (str)
  (interp% str))

Which lets you write:

 (interpolate "{This string appeared in package: ${(package-name *package*)}.}")

Like any self respecting Lisp code cl-interpol avoids interpreting the string at runtime, instead it converts the interpolated string into code. For example that last example expands into:

(with-output-to-string (#:g13131)
  (write-string "This string appeared in package: " #:g13131)
  (princ (progn (package-name *package*)) #:g13131)
  (write-string "." #:g13131))

I started using cl-interpol because somebody suggested it as yet another way to generate HTML. The Lisp community as a few templating languages for this kind of thing.  Who doesn’t?  The more popular of these have mimics in Parenscript.

Parenscript, you will recall, is a thin gloss over Javascript that enables you to write your Javascript using s-expressions which are then converted into Javascript before delivery to the browser.

So I wanted that for cl-interpol as well. So I wrote something that translates the expanded code into parenscript.

As in the example above the output of cl-interpol’s expansion is always a with-output-to-string form, so my hack consists of a parenscript macro for with-output-to-string which then walks the enclosing form converting it into parenscript and then into javascript. For example:

This parenscript:

(let ((x 40)) (interpolate "{How about ${(+ x 2)}.}")))

becomes this javascript:

(function () {
    var x = 40;
    return ['How about ', String(x + 2), '.'].join('');

Cl-interpol has lots of features, and I certainly do not handle things it can do. I’ve only covered cases as I need them. But I’ve found it useful.

Leave a Reply

Your email address will not be published. Required fields are marked *