こんにちは、chibaです。
今回もネタがないのでEmacsネタです。
Dylanのマクロについての文献:
http://people.csail.mit.edu/jrb/Projects/dexprs.pdf
を読んでいて、XMLや、LISPは、Skeleton Syntax Tree Representationsに分類されるというのを読んで、そうか、HTMLも簡単にマクロ書けたりするのかもと思ったのでEmacs Lispでちょっと試してみました。
(defun split-id-or-class (string) (let ((elts (split-string string "[\\.#]"))) (if (cdr elts) elts string))) (defmacro defhtmltag (tag) (let* ((tag-str (symbol-name tag)) (tags (split-string tag-str "[\\.#]")) (tag-name (car tags)) (attr (cadr tags))) `(defmacro ,tag (&rest body) `(list ,(concat "<" ,tag-name (apply #'concat (cond ((find ?. ,tag-str) (list " class=\"" ,attr "\"")) ((find ?# ,tag-str) (list " id=\"" ,attr "\"")) ('T (list "")))) ">") ,@body ,(concat "</" ,tag-name ">"))))) (defun flatten (lis) (cond ((atom lis) lis) ((listp (car lis)) (append (flatten (car lis)) (flatten (cdr lis)))) (t (append (list (car lis)) (flatten (cdr lis)))))) (defmacro with-html-output-to-string (&rest body) `(reduce (lambda (x y) (format "%s%s" x y)) (flatten (list ,@body))))
使い方としては、
(defhtmltag li.foo)
のようにすると、
(list "<li>" "こんにちは" "</li>")
のようなものにマクロが展開されるので、リストの入れ子を平坦にして一つの文字列に繋げれば完成です。
ちょっと込み入ったところだと
(defhtmltag table) (defhtmltag tbody) (defhtmltag td) (defhtmltag tr) (defun list-to-table (list) (table (tbody (mapcar (lambda (x) (tr (mapcar (lambda (y) (td y)) x))) list)))) (insert (with-html-output-to-string (list-to-table '((foo bar baz quux) (1 2 3 4) (z z z z))))) ;=> <li class="foo"><li class="foo"><li class="foo"><li class="foo">foo</li><li class="foo">bar</li><li class="foo">baz</li><li class="foo">quux</li></li><li class="foo"><li class="foo">1</li><li class="foo">2</li><li class="foo">3</li><li class="foo">4</li></li><li class="foo"><li class="foo">z</li><li class="foo">z</li><li class="foo">z</li><li class="foo">z</li></li></li></li>
ということもできます。
ちなみに、マクロ展開でHTML書くって新しいかも!と思いましたが、別にマクロにしなくても関数でも書けることに今気付きました…
とりあえず、もし、HTMLにマクロがあったとしたらLISPと似た感じになるのかなあという印象は持ちました。
■