2008年1月24日木曜日

Chapter 31 Practical: An HTML Generation Library, the Compiler

前説

FOO言語においては、InterpreterとくらべてCompilerが最適化しているのは、テキストをできるだけまとめて出力するようにすること。


The Compiler


  • The compilerのアーキテクチャ。
  • html-compilerクラス。このオブジェクトにbackendの総称関数へ成されたopsを集積させる。
  • backendの総称関数は、前項へのops書き込み機能を持つ。
  • opsを最適化する関数にわたし、最適化される。
  • 最適化されたops vectorをgenerate-code関数が受け取り、CLのコードを吐く。


  • compilerがhtml-compilerのときのprocessor interface(メソッド)は、html-compilerへのopsの集積処理とする。
  • 関数sexp->opsを定義する。これは、前項を順次S式に適用してopsのvectorを作成する。
  • 関数optimize-static-outputを導入する。これは前項のvectorについて、raw-stringを合成する。
  • 関数generate-codeを導入する。これはopsに対して逐次総称関数op->codeを適用するだけ。
  • 総称関数op->codeを定義する。これが、それぞれのopを対応するLisp codeに変換する。
  • op->codeの定義でポイントは2つ。embed-valueとembed-code。
  • embed-valueは、Lispの変数の埋め込みに対応する。これは(princ-to-string value)が本質である。
  • embed-codeは、Lispのコードの埋め込みに対応する。これは、入力のコードをそのまま使える。



FOO Special Operators


  • Special Operatorは、CL本体と同じように、言語の通常の評価ルールでは実現できないことを実現するためのものである。
  • まず、現在のembed-codeの実装(そのまま)では、(p: (random 10))などで、(random 10)の値はすてられ、出力は

    となる。値が欲しいときもある。
  • そのために、:print、:formatを導入する。
  • :printは、embe-codeで検知され、そのbodyをembed-valueに渡す実装とする。
  • :formatは、それの引数がself-evaluatingであれば、それをemit-htmlに渡せる(Interpreterで使える)。Compilerのときは、引数はどんなLisp expressionsでもよい。


  • Special Operatorの実装方法。
  • まず、関数processの第一分岐としてprocess-special-formを呼ぶようにする。
  • Special formは、'html-special-operator(plist)に格納する。名前とlambdaの組で格納。
  • 個々のSpecial formの定義はマクロdefine-html-special-operatorで簡略化する。
  • 関数process-special-formは、plistからlambdaを取得して、formに適用するだけ。
  • これによって、Special Operatorの拡張をモジュール化できている。



FOO Macros


  • Special Operatorの実装方法と類似。
  • 'html-macro plistにマクロ名と処理lambdaを登録する。
  • ただし、ユーザはそのlambdaを直接書くのではなく、そのlambdaを作るための関数generate-macro-with-attributesなど(define-html-macroから呼ばれる構造とする。
  • generate-macro...は、ユーザから受け取ったマクロ定義(args and body)を、DISTRUCTURING-BINDに渡して、argsの置換をおこなうようにする。
  • 関数processの第二分岐にexpand-macor-form関数を登録する。これがマクロ展開を実行する。



The Public API


  • あり? なぜここで急にXHTML? *xhtml*がnil or t。
  • マクロin-html-styleを定義。
  • マクロhtmlを導入。
  • マクロhtmlはそれ自身ネスト可能であるし、その中身は*pretty*の値によって振舞が違うので、コード分岐を含んでもいる。すなわち単純な実装だとネストによって指数関数的にコードが増大してしまう。
  • それはmacroletで回避可能。


The End of the Line

JavaScriptのS式表現をつくる元気はありません。。。

0 件のコメント: