メタテンプレート
MetaOCamlは翻訳しないといけないと思いつつ、寝てたら、夢で思いついてしまったので、もうちょっと詳しく考えてメモしておく。
C様データ定義言語はXMLの考え方を継承する。つまり、XSLTのような言語も考えることができるだろう。
また、HTML生成のテンプレート技術もメタプログラミングに使える。Visual Studioのウィーザードなどはテンプレート技術でソースを生成する。ということが思い出された。
てことで言語生成用のテンプレート、メタテンプレートとでもいうものを考えてみた。
C様データ定義言語上では、字句レベルではなく、構文木レベルで操作が可能である利点と欠点を持つだろう。
メタテンプレートの書き方案1
TMPL[ifelse] { if(TMPL[jyoken];) { TMPL[statements]; } TMPL[elseif] { else if(TMPL[jyoken];) { TMPL[statements]; } }; TMPL[else] { else { TMPL[statements]; } }; };
if文のつながりを出力するテンプレートを書いてみた。
うーん。見にくい。ボツかな。XSLTのように同じ言語体系で同じ言語を出力するようにすると分かりにくくなる問題を抱える、、、。
if( ) { } else if( ) { } else { }
のほうが見やすい。
<%ifelse{%> if(<%joken%>) { <%statements%> } <%elseif{%> else if(<%joken%>) { <%statements%> } <%elseif}%> <%else{%> else { <%statements%> } <%else}%> <%ifelse}%>
のほうが分かりやすい。ブロックは長くなるとわからなくなるから、始まりと終わりに名前を入れて、始まりと終わりを区別するものをつける。
aspの生成には向かないだろうけど、強いに違いない。
てことで、C様データ定義言語でテンプレート案は、あっけなくボツ?
もうちょっといい方法を考えてみる。
TMPL.ifelse[ if(TMPL.jyoken;) { TMPL.statements; } TMPL.elseif[ else if(TMPL.jyoken;) { TMPL.statements; } ](elseif); TMPL.else[ else { TMPL.statements; } ](else); ](ifelse);
大体のブロックが{}なので、テンプレートは[]を使うと少しはマシかな。
オブジェクト指向というか、名前空間ぽくしてみたり。()にコメント入れてみたり。わりかりやすい?
<%ifelse[%> if(<%joken%>) { <%statements%> } <%elseif[%> else if(<%joken%>) { <%statements%> } <%elseif[%> <%else[%> else { <%statements%> } <%else]%> <%ifelse]%>
と比較してどうか?C様データ定義案のほうがすっきりして見える。
なんでか?っていうと、%がごちゃごちゃして見えるからだ。
#がごちゃごちゃして見えるのと一緒だ。aspの出力にも弱い。
パーサは1つでよい点も上のほうがよい。
if( ) { } else if( ) { } else { }
じゃあ、xml表現。ただし、<の後ろが空白ならxmlとしてパースしない。
って条件付にするとか。<でエスケープで、&は&か?とか問題があるけど。
XML出力プログラムの生成を苦手とする。XMLだからね。
同じ表記法に似たものを同じ表記でテンプレート出力しようとすると見にくいって点がどうしてもでて来てしまう。
同じ表記法の中で、できるだけ他の表記と異なる方法をとるのが良いと考えられるんじゃないかなぁと。てことで、ちょっと考えた結論では、
TMPL.ifelse[ if(TMPL.jyoken;) { TMPL.statements; } TMPL.elseif[ else if(TMPL.jyoken;) { TMPL.statements; } ](elseif); TMPL.else[ else { TMPL.statements; } ](else); ](ifelse);
って書き方がいい気がする。
さて、こいつを操作する方法を提供しないといけない。
C様データ定義言語のツリー操作で直接操作してもよいけど、ライブラリを提供すべきだろう。ようは、HTML吐き出しのテンプレート出力プログラムと同じような物をつくったればよい。てことで、意味があるかどうかはしらないけど、ストリーミング出力まで出来てしまうことになる。意味あるのか?まったくもって謎だけど。考え中に、プログラムソースを他のコンピュータに送って計算させるとかやりたいときにはいいのかもしれない。
C様データ定義言語による、ブラウザを作った場合はうれしいだろう。
てことで、操作ライブラリ仕様は、
http://www.wikiroom.com/sakurai/?dtmpl%2Ftmpl
に近いものになる。
TMPL.ifelse[ if(TMPL.jyoken;) { TMPL.statements; } TMPL.elseif[ else if(TMPL.jyoken;) { TMPL.statements; } ](elseif); TMPL.else[ else { TMPL.statements; } ](else); ](ifelse); TmplDom tIfElse = TMPL.ifelse.create(); tIfElse.setValue(tree(jyoken),tree(i == 1)); tIfElse.setValue(tree(statements),tree(printf("test\n");)); for(int i=2;i<4;i++) { TmplDom tElseIf = tmpl.addBlock(tree(elseif)); tElseIf.setValue(tree(jyoken),tree.readTree("i == " ~ i)); tElseIf.setValue(tree(statements),tree.readTree("printf(\"" ~ i ~ "\\n\")"))); } TmplDom tElse = tIfElse.addBlock(tree(else)); tElse.setValue(tree(statements),tree(printf("else\n"))); printf("%.*s\n",tIfElse.toString());
なんか、下のプログラムがD言語なんだけどまぁいいや。生成プログラム自体D言語だし。
で、
if (i == 1) { printf("test\n"); } else if (i == 2) { printf("2\n"); } else if (i == 3) { printf("3\n"); } else { printf("else\n"); }
が出力されると言うかんじだろう。TmplDomクラスで操作できて、setValueで値を設定、addBlockでブロック追加ができる。TMPLのデータ参照方法がコレでいいのか謎。
ifelseテンプレートはifelseのプログラム生成を作る上では1つあればよいわけで、有用かなぁと思うわけだ。tree構文で、ツリーを操作できると。LISPでいうlistだ。
TmplDom tIfElse = new TmplDom(tree( TMPL.ifelse[ if(TMPL.jyoken;) { TMPL.statements; } TMPL.elseif[ else if(TMPL.jyoken;) { TMPL.statements; } ](elseif); TMPL.else[ else { TMPL.statements; } ](else); ](ifelse); ));
て感じがいいかもなぁ。
追記:あ、for(TMPL.a1;;TMPL.a2;;TMPL.a3;)て書くと破綻しそう。と気が付いてしまった。うむむ。;はなしがいいかな?