「厳密分離の原理とテンプレートエンジン」の続きの報告です。
当初は、StringTemplate (http://www.stringtemplate.org/) のPython実装に手を入れて、構文を差し替える予定でした。が、手を入れるのが思いのほか手間がかかりそうなので、スクラッチで作る方向に変更。ただしそれでも、次の方針は維持します。
- StringTemplateの精神と原理を尊重し、それを受け継ぐ。
- StringTemplateのクローンとして使える。
- テンプレート構文解析系とテンプレート展開エンジンは分離する。
- 構文解析部には、パーザージェネレータANTLR(http://www.antlr.org/)を使う。
StringTemplateもANTLRもテレンス・パー(Terence Parr; http://www.cs.usfca.edu/~parrt/index.html)によるソフトウェアです。有り体に言えば、テレンス・パーの見識と技術に依拠しよう、ってことです。
テンプレート構文解析系とテンプレート展開エンジンを分離するために、中間形式を設定します。この中間形式への要求は:
- プログラミング言語中立であり、可搬性がある。
- 高速に実行できるように、十分に単純で低水準である。
- 人間の目で読めて、根性さえあれば手で書ける。
構文解析系(中間形式を出力)と展開エンジンが別なプログラミング言語で実装されていてもいいし、中間形式を人間がガンバッテ書いてもいいということです。構文解析系は、ANTLRを使えば比較的少ない労力で作成できるので、構文を何種類か準備したいところですが、当面はSmarty風のものでしょう。
コンテキスト=展開の環境=属性テーブルは、JSONデータで与えます。テンプレートテキスト t に対して、「tのコンテキスト=tへの入力」として適切なJSONデータの“型”は 決まっています。その型をTとすると、テンプレートテキストtは、t:T→string という関数とみなせます(ここでは、テンプレートエンジンは黒子になる)。別な関数 f:X→Y があると、Y = T、または Y⊆T (YはTの部分型*1)のとき、結合(合成) f;t は安全です。
Y⊆T であることは、Y→T の包含射(inclusion morphism)があるとみなせばいいので、「fの出力型 = tの入力型」のときだけ結合を作れればそれで十分です。この結合に際して、静的に型安全を保証するのは困難*2だし、そこまで必要とも思いませんが、実行時の型チェックなら可能です。「型」をJSONスキーマで定義できるものに限定すれば、関数=JSON処理出力系とテンプレートのあいだにJSONスキーマ・バリデータを挿入して、型の違反をとらまえることができます。
いったいなんでまた、テンプレートとそのコンテキストに型を導入するのかというと、ここがまさにプログラマとデザイナの契約界面だと思うからです。契約=仕様=型に適合したコンテキストデータを供給するのがプログラマの責務だし、与えられたコンテキストデータを使ってプレゼンテーションを構成するのがデザイナの仕事です。契約が型定義*3という形で存在し、それが実行メカニズムと結びついていれば、ミスや勘違いを低減し、テスト容易性を向上させる効果があるだろうと期待しているのです。