Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -3,11 +3,12 @@ DC=dmd DC_OPT=-O -release SRC = $(wildcard *.d polemy/*.d tricks/*.d) -all: + +posix: $(DC) $(DC_OPT) -ofbin/polemy $(SRC) windows: $(DC) $(DC_OPT) -ofbin\\polemy $(SRC) Index: doc/index.html ================================================================== --- doc/index.html +++ doc/index.html @@ -568,60 +568,114 @@
-使い方 - +概要 + + +
+ + +

+samples/macro.pmy にいくつか使い方サンプルが置いてありますので、詳しくはそちらをどうぞ。 +

+
+    >> @macro( twice(print("Hello")) )
+    {
+      pos: {lineno:1, column:9, filename:},
+     args: [ { pos: {lineno:1, column:15, filename:},
+              args: [{pos:{lineno:1, column:21, filename:},
+                       is:Str,
+                     data:Hello}],
+                is: App,
+               fun: {pos:{lineno:1, column:15, filename:}, is:Var, name:print}}
+           ],
+       is: App,
+      fun: {pos:{lineno:1, column:9, filename:}, is:Var, name:twice}
+    }
+
+

+詳細は気にしなくて構いませんが、とにかく、@macro レイヤでは、 +基本的には、コードを実行するとそのコードの構文木がでてきます。 +この挙動は @macro レイヤの変数をセットすることで、カスタマイズできます。 +

+
+    >> @macro twice(x) { x; x } in twice(print("Hello"))
+    Hello
+    Hello
+    Hello
+
+

+(3回出力されてますが、3個目は print(x) の返値は x なので、 +それがREPLによって印字されているだけです。) +@macro レイヤで in 以降を実行すると、print("Hello") という式を表す構文木が作られ、 +それが twice 関数に渡されます。twice の中身も @macro レイヤで実行されるので、 +構文木を作ろうとしますが、変数 x には @macro レイヤで値が入っているので、 +その値を読み取って構文木を作成します。 +結果として、2回 print("Hello") する構文木が作られて、 +その後で、それが @value レイヤで実行されています。 +

+

+本当にベタに構文木を作るだけなので、変数名の衝突などなどは気にしません。「衛生的でない」マクロです。 +

+
+    @macro LetItBe(x, y) { var it = x; y };  # y の中で変数 it が使える
+    print( LetItBe("myself",  "when I find " ~ it ~ " in times of trouble") );
+
+

+変数名に気をつけるには、組み込み関数 gensym() を使って頑張って下さい。 +

+
+ + +
+レイヤ切り替え +
-
-   When function is invoked, it first run in the @macro layer, and after that,
-   it run in the neutral layer. Here is an example.
-
-     >> @macro twice(x) { x; x }
-     >> def f() { twice(print("Hello")); 999 }
-     (function:173b6a0:1789720)
-     >> f()
-     Hello
-     Hello
-     999
-
-   When the interpreter evaluates f(), it first executes
-     "twice(print("Hello")); 999"
-   in the @macro layer. Basically what it does is to just construct its syntax tree.
-   But, since we have defined the "twice" function in the @macro layer, it is
-   execute as a function. Resulting syntax tree is
-     "print("Hello"); print("Hello"); 999"
-   and this is executed on the neutral (in this example, @value) layer.
-   This is the reason why you see two "Hello"s.
-
-      [[quote and unquote]]
-
-   Here is more involved example of code genration.
-   From "x", it generates "x*x*x*x*x*x*x*x*x*x".
-
-     @macro pow10(x) {
-       @value(
-         def pow(x, n) {
-           if( n == 1 ) { x }
-           else {
-             @macro( @value(x) * @value(pow(x,n-1)) )
-           }
-         }
-         in
-           pow(@macro(x),10)
-       )
-     };
-
-   Here, x is a syntax tree but n is an actual integer. If you read carefully,
-   you should get what is going on. Basically, @macro can be considered like
-   quasiquoting and @value to be an escape from it.
+ 

+他のレイヤ同様、@macro レイヤを実行中に @layer( ... ) 構文を使うことで、 +別のレイヤでコードを動かすこともできます。よく使う例は、@value +レイヤに移ることで構文木を普通に計算して色々プログラム的にいじる用途です。 +

+
+    @macro reverseArgs(e) {@value(
+        def rev(xs, acc) {
+          case xs when {car:x, cdr:xs}: rev(xs, {car:x, cdr:acc}) when {}: acc
+        };
+        case @macro(e)
+          when {is:"App", fun:f, args:as}: {is:"App", fun:f, args:rev(as,{})}
+          when e: e
+    )};
+    print( reverseArgs(1-2) ); # 2-1 == 1
 

+reverseArgs は、関数呼び出しの構文木の、引数の順番を逆転する関数です。 +@macro(e) によってマクロレイヤにセットされている構文木引数を取り出し、 +それを @value レイヤによる普通の計算プログラムで操作しています。 +要は、@macro(...) はいわゆる「準クオート (quasiquote)」、 +@value(...) は「逆クオート (unquote)」に近い働きをします。 +

+

+@layer(...) だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、 +一部の引数は @macro、一部の引数は @value レイヤで受け取る関数を書くなど、 +さらに色々面白いことが可能です。 +

+
+ + +
+構文木の構造 + + +
+ + +

構文木がどのようなテーブルで渡されてくるかについては、ソースドキュメントの polemy.ast のページをご覧下さい。例えば変数名を表す Var クラスには、 継承の分も合わせて LexPosition pos; @@ -634,22 +688,38 @@

こんな感じのテーブルになります。 クラス名が is フィールドに、メンバ変数はそのままの名前で入ります。 配列メンバは cons リストになって入ってきます。 +自分で構文木を作る時は、pos フィールドだけは省略しても構いません。

-微妙な挙動 - +微妙なところ +
-
+ 

+ここまで、@macro が本当にただの1レイヤであるかのように説明してきましたが、 +実はちょっと幾つかのトリックが潜んでいます。 +

+
+    >> @macro twice(x) {x; x} in twice(@value(print("Hello")))
+    Hello
+    Hello
+    Hello
+
+

+先ほどの例に @value を増やしたものですが、これでもやはり、Hello +が2回 print されるようになります。 +

+
+@macro レイヤと (rawmacro) レイヤという二つが協調して動作しています。
    (rawmacro) レイヤの話
 
       [[limitations]]
 
    This @macro layer is a very primitive one, and not a perfect macro language.
@@ -805,11 +875,11 @@
 
 
 		
 			Page was generated with
 			
-			on Thu Nov 25 12:30:12 2010
+			on Fri Nov 26 10:02:52 2010