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.