Check-in [203e4cb208]
Not logged in
Overview
SHA1 Hash:203e4cb208bbc9d4da4052d12d8656c368af24c0
Date: 2010-11-27 20:46:26
User: kinaba
Comment:fixed automatic memoization bug (whole part of the contexts are now used as the memo key)
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified doc/_common.html from [b9095bf676f7ac7c] to [99ddb75ae65a2432].

22 22 23 23 The list of modules globaly used inside Polemy.<br><br> 24 24 25 25 </td></tr> 26 26 <tr><td id="docfooter"> 27 27 Page was generated with 28 28 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 29 - on Fri Nov 26 16:41:43 2010 29 + on Sat Nov 27 01:17:56 2010 30 30 31 31 </td></tr> 32 32 </table> 33 33 </div> 34 34 <script> 35 35 explorer.packageExplorer.addModule("index"); 36 36 explorer.packageExplorer.addModule("main");

Modified doc/ast.html from [7559b28d1aa75ece] to [30cfc60d3ceb137f].

590 590 <script>explorer.outline.decSymbolLevel();</script> 591 591 592 592 593 593 </td></tr> 594 594 <tr><td id="docfooter"> 595 595 Page was generated with 596 596 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 597 - on Fri Nov 26 16:41:44 2010 597 + on Sat Nov 27 01:17:56 2010 598 598 599 599 </td></tr> 600 600 </table> 601 601 </div> 602 602 <script> 603 603 explorer.packageExplorer.addModule("index"); 604 604 explorer.packageExplorer.addModule("main");

Modified doc/eval.html from [2f7c4dc496477f14] to [8d466c06bd23cd95].

36 36 37 37 38 38 <dd>Objects for maitaining global environment and evaluation of expression on it<br><br> 39 39 40 40 41 41 <script>explorer.outline.incSymbolLevel();</script> 42 42 <dl> 43 -<script>explorer.outline.writeEnabled = true;</script> 44 -<dt><span class="decl">this(); 45 -</span></dt> 46 -<script>explorer.outline.writeEnabled = false;</script> 47 - 48 - 49 -<dd>Initialize evaluator with empty context<br><br> 50 - 51 -</dd> 52 - 53 43 <script>explorer.outline.writeEnabled = true;</script> 54 44 <dt><span class="decl">Value 55 45 <span class="currsymbol">evalAST</span> 56 46 <script>explorer.outline.addDecl('evalAST');</script> 57 47 58 48 (AST <span class="funcparam">e</span>); 59 49 </span></dt> ................................................................................ 101 91 </span></dt> 102 92 <script>explorer.outline.writeEnabled = false;</script> 103 93 104 94 105 95 <dd>Get the global context<br><br> 106 96 107 97 </dd> 98 + 99 +<script>explorer.outline.writeEnabled = true;</script> 100 +<dt><span class="decl">this(); 101 +</span></dt> 102 +<script>explorer.outline.writeEnabled = false;</script> 103 + 104 + 105 +<dd>Initialize evaluator with empty context<br><br> 106 + 107 +</dd> 108 108 109 109 <script>explorer.outline.writeEnabled = true;</script> 110 110 <dt><span class="decl">void 111 111 <span class="currsymbol">addPrimitive</span> 112 112 <script>explorer.outline.addDecl('addPrimitive');</script> 113 113 114 114 (R, T...)(string <span class="funcparam">name</span>, Layer <span class="funcparam">defLay</span>, R delegate(T) <span class="funcparam">dg</span>); ................................................................................ 128 128 <script>explorer.outline.decSymbolLevel();</script> 129 129 130 130 131 131 </td></tr> 132 132 <tr><td id="docfooter"> 133 133 Page was generated with 134 134 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 135 - on Fri Nov 26 16:41:45 2010 135 + on Sat Nov 27 01:17:57 2010 136 136 137 137 </td></tr> 138 138 </table> 139 139 </div> 140 140 <script> 141 141 explorer.packageExplorer.addModule("index"); 142 142 explorer.packageExplorer.addModule("main");

Modified doc/failure.html from [73b33ccfe21436b6] to [1a82c4c6591961ce].

178 178 <script>explorer.outline.decSymbolLevel();</script> 179 179 180 180 181 181 </td></tr> 182 182 <tr><td id="docfooter"> 183 183 Page was generated with 184 184 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 185 - on Fri Nov 26 16:41:45 2010 185 + on Sat Nov 27 01:17:58 2010 186 186 187 187 </td></tr> 188 188 </table> 189 189 </div> 190 190 <script> 191 191 explorer.packageExplorer.addModule("index"); 192 192 explorer.packageExplorer.addModule("main");

Modified doc/fresh.html from [9043a131c52ae01a] to [dd1d4442ef129d46].

46 46 <script>explorer.outline.decSymbolLevel();</script> 47 47 48 48 49 49 </td></tr> 50 50 <tr><td id="docfooter"> 51 51 Page was generated with 52 52 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 53 - on Fri Nov 26 16:41:46 2010 53 + on Sat Nov 27 01:17:58 2010 54 54 55 55 </td></tr> 56 56 </table> 57 57 </div> 58 58 <script> 59 59 explorer.packageExplorer.addModule("index"); 60 60 explorer.packageExplorer.addModule("main");

Modified doc/index.html from [dc242393e80db0b7] to [a076bfb1003e4c62].

16 16 17 17 <b>Authors:</b><br> 18 18 k.inaba<br><br> 19 19 <b>License:</b><br> 20 20 NYSL 0.9982 (http://www.kmonos.net/nysl/)<br><br> 21 21 22 22 <p> 23 -このファイルは、言語仕様などの簡単な説明です。 23 +左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 24 24 </p> 25 25 <p> 26 -あとついでに、左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 26 +このファイルは、言語仕様などの、やや辞書的な説明です。<br /> 27 +もっとざっくりとした、言語デザインの方向性の魂的なものについては、 28 +「メタプログラミングの会」の発表スライドをご覧下さい。 29 +</p> 30 +<p> 31 +あと、 やたらとマクロの章が長くなっていますが、 この部分は、 32 +レイヤ機能を入れたら自動的にすごく自然にマクロが入るなーと思って、 33 +おまけで実装してみた程度のものです。 34 +あんまり重要ではないので、適当にスルーして下さいませ。 35 +単に、適当に入れたら適当で微妙な部分が多く残ってしまったので注意書きが増えているだけで…。 27 36 </p> 28 37 29 38 30 39 <script>explorer.outline.incSymbolLevel();</script> 31 40 <dl> 32 41 <script>explorer.outline.writeEnabled = true;</script> 33 42 <dt><span class="decl"> ................................................................................ 236 245 </pre> 237 246 <p> 238 247 let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします 239 248 (再帰関数の定義が"うまく"いっているのはこの上書きのためです)。 240 249 なんでこんなことになっているかというと、 241 250 後で説明する「レイヤ」を使ったときに 242 251 <tt>let foo = ... in @lay foo = ... in ...</tt> 243 -で他レイヤに重ね書きするためであります。 252 +で他レイヤに重ね書きするため、のつもりです。詳しくは後で。 244 253 </p> 245 254 </dd> 246 255 </dl> 247 256 <script>explorer.outline.decSymbolLevel();</script> 248 257 249 258 250 259 </dd> ................................................................................ 288 297 以下のデータ型があります。 289 298 </p> 290 299 <ul> 291 300 <li>整数: <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666666789</tt>, ...</li> 292 301 <li>文字列: <tt>"hello, world!"</tt>, ...</li> 293 302 <li>関数: <tt>fun(x){x+1}</tt></li> 294 303 <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li> 295 - <li>未定義値: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li> 304 + <li>ボトム: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li> 296 305 </ul> 297 306 <p> 298 307 関数はいわゆる「クロージャ」です。静的スコープで外側の環境にアクセスできます。 299 308 テーブルはいわゆるプロトタイプチェーンを持っていて、 300 309 自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、 301 310 フィールドの書き換えがないので、これは特に意味ないかもしれない…。 302 311 </p> ................................................................................ 556 565 </pre> 557 566 <p> 558 567 動きとしてはこうです。 559 568 </p> 560 569 <ol> 561 570 <li>関数呼び出し時(とトップレベル環境の実行開始時)に、 562 571 まず、<code>@macro</code> レイヤでコードを実行。</li> 563 -<li>返ってきた構文木を、<code>@value</code> レイヤ、 564 - またはその関数を呼び出したときのレイヤで実行。</li> 572 +<li>返ってきた構文木を、その関数を呼び出したときのレイヤで実行。</li> 565 573 </ol> 566 574 <p> 567 575 <code>@macro</code> レイヤも所詮ただのレイヤですので、 568 576 上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、 569 577 構文木の生成をいじることが可能です。まさにマクロ。 570 578 </p> 571 579 ................................................................................ 655 663 )}; 656 664 print( reverseArgs(1-2) ); <font color=green># 2-1 == 1</font> 657 665 </pre> 658 666 <p> 659 667 <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。 660 668 <tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、 661 669 それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。 662 -要は、<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 663 -<tt>@value(...)</tt> は「逆クオート (unquote)」に近い働きをします。 670 +<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 671 +<tt>@value(...)</tt> は「逆クオート (unquote)」にちょっと近いかもしれません。 664 672 </p> 665 673 <p> 666 674 <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、 667 675 一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、 668 676 さらに色々面白いことが可能です。 669 677 </p> 670 678 </dd> ................................................................................ 696 704 配列メンバは cons リストになって入ってきます。 697 705 自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。 698 706 </p> 699 707 </dd> 700 708 701 709 <script>explorer.outline.writeEnabled = true;</script> 702 710 <dt><span class="decl"> 703 -<span class="currsymbol">微妙なところ</span> 704 -<script>explorer.outline.addDecl('微妙なところ');</script> 711 +<span class="currsymbol">微妙なところ1</span> 712 +<script>explorer.outline.addDecl('微妙なところ1');</script> 705 713 706 714 </span></dt> 707 715 <script>explorer.outline.writeEnabled = false;</script> 708 716 709 717 <dd><p> 710 -ここまで、<tt>@macro</tt> が本当にただの1レイヤであるかのように説明してきましたが、 711 -実はちょっと幾つかのトリックが潜んでいます。 718 +ここまで、<tt>@macro</tt> が本当にただの1レイヤと説明してきましたが、 719 +実はちょっとトリックが潜んでいます。 712 720 </p> 713 721 <pre> 714 722 &gt;&gt; @macro twice(x) {x; x} in twice(<b>@value</b>(print("Hello"))) 715 723 Hello 716 724 Hello 717 725 Hello 718 726 </pre> 719 727 <p> 720 728 先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello 721 -が2回 print されるようになります。 729 +が2回 print されるようになります。これは本来はおかしな話で、<tt>print("Hello")</tt> 730 +は <tt>@value</tt> レイヤで実行されて値に落ちるはずなので、1回しか print されないはず。 731 +</p> 732 +<p> 733 +実は、Polemy の中では、<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> 734 +レイヤという二つの異なるマクロ用レイヤが動いています。 735 +</p> 736 +<ul> 737 + <li><tt>(rawmacro)</tt> も <tt>@macro</tt> も、コードを動かすとその構文木を返す意味論。</li> 738 + <li>ただし、<tt>(rawmacro)</tt> も <tt>@macro</tt> も、 739 + <tt>@macro</tt> レイヤに値のセットされた変数をみつけたときは、 740 + その変数という構文木を作るのではなく、変数の内容を展開。</li> 741 + <li>また <tt>@macro</tt> は、 742 + レイヤ指定式を見ると実行レイヤを切り替て、構文木生成モードをやめてしまう。</li> 743 + <li><tt>(rawmacro)</tt> は、 744 + レイヤ指定式を見ても実行レイヤを切り替えないで構文木にする。</li> 745 +</ul> 746 +<p> 747 +ユーザーから直接 <tt>(rawmacro)</tt> は呼べませんが、 748 +「関数やトップレベル実行開始前のマクロ処理は <tt>(rawmacro)</tt> で実行開始」 749 +「<tt>@macro</tt> レイヤ以外で呼び出した関数の仮引数に <tt>@macro</tt> がついていたら、 750 +その実引数は <tt>(rawmacro)</tt> で実行」 751 +という2つのタイミングで <tt>(rawmacro)</tt> が動き出します。 752 +<tt>(rawmacro)</tt> が <tt>@macro</tt> レイヤから変数を見つけてマクロし始める時に、 753 +そこで <tt>@macro</tt> に動作が移ります。 754 +</p> 755 +<p> 756 +こうなっているのは、全部がレイヤ指定式に反応する <tt>@macro</tt> の動作だと、 757 +レイヤを使ったプログラムが全て <tt>@value</tt> 実行時ではなく、 758 +マクロ展開の時点で動き始めてしまって、おかしなことになるためです。 759 +色々考えた結果、とりあえずこの中途半端な混合が具合がよいのではないかということになりました。 760 +</p> 761 +</dd> 762 + 763 +<script>explorer.outline.writeEnabled = true;</script> 764 +<dt><span class="decl"> 765 +<span class="currsymbol">微妙なところ2</span> 766 +<script>explorer.outline.addDecl('微妙なところ2');</script> 767 + 768 +</span></dt> 769 +<script>explorer.outline.writeEnabled = false;</script> 770 + 771 + <dd><p> 772 +「関数実行開始時に、まずマクロレイヤを実行」と書きましたが、この時、関数内関数まで辿りにいくので、 773 +何重にもネストした関数を使っていると、内側の関数は、何重にもマクロ展開が走ってしまいます。 774 +これはなにかおかしい気がしますね。Scheme などはどうなっているのか調べないと…。 775 +</p> 776 +</dd> 777 + 778 +<script>explorer.outline.writeEnabled = true;</script> 779 +<dt><span class="decl"> 780 +<span class="currsymbol">微妙なところ3</span> 781 +<script>explorer.outline.addDecl('微妙なところ3');</script> 782 + 783 +</span></dt> 784 +<script>explorer.outline.writeEnabled = false;</script> 785 + 786 + <dd><p> 787 +これはエラーになります。 722 788 </p> 723 789 <pre> 724 -<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> レイヤという二つが協調して動作しています。 725 - (rawmacro) レイヤの話 726 - 727 - [[limitations]] 728 - 729 - This @macro layer is a very primitive one, and not a perfect macro language. 730 - Two major limitations are seen in the following "it" example. 731 - 732 - &gt;&gt; @macro LetItBe(x, y) { let it = x in y }; 733 - 734 - The variable name is not hygenic, and so without any effort, the syntax tree "y" 735 - can access the outer variable "it". 736 - 737 - &gt;&gt; def foo() { LetItBe( 1+2+3, it*it ) } 738 - &gt;&gt; foo() 739 - 36 740 - 741 - Of course, this is not just a limitation; it can sometimes allow us to write 742 - many interesting macros. 743 - 744 - The other problem is that the macro expansion is only done at function startup. 745 - So 746 - 747 - &gt;&gt; LetItBe( 1+2+3, it*it ) 748 - ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value 749 - 750 - you cannot directly use the macro in the same scope as the definition. 751 - You need to wrap it up in a function (like the foo() in the above example). 790 + &gt;&gt; let _ = (@macro twice(x) {x;x} in twice(print("Hello"))) 791 + polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\value.d(109): 792 + [<REPL>:2:35] 'twice' is not set in @value layer 752 793 </pre> 794 +<p> 795 +どういうことかというと、<tt>@macro</tt> で定義したマクロはいつから使えるようになるかという話で、 796 +この <tt>@macro twice(x) {x;x} in ...</tt> の部分は <tt>@value</tt> レイヤの式なので、 797 +まずこの式全体のマクロ展開が終わったあとにしか実行されないのです。<tt>twice</tt> 798 +がマクロと見なされはじめるのは、<tt>@macro</tt> 実行が終わった後。 799 +なので、 800 +例えば <tt>twice(print("Hello"))</tt> の部分を無名関数にラップしてやれば、 801 +マクロ展開を遅らせられて、 ちゃんと実行ができます。 802 +</p> 803 +<p> 804 +これだと余りにも不便なので、関数のトップレベルの変数宣言式の列についてだけは、 805 +<tt>@macro</tt> と <tt>@value</tt> の評価を交互にインターリーブするようにしました。 806 +「関数やREPLのトップレベルの最初に宣言したマクロだけは、その関数内で即座に使える」わけです。 807 +これも Scheme の let-syntax などなどの動きを調べて勉強しないと…。 808 +</p> 753 809 </dd> 754 810 </dl> 755 811 <script>explorer.outline.decSymbolLevel();</script> 756 812 757 813 758 814 </dd> 759 815 ................................................................................ 877 933 <script>explorer.outline.decSymbolLevel();</script> 878 934 879 935 880 936 </td></tr> 881 937 <tr><td id="docfooter"> 882 938 Page was generated with 883 939 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 884 - on Fri Nov 26 16:41:52 2010 940 + on Sat Nov 27 01:54:49 2010 885 941 886 942 </td></tr> 887 943 </table> 888 944 </div> 889 945 <script> 890 946 explorer.packageExplorer.addModule("index"); 891 947 explorer.packageExplorer.addModule("main");

Modified doc/layer.html from [a4f78e6e3d8c715a] to [136da3cf5e90765a].

163 163 <script>explorer.outline.decSymbolLevel();</script> 164 164 165 165 166 166 </td></tr> 167 167 <tr><td id="docfooter"> 168 168 Page was generated with 169 169 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 170 - on Fri Nov 26 16:41:46 2010 170 + on Sat Nov 27 01:17:58 2010 171 171 172 172 </td></tr> 173 173 </table> 174 174 </div> 175 175 <script> 176 176 explorer.packageExplorer.addModule("index"); 177 177 explorer.packageExplorer.addModule("main");

Modified doc/lex.html from [b039dcaea4552a8f] to [4b49ee7344141eea].

307 307 <script>explorer.outline.decSymbolLevel();</script> 308 308 309 309 310 310 </td></tr> 311 311 <tr><td id="docfooter"> 312 312 Page was generated with 313 313 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 314 - on Fri Nov 26 16:41:47 2010 314 + on Sat Nov 27 01:17:59 2010 315 315 316 316 </td></tr> 317 317 </table> 318 318 </div> 319 319 <script> 320 320 explorer.packageExplorer.addModule("index"); 321 321 explorer.packageExplorer.addModule("main");

Modified doc/main.html from [d5dd76810e38b7f6] to [0482b340bcdb09a1].

62 62 <script>explorer.outline.decSymbolLevel();</script> 63 63 64 64 65 65 </td></tr> 66 66 <tr><td id="docfooter"> 67 67 Page was generated with 68 68 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 69 - on Fri Nov 26 16:41:42 2010 69 + on Sat Nov 27 01:17:56 2010 70 70 71 71 </td></tr> 72 72 </table> 73 73 </div> 74 74 <script> 75 75 explorer.packageExplorer.addModule("index"); 76 76 explorer.packageExplorer.addModule("main");

Modified doc/parse.html from [e3b4b64f19f93798] to [b7809106bd8bbf5f].

56 56 <script>explorer.outline.decSymbolLevel();</script> 57 57 58 58 59 59 </td></tr> 60 60 <tr><td id="docfooter"> 61 61 Page was generated with 62 62 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 63 - on Fri Nov 26 16:41:48 2010 63 + on Sat Nov 27 01:17:59 2010 64 64 65 65 </td></tr> 66 66 </table> 67 67 </div> 68 68 <script> 69 69 explorer.packageExplorer.addModule("index"); 70 70 explorer.packageExplorer.addModule("main");

Modified doc/repl.html from [f38bae3012b6b256] to [06b9b45e10860394].

156 156 <script>explorer.outline.decSymbolLevel();</script> 157 157 158 158 159 159 </td></tr> 160 160 <tr><td id="docfooter"> 161 161 Page was generated with 162 162 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 163 - on Fri Nov 26 16:41:48 2010 163 + on Sat Nov 27 01:18:00 2010 164 164 165 165 </td></tr> 166 166 </table> 167 167 </div> 168 168 <script> 169 169 explorer.packageExplorer.addModule("index"); 170 170 explorer.packageExplorer.addModule("main");

Modified doc/runtime.html from [fb971a54db14120e] to [05c59f5e4897aa6d].

42 42 <script>explorer.outline.decSymbolLevel();</script> 43 43 44 44 45 45 </td></tr> 46 46 <tr><td id="docfooter"> 47 47 Page was generated with 48 48 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 49 - on Fri Nov 26 16:41:49 2010 49 + on Sat Nov 27 01:18:00 2010 50 50 51 51 </td></tr> 52 52 </table> 53 53 </div> 54 54 <script> 55 55 explorer.packageExplorer.addModule("index"); 56 56 explorer.packageExplorer.addModule("main");

Modified doc/test.html from [65937464daabbe41] to [2826fbbbd41fd9fd].

143 143 <script>explorer.outline.decSymbolLevel();</script> 144 144 145 145 146 146 </td></tr> 147 147 <tr><td id="docfooter"> 148 148 Page was generated with 149 149 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 150 - on Fri Nov 26 16:41:51 2010 150 + on Sat Nov 27 01:18:02 2010 151 151 152 152 </td></tr> 153 153 </table> 154 154 </div> 155 155 <script> 156 156 explorer.packageExplorer.addModule("index"); 157 157 explorer.packageExplorer.addModule("main");

Modified doc/tricks.html from [66f1242be8634b07] to [3a211e8310f22d0a].

246 246 <script>explorer.outline.decSymbolLevel();</script> 247 247 248 248 249 249 </td></tr> 250 250 <tr><td id="docfooter"> 251 251 Page was generated with 252 252 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 253 - on Fri Nov 26 16:41:52 2010 253 + on Sat Nov 27 01:18:02 2010 254 254 255 255 </td></tr> 256 256 </table> 257 257 </div> 258 258 <script> 259 259 explorer.packageExplorer.addModule("index"); 260 260 explorer.packageExplorer.addModule("main");

Modified doc/value.html from [4d6f8832c63e974c] to [56bfccf06cb302b1].

63 63 64 64 65 65 <dd><br><br> 66 66 </dd> 67 67 68 68 <script>explorer.outline.writeEnabled = true;</script> 69 69 <dt><span class="decl">class 70 -<span class="currsymbol">UndefinedValue</span> 71 -<script>explorer.outline.addDecl('UndefinedValue');</script> 70 +<span class="currsymbol">BottomValue</span> 71 +<script>explorer.outline.addDecl('BottomValue');</script> 72 72 73 73 : polemy.value.Value; 74 74 </span></dt> 75 75 <script>explorer.outline.writeEnabled = false;</script> 76 76 77 77 78 78 <dd><br><br> ................................................................................ 259 259 <script>explorer.outline.decSymbolLevel();</script> 260 260 261 261 262 262 </td></tr> 263 263 <tr><td id="docfooter"> 264 264 Page was generated with 265 265 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 266 - on Fri Nov 26 16:41:50 2010 266 + on Sat Nov 27 01:18:01 2010 267 267 268 268 </td></tr> 269 269 </table> 270 270 </div> 271 271 <script> 272 272 explorer.packageExplorer.addModule("index"); 273 273 explorer.packageExplorer.addModule("main");

Modified doc/valueconv.html from [e08638d4763e1185] to [d3b97793d6c2afdf].

75 75 (T)(T <span class="funcparam">e</span>, Value delegate(AST) <span class="funcparam">rec</span>); 76 76 </span></dt> 77 77 <script>explorer.outline.writeEnabled = false;</script> 78 78 79 79 80 80 <dd>Convert AST to Table so that it can be used in Polemy<br><br> 81 81 82 +</dd> 83 + 84 +<script>explorer.outline.writeEnabled = true;</script> 85 +<dt><span class="decl">Value 86 +<span class="currsymbol">ast2table</span> 87 +<script>explorer.outline.addDecl('ast2table');</script> 88 + 89 +(T)(T <span class="funcparam">e</span>); 90 +</span></dt> 91 +<script>explorer.outline.writeEnabled = false;</script> 92 + 93 + 94 +<dd>No hook version<br><br> 95 + 82 96 </dd> 83 97 </dl> 84 98 <script>explorer.outline.decSymbolLevel();</script> 85 99 86 100 87 101 </td></tr> 88 102 <tr><td id="docfooter"> 89 103 Page was generated with 90 104 <img src="candydoc/img/candydoc.gif" style="vertical-align:middle; position:relative; top:-1px"> 91 - on Fri Nov 26 16:41:51 2010 105 + on Sat Nov 27 01:18:01 2010 92 106 93 107 </td></tr> 94 108 </table> 95 109 </div> 96 110 <script> 97 111 explorer.packageExplorer.addModule("index"); 98 112 explorer.packageExplorer.addModule("main");

Modified index.dd from [a7325259b4f09952] to [d2cf6de49dcafd42].

1 1 Ddoc 2 2 $(DDOC_AUTHORS k.inaba) 3 3 $(DDOC_LICENSE NYSL 0.9982 (http://www.kmonos.net/nysl/)) 4 4 5 5 <p> 6 -このファイルは、言語仕様などの簡単な説明です。 6 +左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 7 7 </p> 8 8 <p> 9 -あとついでに、左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 9 +このファイルは、言語仕様などの、やや辞書的な説明です。<br /> 10 +もっとざっくりとした、言語デザインの方向性の魂的なものについては、 11 +「メタプログラミングの会」の発表スライドをご覧下さい。 12 +</p> 13 +<p> 14 +あと、 やたらとマクロの章が長くなっていますが、 この部分は、 15 +レイヤ機能を入れたら自動的にすごく自然にマクロが入るなーと思って、 16 +おまけで実装してみた程度のものです。 17 +あんまり重要ではないので、適当にスルーして下さいませ。 18 +単に、適当に入れたら適当で微妙な部分が多く残ってしまったので注意書きが増えているだけで…。 10 19 </p> 11 20 12 21 $(DDOC_MEMBERS 13 22 14 23 $(SECTION Syntax, $(SECBODY 15 24 <p> 16 25 文法について。 ................................................................................ 171 180 </pre> 172 181 <p> 173 182 let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします 174 183 (再帰関数の定義が"うまく"いっているのはこの上書きのためです)。 175 184 なんでこんなことになっているかというと、 176 185 後で説明する「レイヤ」を使ったときに 177 186 <tt>let foo = ... in @lay foo = ... in ...</tt> 178 -で他レイヤに重ね書きするためであります。 187 +で他レイヤに重ね書きするため、のつもりです。詳しくは後で。 179 188 </p> 180 189 )) 181 190 ) 182 191 )) 183 192 184 193 185 194 ................................................................................ 203 212 以下のデータ型があります。 204 213 </p> 205 214 <ul> 206 215 <li>整数: <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666666789</tt>, ...</li> 207 216 <li>文字列: <tt>"hello, world!"</tt>, ...</li> 208 217 <li>関数: <tt>fun(x){x+1}</tt></li> 209 218 <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li> 210 - <li>未定義値: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li> 219 + <li>ボトム: (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li> 211 220 </ul> 212 221 <p> 213 222 関数はいわゆる「クロージャ」です。静的スコープで外側の環境にアクセスできます。 214 223 テーブルはいわゆるプロトタイプチェーンを持っていて、 215 224 自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、 216 225 フィールドの書き換えがないので、これは特に意味ないかもしれない…。 217 226 </p> ................................................................................ 444 453 </pre> 445 454 <p> 446 455 動きとしてはこうです。 447 456 </p> 448 457 <ol> 449 458 <li>関数呼び出し時(とトップレベル環境の実行開始時)に、 450 459 まず、<code>@macro</code> レイヤでコードを実行。</li> 451 -<li>返ってきた構文木を、<code>@value</code> レイヤ、 452 - またはその関数を呼び出したときのレイヤで実行。</li> 460 +<li>返ってきた構文木を、その関数を呼び出したときのレイヤで実行。</li> 453 461 </ol> 454 462 <p> 455 463 <code>@macro</code> レイヤも所詮ただのレイヤですので、 456 464 上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、 457 465 構文木の生成をいじることが可能です。まさにマクロ。 458 466 </p> 459 467 ................................................................................ 526 534 )}; 527 535 print( reverseArgs(1-2) ); $(D_COMMENT # 2-1 == 1) 528 536 </pre> 529 537 <p> 530 538 <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。 531 539 <tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、 532 540 それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。 533 -要は、<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 534 -<tt>@value(...)</tt> は「逆クオート (unquote)」に近い働きをします。 541 +<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、 542 +<tt>@value(...)</tt> は「逆クオート (unquote)」にちょっと近いかもしれません。 535 543 </p> 536 544 <p> 537 545 <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、 538 546 一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、 539 547 さらに色々面白いことが可能です。 540 548 </p> 541 549 )) ................................................................................ 556 564 <p> 557 565 こんな感じのテーブルになります。 558 566 クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。 559 567 配列メンバは cons リストになって入ってきます。 560 568 自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。 561 569 </p> 562 570 )) 563 -$(SECTION 微妙なところ, $(SECBODY 571 +$(SECTION 微妙なところ1, $(SECBODY 564 572 <p> 565 -ここまで、<tt>@macro</tt> が本当にただの1レイヤであるかのように説明してきましたが、 566 -実はちょっと幾つかのトリックが潜んでいます。 573 +ここまで、<tt>@macro</tt> が本当にただの1レイヤと説明してきましたが、 574 +実はちょっとトリックが潜んでいます。 567 575 </p> 568 576 <pre> 569 577 &gt;&gt; @macro twice(x) {x; x} in twice($(B @value)(print("Hello"))) 570 578 Hello 571 579 Hello 572 580 Hello 573 581 </pre> 574 582 <p> 575 583 先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello 576 -が2回 print されるようになります。 584 +が2回 print されるようになります。これは本来はおかしな話で、<tt>print("Hello")</tt> 585 +は <tt>@value</tt> レイヤで実行されて値に落ちるはずなので、1回しか print されないはず。 586 +</p> 587 +<p> 588 +実は、Polemy の中では、<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> 589 +レイヤという二つの異なるマクロ用レイヤが動いています。 590 +</p> 591 +<ul> 592 + <li><tt>(rawmacro)</tt> も <tt>@macro</tt> も、コードを動かすとその構文木を返す意味論。</li> 593 + <li>ただし、<tt>(rawmacro)</tt> も <tt>@macro</tt> も、 594 + <tt>@macro</tt> レイヤに値のセットされた変数をみつけたときは、 595 + その変数という構文木を作るのではなく、変数の内容を展開。</li> 596 + <li>また <tt>@macro</tt> は、 597 + レイヤ指定式を見ると実行レイヤを切り替て、構文木生成モードをやめてしまう。</li> 598 + <li><tt>(rawmacro)</tt> は、 599 + レイヤ指定式を見ても実行レイヤを切り替えないで構文木にする。</li> 600 +</ul> 601 +<p> 602 +ユーザーから直接 <tt>(rawmacro)</tt> は呼べませんが、 603 +「関数やトップレベル実行開始前のマクロ処理は <tt>(rawmacro)</tt> で実行開始」 604 +「<tt>@macro</tt> レイヤ以外で呼び出した関数の仮引数に <tt>@macro</tt> がついていたら、 605 +その実引数は <tt>(rawmacro)</tt> で実行」 606 +という2つのタイミングで <tt>(rawmacro)</tt> が動き出します。 607 +<tt>(rawmacro)</tt> が <tt>@macro</tt> レイヤから変数を見つけてマクロし始める時に、 608 +そこで <tt>@macro</tt> に動作が移ります。 609 +</p> 610 +<p> 611 +こうなっているのは、全部がレイヤ指定式に反応する <tt>@macro</tt> の動作だと、 612 +レイヤを使ったプログラムが全て <tt>@value</tt> 実行時ではなく、 613 +マクロ展開の時点で動き始めてしまって、おかしなことになるためです。 614 +色々考えた結果、とりあえずこの中途半端な混合が具合がよいのではないかということになりました。 615 +</p> 616 +)) 617 +$(SECTION 微妙なところ2, $(SECBODY 618 +<p> 619 +「関数実行開始時に、まずマクロレイヤを実行」と書きましたが、この時、関数内関数まで辿りにいくので、 620 +何重にもネストした関数を使っていると、内側の関数は、何重にもマクロ展開が走ってしまいます。 621 +これはなにかおかしい気がしますね。Scheme などはどうなっているのか調べないと…。 622 +</p> 623 +)) 624 +$(SECTION 微妙なところ3, $(SECBODY 625 +<p> 626 +これはエラーになります。 577 627 </p> 578 628 <pre> 579 -<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> レイヤという二つが協調して動作しています。 580 - (rawmacro) レイヤの話 581 - 582 - [[limitations]] 583 - 584 - This @macro layer is a very primitive one, and not a perfect macro language. 585 - Two major limitations are seen in the following "it" example. 586 - 587 - >> @macro LetItBe(x, y) { let it = x in y }; 588 - 589 - The variable name is not hygenic, and so without any effort, the syntax tree "y" 590 - can access the outer variable "it". 591 - 592 - >> def foo() { LetItBe( 1+2+3, it*it ) } 593 - >> foo() 594 - 36 595 - 596 - Of course, this is not just a limitation; it can sometimes allow us to write 597 - many interesting macros. 598 - 599 - The other problem is that the macro expansion is only done at function startup. 600 - So 601 - 602 - >> LetItBe( 1+2+3, it*it ) 603 - ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value 604 - 605 - you cannot directly use the macro in the same scope as the definition. 606 - You need to wrap it up in a function (like the foo() in the above example). 629 + &gt;&gt; let _ = (@macro twice(x) {x;x} in twice(print("Hello"))) 630 + polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\value.d(109): 631 + [<REPL>:2:35] 'twice' is not set in @value layer 607 632 </pre> 633 +<p> 634 +どういうことかというと、<tt>@macro</tt> で定義したマクロはいつから使えるようになるかという話で、 635 +この <tt>@macro twice(x) {x;x} in ...</tt> の部分は <tt>@value</tt> レイヤの式なので、 636 +まずこの式全体のマクロ展開が終わったあとにしか実行されないのです。<tt>twice</tt> 637 +がマクロと見なされはじめるのは、<tt>@macro</tt> 実行が終わった後。 638 +なので、 639 +例えば <tt>twice(print("Hello"))</tt> の部分を無名関数にラップしてやれば、 640 +マクロ展開を遅らせられて、 ちゃんと実行ができます。 641 +</p> 642 +<p> 643 +これだと余りにも不便なので、関数のトップレベルの変数宣言式の列についてだけは、 644 +<tt>@macro</tt> と <tt>@value</tt> の評価を交互にインターリーブするようにしました。 645 +「関数やREPLのトップレベルの最初に宣言したマクロだけは、その関数内で即座に使える」わけです。 646 +これも Scheme の let-syntax などなどの動きを調べて勉強しないと…。 647 +</p> 608 648 )) 609 649 ) 610 650 )) 611 651 612 652 613 653 $(SECTION Built-in Primitives, $(SECBODY 614 654 <p>

Modified polemy/eval.d from [10da2d7378e56ec4] to [9460508c714f0a1b].

15 15 import polemy.valueconv; 16 16 import std.signals; 17 17 18 18 /// Objects for maitaining global environment and evaluation of expression on it 19 19 class Evaluator 20 20 { 21 21 public: 22 - /// Initialize evaluator with empty context 23 - this() { theContext = new Table; } 24 - 25 22 /// Evaluate the AST 26 23 Value evalAST(AST e) 27 - { 28 - return macroAndEval(e, ValueLayer, theContext, OverwriteCtx); 29 - } 24 + { return getLayerEval(ValueLayer).macroAndEval(e, theContext, LayerEval.OverwriteCtx); } 30 25 31 26 /// Evaluate the string 32 27 Value evalString(S,T...)(S str, T fn_ln_cn) 33 - { 34 - return evalAST(parseString(str,fn_ln_cn)); 35 - } 28 + { return evalAST(parseString(str,fn_ln_cn)); } 36 29 37 30 /// Evaluate the file 38 31 Value evalFile(S,T...)(S filename, T ln_cn) 39 - { 40 - return evalAST(parseFile(filename,ln_cn)); 41 - } 32 + { return evalAST(parseFile(filename,ln_cn)); } 42 33 43 34 /// Get the global context 44 35 Table globalContext() 36 + { return theContext; } 37 + 38 + /// Initialize evaluator with empty context 39 + this() 45 40 { 46 - return theContext; 41 + theContext = new Table; 42 + theLayers[ValueLayer] = new ValueLayerEval; 43 + theLayers[MacroLayer] = new MacroLayerEval; 44 + theLayers[RawMacroLayer] = new RawMacroLayerEval; 47 45 } 48 46 49 47 private: 50 - Table theContext; 48 + Table theContext; 49 + LayerEval[Layer] theLayers; 51 50 52 - enum : bool { CascadeCtx=false, OverwriteCtx=true }; 53 - 54 - LayerEval getLayerEvaluator(Layer lay) 51 + /// Get the layer evaluator from layer ID 52 + LayerEval getLayerEval(Layer lay) 55 53 { 56 - if( lay == ValueLayer ) 57 - return new ValueLayerEval; 58 - if( lay == RawMacroLayer ) 59 - return new RawMacroLayerEval; 60 - if( lay == MacroLayer ) 61 - return new MacroLayerEval; 62 - return new UserDefinedLayerEval(lay); 54 + if(auto p = lay in theLayers) 55 + return *p; 56 + return theLayers[lay] = new UserDefinedLayerEval(lay); 63 57 } 64 58 59 + /// Interface of layers 65 60 abstract class LayerEval 66 61 { 62 + enum : bool { CascadeCtx=false, OverwriteCtx=true }; 63 + 67 64 /// Concrete layers should implement these 68 - Layer currentLayer(); 69 - Value eval_( Die e, Table ctx, bool ctxMod );/// 70 - Value eval_( Str e, Table ctx, bool ctxMod );/// 71 - Value eval_( Int e, Table ctx, bool ctxMod );/// 72 - Value eval_( Var e, Table ctx, bool ctxMod );/// 73 - Value eval_( Lay e, Table ctx, bool ctxMod );/// 74 - Value eval_( Let e, Table ctx, bool ctxMod );/// 75 - Value eval_( App e, Table ctx, bool ctxMod );/// 76 - Value eval_( Fun e, Table ctx, bool ctxMod );/// 65 + protected Layer layerID(); 66 + protected Value eval_( Die e, Table ctx, bool ctxMod );/// 67 + protected Value eval_( Str e, Table ctx, bool ctxMod );/// 68 + protected Value eval_( Int e, Table ctx, bool ctxMod );/// 69 + protected Value eval_( Var e, Table ctx, bool ctxMod );/// 70 + protected Value eval_( Lay e, Table ctx, bool ctxMod );/// 71 + protected Value eval_( Let e, Table ctx, bool ctxMod );/// 72 + protected Value eval_( App e, Table ctx, bool ctxMod );/// 73 + protected Value eval_( Fun e, Table ctx, bool ctxMod );/// 74 + 75 + /// Should override this also, if the layer may return null for optimization 76 + Value evalToNonNull( AST e, Table ctx, bool ctxMod = CascadeCtx ) 77 + { return eval(e,ctx,ctxMod); } 78 + 79 + /// Do macro expansion first, and then eval. Should override this also if it is NOT macro layer. 80 + Value macroAndEval( AST e, Table ctx, bool ctxMod = CascadeCtx ) 81 + { return evalToNonNull(e,ctx,ctxMod); } 77 82 78 83 /// dynamic-overload-resolution 79 - Value eval( AST e, Table ctx, bool ctxMod ) 84 + Value eval( AST e, Table ctx, bool ctxMod = CascadeCtx ) 80 85 { 81 - enum funName = "eval_"; // modify here to customize 82 - alias TypeTuple!(e,ctx,ctxMod) params; // modify here to customize 86 + enum funName = "eval_"; // modify here for customization 87 + alias TypeTuple!(e,ctx,ctxMod) params; // modify here for customization 83 88 84 89 alias typeof(__traits(getOverloads, this, funName)) ovTypes; 85 90 alias staticMap!(firstParam, ovTypes) fstTypes; 86 91 alias DerivedToFront!(fstTypes) fstTypes_sorted; 87 92 foreach(i, T; fstTypes_sorted) 88 93 static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] ) 89 94 return __traits(getOverloads, this, funName)[i](_x, params[1..$]); 90 95 91 96 // modify here to customize the default behavior 92 97 assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined")); 93 98 } 94 99 95 - /// 96 - Value invokeFunction(Value _f, AST[] args, Table ctx, LexPosition pos, string callstackmsg) 100 + /// Function calling convention. 101 + /// Run all arugment AST in the appropriate layer and invoke the function. 102 + Value invokeFunction(Value f_, AST[] args, Table ctx, LexPosition pos, string callstackmsg) 97 103 { 98 - if(auto f = cast(FunValue)_f) 99 - { 100 - Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 101 - foreach(i,p; f.params()) 102 - if( p.layers.empty ) { 103 - Value v = this.eval(args[i], ctx, CascadeCtx); 104 - if(v is null) v = ast2table(args[i]); 105 - newCtx.set(p.name, currentLayer(), v); 104 + FunValue f = cast(FunValue)f_; 105 + if( f is null ) 106 + throw genex!RuntimeException(pos, text("tried to call non-function: ",f)); 107 + if( f.params().length != args.length ) 108 + throw genex!RuntimeException(pos, 109 + sprintf!("%d arguments required but %d passed")(f.params().length, args.length)); 110 + 111 + Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 112 + foreach(i,p; f.params()) 113 + if( p.layers.empty ) 114 + newCtx.set(p.name, layerID(), this.evalToNonNull(args[i], ctx)); 115 + else 116 + foreach(argLay; p.layers) 117 + { 118 + Layer ll = argLay; 119 + if( isMacroLayer(argLay) && typeid(this)!=typeid(MacroLayerEval) ) 120 + ll = RawMacroLayer; // explicit @macro invokes (rawmacro) 121 + newCtx.set(p.name, argLay, getLayerEval(ll).evalToNonNull(args[i], ctx)); 106 122 } 107 - else 108 - foreach(argLay; p.layers) { 109 - Layer ll = argLay; 110 - if( isMacroLayer(argLay) && typeid(this)!=typeid(MacroLayerEval) ) 111 - ll = RawMacroLayer; // explicit @macro invokes (rawmacro) 112 - Value v = getLayerEvaluator(ll).eval(args[i], ctx, CascadeCtx); 113 - if(v is null) v = ast2table(args[i]); 114 - newCtx.set(p.name, argLay, v); 115 - } 116 - scope _ = new PushCallStack(pos, callstackmsg); 117 - return f.invoke(currentLayer(), newCtx, pos); 118 - } 119 - throw genex!RuntimeException(pos, text("tried to call non-function: ",_f)); 123 + scope _ = new PushCallStack(pos, callstackmsg); 124 + return f.invoke(layerID(), newCtx, pos); 120 125 } 121 126 122 - /// 127 + /// Lift the value v to the current layer 123 128 Value lift(Value v, Table ctx, LexPosition pos) 124 129 { 125 - Layer lay = currentLayer(); 126 - 127 - // functions are automatically lifterd 130 + // functions are automatically lifted by itself 128 131 if( cast(FunValue) v ) 129 132 return v; 130 133 134 + Layer lay = layerID(); 135 + 136 + // load the lift function 131 137 if( !ctx.has(lay, LiftLayer) ) 132 138 throw genex!RuntimeException(pos, "lift function for "~lay~" is not registered" ); 133 139 134 - // similar to invokeFunction, but with only one argument bound to ValueLayer 135 - auto _f = ctx.get(lay, LiftLayer, pos); 136 - if(auto f = cast(FunValue)_f) 137 - { 138 - Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 139 - auto ps = f.params(); 140 - if( ps.length != 1 ) 141 - throw genex!RuntimeException(pos, 142 - text("lift function for", lay, " must take exactly one argument of ", ValueLayer)); 143 - if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer ) 144 - { 145 - newCtx.set(ps[0].name, ValueLayer, v); 146 - scope _ = new PushCallStack(pos, lay); 147 - return f.invoke(ValueLayer, newCtx, pos); 148 - } 149 - else 150 - throw genex!RuntimeException(pos, 151 - text("lift function for", lay, " must take exactly one argument of ", ValueLayer)); 152 - } 153 - throw genex!RuntimeException(pos, 154 - text("non-function ", _f, " is registered as the lift function for ", lay)); 140 + Value f_ = ctx.get(lay, LiftLayer, pos); 141 + FunValue f = cast(FunValue) f_; 142 + if( f is null ) 143 + throw genex!RuntimeException(pos, 144 + text("non-function ", f_, " is registered as the lift function for ", lay)); 145 + if( f.params().length != 1 || f.params()[0].layers.length>=1 ) 146 + throw genex!RuntimeException(pos, 147 + text("lift function must take exactly 1 neutral parameter:",lay)); 148 + 149 + // invokeFunction 150 + Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet); 151 + newCtx.set(f.params()[0].name, ValueLayer, v); 152 + scope _ = new PushCallStack(pos, "lift to "~lay); 153 + return f.invoke(ValueLayer, newCtx, pos); 155 154 } 156 155 } 157 156 158 157 /// Evaluator for standard @value semantics 159 158 class ValueLayerEval : LayerEval 160 159 { 161 - override Layer currentLayer() 160 + override Layer layerID() 162 161 { 163 162 return ValueLayer; 164 163 } 165 164 override Value eval_( Die e, Table ctx, bool ctxMod ) 166 165 { 167 166 throw genex!RuntimeException(e.pos, "undefined case"); 168 167 } ................................................................................ 172 171 } 173 172 override Value eval_( Int e, Table ctx, bool ctxMod ) 174 173 { 175 174 return new IntValue(e.data); 176 175 } 177 176 override Value eval_( Var e, Table ctx, bool ctxMod ) 178 177 { 179 - return ctx.get(e.name, currentLayer(), e.pos); 178 + return ctx.get(e.name, layerID(), e.pos); 180 179 } 181 180 override Value eval_( Lay e, Table ctx, bool ctxMod ) 182 181 { 183 - auto le = getLayerEvaluator(e.layer); 184 - auto v = le.eval(e.expr,ctx,CascadeCtx); 185 - if( (v is null) && (cast(MacroLayerEval)le !is null) ) 186 - return ast2table(e.expr); 187 - else 188 - return v; 182 + return getLayerEval(e.layer).evalToNonNull(e.expr, ctx); 189 183 } 190 184 override Value eval_( Let e, Table ctx, bool ctxMod ) 191 185 { 192 - Table newCtx = ctxMod ? ctx : new Table(ctx, Table.Kind.NotPropagateSet); 193 - Value ri = this.eval(e.init, newCtx, CascadeCtx); 194 - if(e.name!="_") 195 - newCtx.set(e.name, e.layer.empty ? currentLayer() : e.layer, ri); 196 - return this.eval(e.expr, newCtx, OverwriteCtx); 186 + if( !ctxMod ) 187 + ctx = new Table(ctx, Table.Kind.NotPropagateSet); 188 + Value ri = this.eval(e.init, ctx); 189 + ctx.set(e.name, e.layer.empty ? layerID(): e.layer, ri); 190 + return this.eval(e.expr, ctx, OverwriteCtx); 197 191 } 198 192 override Value eval_( App e, Table ctx, bool ctxMod ) 199 193 { 200 194 Value f = this.eval( e.fun, ctx, CascadeCtx ); 201 195 return this.invokeFunction(f, e.args, ctx, e.pos, getNameIfPossible(e.fun)); 202 196 } 203 197 override Value eval_( Fun e, Table ctx, bool ctxMod ) 204 198 { 205 199 return createNewFunction(e, ctx); 206 200 } 201 + override Value macroAndEval( AST e, Table ctx, bool ctxMod ) 202 + { 203 + // incremental execution of let-expressions 204 + if(auto le = cast(Let)e) 205 + { 206 + AST ai = runMacro(le.init, ctx); 207 + 208 + if( !ctxMod ) 209 + ctx = new Table(ctx, Table.Kind.NotPropagateSet); 210 + 211 + Value vi = this.eval(ai, ctx); 212 + ctx.set(le.name, le.layer.empty ? layerID() : le.layer, vi); 213 + return this.macroAndEval(le.expr, ctx, OverwriteCtx); 214 + } 215 + else 216 + return this.eval(runMacro(e,ctx,ctxMod), ctx, ctxMod); 217 + } 207 218 } 208 219 209 220 /// Evaluator for user-defined layer 210 221 class UserDefinedLayerEval : ValueLayerEval 211 222 { 212 - Layer layerID; 223 + Layer theID; 213 224 mixin SimpleConstructor; 214 225 215 - override Layer currentLayer() 226 + override Layer layerID() 216 227 { 217 - return layerID; 228 + return theID; 218 229 } 219 230 override Value eval_( Die e, Table ctx, bool ctxMod ) 220 231 { 221 - return new UndefinedValue; 232 + return new BottomValue; 222 233 } 223 234 override Value eval_( Str e, Table ctx, bool ctxMod ) 224 235 { 225 - return this.lift(new StrValue(e.data), ctx, e.pos); 236 + return this.lift(super.eval_(e,ctx,ctxMod), ctx, e.pos); 226 237 } 227 238 override Value eval_( Int e, Table ctx, bool ctxMod ) 228 239 { 229 - return this.lift(new IntValue(e.data), ctx, e.pos); 240 + return this.lift(super.eval_(e,ctx,ctxMod), ctx, e.pos); 230 241 } 231 242 override Value eval_( Var e, Table ctx, bool ctxMod ) 232 243 { 233 - if( ctx.has(e.name, currentLayer()) ) 234 - return ctx.get(e.name, currentLayer()); 244 + if( ctx.has(e.name, layerID()) ) 245 + return ctx.get(e.name, layerID()); 235 246 return this.lift(ctx.get(e.name, ValueLayer, e.pos), ctx, e.pos); 236 247 } 237 248 } 238 249 239 - // Convention!! 240 - // returns null if never used macro-like feature 250 + // Macro layer. For optimization, if AST didn't change it returns null 241 251 class MacroLayerEval : LayerEval 242 252 { 243 - override Layer currentLayer() 253 + override Layer layerID() 244 254 { 245 255 return MacroLayer; 256 + } 257 + override Value evalToNonNull( AST e, Table ctx, bool ctxMod = CascadeCtx ) 258 + { 259 + Value v = this.eval(e, ctx, ctxMod); 260 + return v is null ? ast2table(e) : v; 246 261 } 247 262 override Value eval_( Die e, Table ctx, bool ctxMod ) 248 263 { 249 264 return null; 250 265 } 251 266 override Value eval_( Str e, Table ctx, bool ctxMod ) 252 267 { ................................................................................ 254 269 } 255 270 override Value eval_( Int e, Table ctx, bool ctxMod ) 256 271 { 257 272 return null; 258 273 } 259 274 override Value eval_( Var e, Table ctx, bool ctxMod ) 260 275 { 261 - if( ctx.has(e.name, currentLayer()) ) 262 - return ctx.get(e.name, currentLayer(), e.pos); 263 - else 264 - return null; 276 + if( ctx.has(e.name, layerID()) ) 277 + return ctx.get(e.name, layerID(), e.pos); 278 + return null; 265 279 } 266 280 override Value eval_( Lay e, Table ctx, bool ctxMod ) 267 281 { 268 - auto le = getLayerEvaluator(e.layer); 269 - return le.eval(e.expr,ctx,CascadeCtx); 282 + return getLayerEval(e.layer).eval(e.expr,ctx); 270 283 } 271 284 override Value eval_( Let e, Table ctx, bool ctxMod ) 272 285 { 273 - Table newCtx = ctxMod ? ctx : new Table(ctx, Table.Kind.NotPropagateSet); 274 - Value ai = this.eval(e.init, newCtx, CascadeCtx); 275 - newCtx.set(e.name, NoopLayer, null); 276 - Value ae = this.eval(e.expr, newCtx, OverwriteCtx); 277 - if( ai is null && ae is null ) 278 - return null; 286 + if( !ctxMod ) 287 + ctx = new Table(ctx, Table.Kind.NotPropagateSet); 288 + 289 + Value ai = this.eval(e.init, ctx); 290 + ctx.set(e.name, NoopLayer, null); 291 + Value ae = this.eval(e.expr, ctx, OverwriteCtx); 292 + 293 + if( ai is null && ae is null ) return null; 279 294 if( ai is null ) ai = ast2table(e.init); 280 295 if( ae is null ) ae = ast2table(e.expr); 296 + 281 297 return ast2table(e, delegate Value (AST _){ 282 298 if(_ is e.init) { return ai; } 283 299 if(_ is e.expr) { return ae; } 284 300 assert(false); 285 301 }); 286 302 } 287 303 override Value eval_( App e, Table ctx, bool ctxMod ) 288 304 { 289 - Value f = this.eval( e.fun, ctx, CascadeCtx ); 305 + Value f = this.eval( e.fun, ctx ); 290 306 if(auto ff = cast(FunValue)f) 291 307 return this.invokeFunction(ff, e.args, ctx, e.pos, getNameIfPossible(e.fun)); 292 - else { 308 + else 309 + { 293 310 bool allNull = (f is null); 294 311 Value[] vas; 295 - foreach(a; e.args) { 312 + foreach(a; e.args) 313 + { 296 314 Value va = this.eval(a, ctx, CascadeCtx); 297 315 if(va !is null) allNull = false; 298 316 vas ~= va; 299 317 } 300 318 if( allNull ) 301 319 return null; 302 320 return ast2table(e, delegate Value (AST _){ ................................................................................ 304 322 foreach(i,a; e.args) if(_ is a) return (vas[i] is null ? ast2table(a) : vas[i]); 305 323 assert(false); 306 324 }); 307 325 } 308 326 } 309 327 override Value eval_( Fun e, Table ctx, bool ctxMod ) 310 328 { 311 - Table newCtx = new Table(ctx, Table.Kind.NotPropagateSet); 329 + ctx = new Table(ctx, Table.Kind.NotPropagateSet); 312 330 foreach(p; e.params) 313 - newCtx.set(p.name, NoopLayer, null); 314 - Value af = this.eval(e.funbody, newCtx, CascadeCtx); 331 + ctx.set(p.name, NoopLayer, null); 332 + Value af = this.eval(e.funbody, ctx); 315 333 if( af is null ) 316 334 return null; 317 335 return ast2table(e, (AST _){if(_ is e.funbody)return af; assert(false);}); 318 336 } 319 337 } 320 338 339 + /// (rawmacro) layer. almost same as @macro, but the Layer expression becomes AST, too. 321 340 class RawMacroLayerEval : MacroLayerEval 322 341 { 323 342 override Value eval_( Lay e, Table ctx, bool ctxMod ) 324 343 { 325 - Value ae = this.eval(e.expr, ctx, CascadeCtx); 344 + Value ae = this.eval(e.expr, ctx); 326 345 return ae is null ? null 327 346 : ast2table(e, delegate Value (AST _){if(_ is e.expr)return ae; assert(false);}); 328 347 } 329 348 } 330 349 331 -private: 332 - Value macroAndEval( AST e_, Layer lay, Table ctx, bool ctxMod ) 333 - { 334 - assert( !isASTLayer(lay) ); 335 - if(auto e = cast(Let)e_) 336 - { 337 - Value vai = getLayerEvaluator(RawMacroLayer).eval(e.init, ctx, CascadeCtx); 338 - AST ai = (vai is null ? e.init : polemy2d!(AST)(vai, e.pos)); 350 +private: // short utils 339 351 340 - if( !ctxMod ) 341 - ctx = new Table(ctx, Table.Kind.NotPropagateSet); 342 - 343 - Value vi = getLayerEvaluator(lay).eval(ai, ctx, CascadeCtx); 344 - string theLayer = e.layer.empty ? lay : e.layer; 345 - ctx.set(e.name, theLayer, vi); 346 - 347 - return macroAndEval( e.expr, lay, ctx, OverwriteCtx ); 348 - } 349 - else 350 - { 351 - Value va = getLayerEvaluator(RawMacroLayer).eval(e_, ctx, ctxMod); 352 - AST a = (va is null ? e_ : polemy2d!(AST)(va, e_.pos)); 353 - return getLayerEvaluator(lay).eval(a, ctx, ctxMod); 354 - } 355 - } 356 - 357 -private: 358 352 string getNameIfPossible(AST e) 359 353 { 360 354 if(auto v = cast(Var)e) 361 355 return v.name; 362 356 return ""; 363 357 } 364 358 359 + AST runMacro(AST e, Table ctx, bool ctxMod=LayerEval.CascadeCtx) 360 + { 361 + Value v = getLayerEval(RawMacroLayer).eval(e, ctx, ctxMod); 362 + return (v is null ? e : polemy2d!(AST)(v, e.pos)); 363 + } 364 + 365 +private: 365 366 Value createNewFunction(Fun e, Table ctx) 366 367 { 367 368 class UserDefinedFunValue : FunValue 368 369 { 369 370 Fun ast; 370 371 Table defCtx; 371 372 override const(Parameter[]) params() { return ast.params; } ................................................................................ 385 386 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 386 387 throw genex!RuntimeException("comparison with value and something other"); 387 388 } 388 389 override hash_t toHash() { 389 390 return (cast(hash_t)cast(void*)ast) + (cast(hash_t)cast(void*)defCtx); 390 391 } 391 392 392 - AST macroCache; 393 393 AST[void*] mandeCache; 394 394 static class MemokeyType 395 395 { 396 - void* a; Layer b; Tuple!(string,Layer,Value)[] c; 397 - hash_t toHash() { 398 - hash_t h = structuralHash(a) + structuralHash(b); 399 - foreach(e; c) 400 - h += structuralHash(e[0])+structuralHash(e[1])+structuralHash(e[2]); 401 - return h; 402 - } 403 - mixin SimpleToString; 404 - mixin SimpleConstructor; 405 - mixin SimpleCompareWithoutToHash; 396 + void* a; Layer b; Table c; 397 + mixin SimpleClass; 406 398 } 407 399 static Tuple!(Value,int)[MemokeyType] memo; 408 400 409 401 override Value invoke(Layer lay, Table ctx, LexPosition pos) 410 402 { 411 - if( isASTLayer(lay) ) { 412 - Value v = getLayerEvaluator(lay).eval(ast.funbody, ctx, CascadeCtx); 413 - if( v is null ) v = ast2table(ast.funbody); 414 - return v; 415 - } 416 - return macroAndEval(ast.funbody, lay, ctx, CascadeCtx); 417 -/* 418 - auto nonMemoizedRun = (){ 419 - if( macroCache is null ) 420 - { 421 - auto va = macroAndEval(e.funbody, lay, ctx, CascadeCtx, mandeCache); 422 - macroCache = va[1]; 423 - return va[0]; 424 - } 425 - else 426 - return eval(macroCache, lay, ctx); 427 - }; 403 + auto evlay = getLayerEval(lay); 404 + auto nonMemoizedRun = (){ return evlay.macroAndEval(ast.funbody, ctx); }; 428 405 429 406 if( !isUserDefinedLayer(lay) ) 430 407 return nonMemoizedRun(); 431 408 432 - MemokeyType memokey = new MemokeyType(cast(void*)ast, lay, ctx.direct_entries()); 433 - 409 + // automatic memoized co-recursive execution 410 + MemokeyType memokey = new MemokeyType(cast(void*)ast, lay, ctx); 434 411 if(auto p = memokey in memo) 435 412 { 436 413 (*p)[1] ++; 437 414 return (*p)[0]; 438 415 } 439 416 else 440 - memo[memokey] = tuple(lift(new UndefinedValue, lay, ctx, pos), 0); 417 + memo[memokey] = tuple(evlay.lift(new BottomValue, ctx, pos), 0); 441 418 442 419 Value r = nonMemoizedRun(); 443 420 444 421 int touched = memo[memokey][1]; 445 422 memo[memokey] = tuple(r, 12345678); 446 - //if(touched) {DBG("rerun :: ",r);r = nonMemoizedRun();} // twice!! 447 423 return r; 448 -*/ 449 424 } 450 425 } 451 426 return new UserDefinedFunValue(e,ctx); 452 427 } 453 428 454 429 public: 455 430 /// Add primitive function to the global context ................................................................................ 499 474 } 500 475 } 501 476 } 502 477 theContext.set(name, defLay, new NativeFunValue(dg)); 503 478 } 504 479 } 505 480 506 -version(unittest) import polemy.runtime; 481 +version(unittest) 482 + import polemy.runtime; 483 + 507 484 unittest 508 485 { 509 486 auto e = new Evaluator; 510 487 enrollRuntimeLibrary(e); 511 488 auto r = assert_nothrow( e.evalString(`var x = 21; x + x*x;`) ); 512 489 assert_eq( r, new IntValue(BigInt(21+21*21)) ); 513 490 assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21)) ); 514 491 assert_nothrow( e.globalContext.get("x",ValueLayer) ); 515 492 assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) ); 516 493 } 494 + 517 495 unittest 518 496 { 519 497 auto e = new Evaluator; 520 498 enrollRuntimeLibrary(e); 521 499 auto r = assert_nothrow( e.evalString(`var x = 21; var x = x + x*x;`) ); 522 500 assert_eq( r, new IntValue(BigInt(21+21*21)) ); 523 501 assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(21+21*21) ); ................................................................................ 593 571 } 594 572 595 573 unittest 596 574 { 597 575 auto e = new Evaluator; 598 576 enrollRuntimeLibrary(e); 599 577 assert_throw!RuntimeException( e.evalString(`...`) ); 600 - assert_eq( e.evalString(`@@foo(x){x}; @foo(...)`), new UndefinedValue ); 578 + assert_eq( e.evalString(`@@foo(x){x}; @foo(...)`), new BottomValue ); 601 579 }

Modified polemy/runtime.d from [f71ff7dc6628e423] to [d6bfebbae7e5dfaf].

57 57 e.addPrimitive("_isint", ValueLayer, 58 58 (Value v){return new IntValue(cast(IntValue)v !is null);} ); 59 59 e.addPrimitive("_isstr", ValueLayer, 60 60 (Value v){return new IntValue(cast(StrValue)v !is null);} ); 61 61 e.addPrimitive("_isfun", ValueLayer, 62 62 (Value v){return new IntValue(cast(FunValue)v !is null);} ); 63 63 e.addPrimitive("_isundefined", ValueLayer, 64 - (Value v){return new IntValue(cast(UndefinedValue)v !is null);} ); 64 + (Value v){return new IntValue(cast(BottomValue)v !is null);} ); 65 65 e.addPrimitive("_istable", ValueLayer, 66 66 (Value v){return new IntValue(cast(Table)v !is null);} ); 67 67 // table 68 68 e.addPrimitive(".", ValueLayer, (Table t, StrValue s){ 69 69 if( t.has(s.data, ValueLayer) ) 70 70 return t.get(s.data, ValueLayer); 71 71 throw genex!RuntimeException(text("table do not have the field ",s));

Modified polemy/value.d from [3d0cc7f551924493] to [37c7b437fe230ee4].

48 48 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 49 49 throw genex!RuntimeException("comparison with value and somithing other"); 50 50 } 51 51 mixin SimpleToHash; 52 52 } 53 53 54 54 /// 55 -class UndefinedValue : Value 55 +class BottomValue : Value 56 56 { 57 57 mixin SimpleConstructor; 58 - override string toString() const { return "<undefined>"; } 58 + override string toString() const { return "_|_"; } 59 59 override int opCmp(Object rhs) { 60 60 if(auto r = cast(StrValue)rhs) return 0; 61 61 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 62 62 throw genex!RuntimeException("comparison with value and somithing other"); 63 63 } 64 64 mixin SimpleToHash; 65 65 }

Modified sample/fib.pmy from [5b2c3c452aca5b18] to [4438bc82733dcb16].

1 +# Standard Fibonacci function 1 2 def fib(x) 2 3 { 3 4 if x<2 then 1 else fib(x-1) + fib(x-2) 4 5 }; 5 6 6 7 let upto = fun(n, f){ 7 8 if n > 0: upto(n-1,f); 8 9 f(n) 9 10 }; 10 11 11 12 var compose = fun(f,g){ fun(x){f(g(x))} }; 12 13 var "<<" = compose; 13 14 14 -upto(16, print<<fib); 15 +upto(18, print<<fib); 16 + 17 + 18 +###################################### 19 +# Omake. Feel the automatic memoization! 20 + 21 +# Set up a mirror layer (do-the-same-thing layer) of @value 22 +@@m(x){x}; 23 +@m "+" (x,y) { @value(@m(x)+@m(y)) }; 24 +@m "-" (x,y) { @value(@m(x)-@m(y)) }; 25 +@m "<" (x,y) { @value(@m(x)<@m(y)) }; 26 +@m "if" (c,t,e) { @value(if @m(c) then @m(t()) else @m(e())) }; 27 + 28 +# Helper function to call fib in layer @m 29 +def fibm(x @value) { @m(fib(@value(x))) }; 30 + 31 +# User defined layers are automatically memoized. 32 +# So this is much faster. 33 +upto(18, print<<fibm);

Modified sample/helloworld.pmy from [da81646a4f1f8106] to [0b93991cb774eeae].

1 -# omake. how to use argv 1 +print( "Hello, World" ); 2 + 3 +# Omake. How to use argv 2 4 def print_list(xs) 3 5 { 4 6 case xs when {car: x, cdr: xs}: ( 5 7 print(x); 6 8 print_list(xs) 7 9 ) 8 10 }; 9 11 print_list(argv); 10 - 11 -# here is the helloworld 12 -print( "Hello, World" );