Velocityっぽいテンプレートエンジンをやる場合、仕様はどうする?
- 仕様を読んでみると、テンプレートエンジンにそんな機能が必要か疑問なものが散見されたり、逆にテンプレートエンジンに欲しい機能が抜けてる気がしたもので・・・
Velocityについて
- Velocity
- Cheetah
- Python用のテンプレートエンジン
- 記法はパッと見た感じVelocityに似てるけど、Velocity以上に色々できる。
- やり過ぎると、直接Pythonコード埋め込むのと変わらなくなる
- Airspeed
- Python用のテンプレートエンジン
- Cheetahより軽快でCGI運用でも問題なし
## Velocityと違って、Airspeedでこれは文法エラーみたい
#set($foo = 1 == 1)
## Velocityなら、先に「1 == 1」が評価され、結果が$fooに代入される
## よって $fooの値はtrue
Velocityメモ
## Velocityはリストのリテラル中に演算子を記述できない
## 以下はerrorとなる
#set($foo = [1 * 2, 2 * 2, 3 * 2])
## Velocityは空リストの中にスペースを記述できない
## 1.4では以下はerrorとなる(仕様なのか実装のバグかは不明)
#set($foo = [ ])
## 以下は問題ない
#set($foo = [])
## Velocityは行継続に対応してない
## 以下はerrorとなる
#set($foo = 3 +
4)
検討項目
- フィールドアクセスは、スロットアクセスに置き換える(参照、代入共に)
- defaultではslot-refで対応、オプションでgetterを選択すればいいか
- メソッドは?
- 変数のスコープはレキシカルスコープでは無い
- ループカウンタ(VelocityCount)はどうしようか?
- foreachをネストした際の挙動が微妙だし、ステの方向で
- foreachにもelse節を用意する
- 与えられたリストが空の場合、あるいはfalseを与えられた場合はelse節が実行
- Velocityのマクロは単なる置換(C言語に近い?)
- 名前空間は呼び出し元と同一?
- とりあえず微妙なので独立した名前空間を用意、マクロというよりサブルーチンになった(値は返さない)
- マクロは再帰呼び出し可能にする(ますます関数っぽくなった)
- マクロ内でマクロの定義を可能にするか?
- includeは、呼ばれるたびにファイルを開く
- パースして中間形式への変換時に展開する機能もいるかな
- includeと違って一回しか展開されず、対象に変数は指定できない
- リテラルの取捨選択は?
- 文字列は「'」シングルクォートで変数展開不可、「"」ダブルクォートで変数展開可能なものにする
- $fooが「ABC」の場合、"$foo/DEF"は「ABC/DEF」となる
- '$foo/DEF'は変数展開が行われないので、「$foo/DEF」のまま
- 数値は、引用符で囲まれてない数字で表現
- 真偽値はtrue, falseで表現
- nullを追加、「 $ls == null 」で$lsが空リストかどうか調べる
- リストはステ?
- 変数表示は接頭子「$」を(例 $foo)
- 変数名の末尾を明示化する場合は ${foo}
- Template ToolKitのパイプ構文フィルタの導入(smartyにもある)
- ${foo | html-escape}
- ${foo | string-trim | html-escape}
- includeにもフィルタの導入?
#include("incl.html" | $nl->br)
- Template ToolKitのフィルタディレクティブの導入
#filter ($html-escape | $nl->br)
範囲指定型のフィルタ
$id : $name : $content
#end
- parseを回避するliteralディレクティブの導入(smartyから拝借)
#literal
#set($foo = $bar)
$foo.param
#end
## literalからendまでは、変数展開やディレクティブの実行が行われることなく、
## そのままの文字列が出力される
文法を少し変更する
以下のディレクティブの記法は、velocityでは無効
#foreach($x in $list)
# if($x)
True
# else
False
# end
#end
なぜなら、「#」とディレクティブ名の間に空白が含まれるから
でも個人的には許容したい
というのも、「#」を行頭に持ってきて、
「#」とディレクティブ名の間にインデントを入れる記法が好みなので・・・
(でもその記法は一行一ディレクティブが前提か)
演算子の優先順位(弱い順)
- [ || ][ && ][ ==, !=, >, <, >=, <= ]
- 四則演算を取り入れるなら以下のようになる
- [ || ][ && ][ ==, !=, >, <, >=, <= ][ *, /, % ][ +, - ]
parse時に解決されるディレクティブを取り入れる?
- #literal
- #include-once
- 中間形式では文字列リテラルに変換される
- 引数はファイル名だが、変数は不可能で、文字列リテラルのみ可能
- #parse-once
- 中間形式では通常のコードとして解釈される
- 引数はファイル名だが、変数は不可能で、文字列リテラルのみ可能
その他
- include ディレクティブ実行しない、変数展開なし
- parse ディレクティブ実行する、変数展開あり
- literal
- filter
暫定版
heieiei.080815a.tar.gz
名前は適当にheieiei(ハイアイアイ)という名前にする
これは架空の島の名前が由来
memo.txt
こんな感じ
(use heieiei)
(template
(
(foo '(1 2 3 4 5))
(bar #t))
(call-with-input-file "example.tmpl" port->string))
example.tmplの中身はこんな感じで
<ul>
#foreach($x in $foo)
<li>$x</li>
#end
</ul>
#if($bar)
TRUE!!
#else
FALSE!!
#end
暫定版の実装メモ
- operator-sort
- リテラルと演算子で構成されたリストから、演算子の優先度にそった木を作成する
'(1 + 2 * 3 == 7 and true)
(and
(==
(+
1
(*
2
3))
7)
true)
#set($num = 1 . 2 . 3)
#set($str = "str1" . ":" . "str2")
#set($arr = [1,2,3] . [7,8,9])
$numは「123」、$strは「"str1:str2"」、$arrは「[1,2,3,7,8,9]」
リスト同士の場合はリストをappendしたリストを返すが、それ以外のものは文字列表現を結合して返す
- 手書きのパーサが非常に読みづらいものになってるので要リファクタリング
- ディレクティブごとに正規表現を用意してるのが馬鹿っぽい
- このてのパーサは最初にトークン切り出しをしてから、レクサに解釈させるのが普通なんだろうけど、こんなテキストテンプレートをトークンパーサにかけるのは抵抗があった、理由はよくわからないけど
TODO
- 行継続の導入
- Velocityではディレクティブ内の式を複数行に展開できない
仕様を拡張して展開できる用にしたい
- 多重代入の導入(対応済み)
- Perl,Pythonなどで一般的なリストから複数変数への多重代入を導入したい
これはsetとforeachが対象となる
Last modified : 2008/12/29 22:35:15 JST