Differences From Artifact [caf492581281c25d]:
- File        
index.dd
- 2010-11-25 03:32:41 - part of checkin [474c4facf0] on branch trunk - Introduced makefile to build documents. sample/macro.pmy is fully reformed. print(x) now returns x, not 0. (user: kinaba) [annotate]
 
 
To Artifact [80b16f2bd31d3d7f]:
- File        
index.dd
- 2010-11-26 05:03:10 - part of checkin [207cea338a] on branch trunk - changed hiding mechanizem of x in let x = ... for @macro layer. Old: set(x,ValueLayer,undefined) Nee: set(x,NoopLayer,null) (user: kinaba) [annotate]
 
 
  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      >> @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      >> @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      >> @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