Diff
Not logged in

Differences From Artifact [caf492581281c25d]:

To Artifact [80b16f2bd31d3d7f]:


450 <p> 450 <p> 451 <code>@macro</code> レイヤも所詮ただのレイヤですので、 451 <code>@macro</code> レイヤも所詮ただのレイヤですので、 452 上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、 452 上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、 453 構文木の生成をいじることが可能です。まさにマクロ。 453 構文木の生成をいじることが可能です。まさにマクロ。 454 </p> 454 </p> 455 455 456 $(DDOC_MEMBERS 456 $(DDOC_MEMBERS 457 $(SECTION 使い方, $(SECBODY | 457 $(SECTION 概要, $(SECBODY > 458 <p> > 459 samples/macro.pmy にいくつか使い方サンプルが置いてありますで、詳しくはそちらをどうぞ。 > 460 </p> > 461 <pre> > 462 &gt;&gt; @macro( twice(print("Hello")) ) > 463 { > 464 pos: {lineno:1, column:9, filename:<REPL>}, > 465 args: [ { pos: {lineno:1, column:15, filename:<REPL>}, > 466 args: [{pos:{lineno:1, column:21, filename:<REPL>}, > 467 is:Str, > 468 data:Hello}], > 469 is: App, > 470 fun: {pos:{lineno:1, column:15, filename:<REPL>}, is:Var, name:pr > 471 ], > 472 is: App, > 473 fun: {pos:{lineno:1, column:9, filename:<REPL>}, is:Var, name:twice} > 474 } > 475 </pre> > 476 <p> > 477 詳細は気にしなくて構いませんが、とにかく、<tt>@macro</tt> イヤでは、 > 478 基本的には、コードを実行するとそのコードの構文木ができます。 > 479 この挙動は <tt>@macro</tt> レイヤの変数をセットすることで、カスタマイズできます。 > 480 </p> > 481 <pre> > 482 &gt;&gt; @macro twice(x) { x; x } in twice(print("Hello")) > 483 Hello > 484 Hello > 485 Hello > 486 </pre> > 487 <p> > 488 (3回出力されてますが、3個目は <tt>print(x)</tt> の返値は <tt>x</tt> なので、 > 489 それがREPLによって印字されているだけです。) > 490 <tt>@macro</tt> レイヤで <tt>in</tt> 以降を実行すると、<tt>print("Hello")</tt> という式を表す構文木が作ら > 491 それが <tt>twice</tt> 関数に渡されます。<tt>twice</tt> の中身も <tt>@macro</tt> レイヤで実行されるので、 > 492 構文木を作ろうとしますが、変数 <tt>x</tt> には <tt>@macro</tt> レイヤで値が入っているので、 > 493 その値を読み取って構文木を作成します。 > 494 結果として、2回 <tt>print("Hello")</tt> する構文木が作られて > 495 その後で、それが <tt>@value</tt> レイヤで実行されています。 > 496 </p> > 497 <p> > 498 本当にベタに構文木を作るだけなので、変数名の衝突などどは気にしません。「衛生的でない」マクロです。 > 499 </p> > 500 <pre> > 501 @macro LetItBe(x, y) { var $(B it) = x; y }; $(D_COMMENT # y の中で変 it が使える) > 502 print( LetItBe("myself", "when I find " ~ $(B it) ~ " in times of trouble") > 503 </pre> > 504 <p> > 505 変数名に気をつけるには、組み込み関数 <tt>gensym()</tt> を使て頑張って下さい。 > 506 </p> > 507 )) > 508 $(SECTION レイヤ切り替え, $(SECBODY > 509 <p> > 510 他のレイヤ同様、<tt>@macro</tt> レイヤを実行中に <tt>@layer( ... )</tt> 構文を使うことで、 > 511 別のレイヤでコードを動かすこともできます。よく使う例、<tt>@value</tt> > 512 レイヤに移ることで構文木を普通に計算して色々プログラ的にいじる用途です。 > 513 </p> 458 <pre> 514 <pre> 459 When function is invoked, it first run in the @macro layer, and after that, | 515 @macro reverseArgs(e) {$(B @value)( 460 it run in the neutral layer. Here is an example. | 516 def rev(xs, acc) { 461 < 462 >> @macro twice(x) { x; x } < 463 >> def f() { twice(print("Hello")); 999 } < 464 (function:173b6a0:1789720) < 465 >> f() < 466 Hello < 467 Hello < 468 999 < 469 < 470 When the interpreter evaluates f(), it first executes < 471 "twice(print("Hello")); 999" < 472 in the @macro layer. Basically what it does is to just construct its syntax t < 473 But, since we have defined the "twice" function in the @macro layer, it is < 474 execute as a function. Resulting syntax tree is < 475 "print("Hello"); print("Hello"); 999" < 476 and this is executed on the neutral (in this example, @value) layer. < 477 This is the reason why you see two "Hello"s. < 478 < 479 [[quote and unquote]] < 480 < 481 Here is more involved example of code genration. < 482 From "x", it generates "x*x*x*x*x*x*x*x*x*x". < 483 < 484 @macro pow10(x) { < 485 @value( < 486 def pow(x, n) { < 487 if( n == 1 ) { x } < 488 else { < 489 @macro( @value(x) * @value(pow(x,n-1)) ) < > 517 case xs when {car:x, cdr:xs}: rev(xs, {car:x, cdr:acc}) when {}: acc 490 } | 518 }; 491 } < 492 in < 493 pow(@macro(x),10) | 519 case @macro(e) 494 ) < > 520 when {is:"App", fun:f, args:as}: {is:"App", fun:f, args:rev(as,{})} > 521 when e: e 495 }; | 522 )}; 496 < 497 Here, x is a syntax tree but n is an actual integer. If you read carefully, < 498 you should get what is going on. Basically, @macro can be considered like < 499 quasiquoting and @value to be an escape from it. < > 523 print( reverseArgs(1-2) ); $(D_COMMENT # 2-1 == 1) 500 </pre> 524 </pre> > 525 <p> > 526 <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番逆転する関数です。 > 527 <tt>@macro(e)</tt> によってマクロレイヤにセットされている構木引数を取り出し、 > 528 それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。 > 529 要は、<tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」 > 530 <tt>@value(...)</tt> は「逆クオート (unquote)」に近い働きをしま。 > 531 </p> > 532 <p> > 533 <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども様に使うことができるので、 > 534 一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイで受け取る関数を書くなど、 > 535 さらに色々面白いことが可能です。 > 536 </p> > 537 )) > 538 $(SECTION 構文木の構造, $(SECBODY 501 <p> 539 <p> 502 構文木がどのようなテーブルで渡されてくるかについては、ソースドキュメントの 540 構文木がどのようなテーブルで渡されてくるかについては、ソースドキュメントの 503 <a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/ast.html">polemy.ast</a> 541 <a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/ast.html">polemy.ast</a> 504 のページをご覧下さい。例えば変数名を表す <code>Var</code> クラスには、 542 のページをご覧下さい。例えば変数名を表す <code>Var</code> クラスには、 505 継承の分も合わせて 543 継承の分も合わせて 506 <tt><a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/failure.html">LexPos 544 <tt><a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/failure.html">LexPos 507 と <tt>string name;</tt> の2つのメンバがあるので 545 と <tt>string name;</tt> の2つのメンバがあるので ................................................................................................................................................................................ 511 pos: {filename:"foo.pmy", lineno:123, column:45}, 549 pos: {filename:"foo.pmy", lineno:123, column:45}, 512 name: "x" } 550 name: "x" } 513 </pre> 551 </pre> 514 <p> 552 <p> 515 こんな感じのテーブルになります。 553 こんな感じのテーブルになります。 516 クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。 554 クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。 517 配列メンバは cons リストになって入ってきます。 555 配列メンバは cons リストになって入ってきます。 > 556 自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略ても構いません。 518 </p> 557 </p> 519 )) 558 )) 520 $(SECTION 微妙な挙動, $(SECBODY | 559 $(SECTION 微妙なところ, $(SECBODY > 560 <p> > 561 ここまで、<tt>@macro</tt> が本当にただの1レイヤであるかのうに説明してきましたが、 > 562 実はちょっと幾つかのトリックが潜んでいます。 > 563 </p> > 564 <pre> > 565 &gt;&gt; @macro twice(x) {x; x} in twice($(B @value)(print("Hello"))) > 566 Hello > 567 Hello > 568 Hello > 569 </pre> > 570 <p> > 571 先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello > 572 が2回 print されるようになります。 > 573 </p> 521 <pre> 574 <pre> > 575 <tt>@macro</tt> レイヤと <tt>(rawmacro)</tt> レイヤという二つが協して動作しています。 522 (rawmacro) レイヤの話 576 (rawmacro) レイヤの話 523 577 524 [[limitations]] 578 [[limitations]] 525 579 526 This @macro layer is a very primitive one, and not a perfect macro language. 580 This @macro layer is a very primitive one, and not a perfect macro language. 527 Two major limitations are seen in the following "it" example. 581 Two major limitations are seen in the following "it" example. 528 582