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 にして出力するようにして誤摩化したためです(笑)