HTMLにLispを埋め込む

Common LispでWikiエンジンを作る過程で 、
HTMLにS式を埋め込みたいという願望がありました。

<html>
<head><title>test</title></head>
<body>
現在時刻は<?lisp
(let ((time
(multiple-value-list
(decode-universal-time
(get-universal-time)))))
(echo (third time) "時" (second time) "分"
(first time) "秒"))
?>です。
</body>
</html>

しかし、ページを読み込むたびにこんなのを解釈してたら、
動作が遅くなるよな…ということでためらっていたのですが、
どうしてもやりたくなったので、ページ表示時に毎回処理するのではなく、
初めて表示するとき(*)に普通の表示と組み込まれたLispの処理を行う
LAMBDA式(関数ではなくリスト!)を生成し、
それをコンパイルするという方針をとりました。
(*) もちろん、ファイルが更新されればコンパイルし直します。
上のテキストは次のようなLAMBDA式に変換されます。

(LAMBDA (#1=#:G1652 STREAM REQUEST LOGINED?)
(DECLARE (IGNORABLE STREAM REQUEST LOGINED?))
(MACROLET ((CHECK-LOGIN ()
'(UNLESS LOGINED? (SETF #2=#:G1651 :NOT-LOGIN)
(GO #3=#:G1650))))
(WITH-OPEN-FILE (#4=#:G1647 #1#
:EXTERNAL-FORMAT :UTF-8
:DIRECTION :INPUT)
(LET ((#2# T))
(TAGBODY
(SEND-TEMPLATE-LINES STREAM #4# 3 5)
(LET ((TIME
(MULTIPLE-VALUE-LIST
(DECODE-UNIVERSAL-TIME (GET-UNIVERSAL-TIME)))))
(ECHO (THIRD TIME) "時" (SECOND TIME) "分"
(FIRST TIME) "秒"))
(FILE-POSITION #4# 252)
(SEND-TEMPLATE-LINES STREAM #4# 3)
#3#)
#2#))))

これを (compile nil LAMBDA-SHIKI) という感じでコンパイルするだけ。
ね、簡単でしょ?
今回はサーバ自体をLispで作っているため、その関数を一度読み込ませたら、
ずっと持っておけばいいんですが、サーバを再起動すると関数が消えてしまうので、
LAMBDA式をファイルに書き出すということにしました。
そうすれば今後はLAMBDA式を書き出したファイルを読み込んで、
コンパイルするだけですみます(それでもコンパイルが必要なのが問題ですが…)。
上のLAMBDA式をみれば分かる通り、関数自体は表示すべきテキストを持っていません。
実行時に元のファイルから読み込ませるようにしています。
メモリに常駐させる以上、あまり大きな関数を作りたくないという考えからそうしました。
また、echoという見慣れないものを使っていますが、これはmacroletで定義してます。
ほかにもいろんなもののSyntax Sugarをmacroletで定義しています。
上のLAMBDA式のmacroletにはcheck-loginというものしかありませんが、
コンパイルする直前に(リスト操作で)いろいろと追加します。
(check-loginだけ先にあるのは変数を参照するためです)
ちなみに #n= と #n# を使っていますが、
これはファイルに書き出した後にリードしないといけないのに、
Uninterned symbolを使っていたことに、かなり最後の方になって気づき、
大慌てで *print-circle* を t にして出力するようにして誤摩化したためです(笑)

Leave a Reply