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 件のコメント:
コメントを投稿