30章と31章については、各節のエッセンスをメモしていく形にします。
前説
- Interpreter : FOOプログラムを受け取って、HTMLを生成する。
- Compiler : FOOプログラム(CL埋め込みあり)を受け取って、CLのコードを生成する。
Designing a Domain-Specific Language
DSL設計は2段階。
- DSLの構文というか書きぶりを決める。
- それの処理系を実装する。
DSLの設計のポイントは、DSLによっていかに表現が「圧縮」されるかということ。
The FOO Language
- Lisp objectsを基礎におく。
- self-evaluating lisp objectsは、PRINC-TO-STRINGで変換したものをFOOでは出力する。このとき<>などのエスケープも行う。
- HTMLの要素名をキーワードシンボルとする。キーワードシンボルを第一要素とするリストを、HTMLの要素に対応させる。
- 属性は次の2つの表現が可能とする。
表現1 (:p :id "x" "Foo")
表現2 ((:p :id "x") "Foo")
Character Escaping
- 要素と属性でエスケープ対象文字が異なる。
- 対象文字を、*element-escape*, *attribute-escape*に格納する。
- *escape*に場所場所でどちらかを割り当てるなどの運用をする。
Indenting Printer
- indenting-printerというクラスに情報を格納してindentを制御する。
- ただし、indenting-printerのindentation slotに入っている値に対応してindentするというだけの機構。
- 文字列をindentして出力するための基本関数を定義。
(defun emit (ip string) ...)
(defun emit/no-newlines (ip string &key (start 0) end) ...)
(defun indent-if-necessary (ip) ...)
(defun emit-newline (ip) ...)
(defun emit-freshline (ip) ...)
HTML Processor Interface
- HTML Processorのインターフェイスは総称関数で定義する。
- これはInterpreterとCompilerの両方に対応するため。
- 総称関数は次の8つ。
(defgeneric raw-string (processor string &optional newlines-p))
(defgeneric newline (processor))
(defgeneric freshline (processor))
(defgeneric indent (processor))
(defgeneric unindent (processor))
(defgeneric toggle-indenting (processor))
(defgeneric embed-value (processor value))
(defgeneric embed-code (processor code))
The Pretty Printer Backend
- html-pretty-printerというクラスを導入する。これは、slotにindenting-printerとtab-widthをもつ。
- 前章の総称関数に対するメソッドの定義をする。そのとき、Indenting-printer節で定義した基本関数が使える。
- embed-valueとembed-codeとは、Compilerのみで使用する。Interpreterではerrorとなるようにする。
The Basic Evaluation Rule
- 評価としては、まずself-evaluatingならば、raw-string関数にわたす。
- そうでなければ、それはFOO言語のcons-sexp形式となる。
- process-cons-sexp-html関数を導入する。
- この関数は、HTMLタグ出力、その中身の出力、インデントの管理、改行の管理を担当する。
- これの振舞の観点から、HTML要素は3つに分類できる。
(defparameter *block-elements* '(:body :colgroup ...))
(defparameter *paragraph-elements* '(:area :base :blockquote ...))
(defparameter *inline-elements* '(:a :abbr ...)) - この他に2つの補足的分類がある。
(defparameter *empty-elements* '(:area :base :br ...))
(defparameter *preserve-whitespace-elements* '(:pre :script ...)) - この分類を利用して、process-cons-sexp-htmlを実装する。
- process関数を直に呼ぶのでは手間なので、emit-html関数を導入して省く。
- *html-ouput*自身をAPIとして公開したくはないので、with-html-ouputマクロを導入して隠蔽する。
What's Next?
特になし。
0 件のコメント:
コメントを投稿