Artifact Content
Not logged in

Artifact 388d91fa67a7c4030a0e98059528f6897e718fa4


     1  Ddoc
     2  $(DDOC_AUTHORS k.inaba)
     3  $(DDOC_LICENSE NYSL 0.9982 (http://www.kmonos.net/nysl/))
     4  
     5  <p>
     6  左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。
     7  </p>
     8  <p>
     9  このファイルは、言語仕様などの、やや辞書的な説明です。<br />
    10  もっとざっくりとした、言語デザインの方向性の魂的なものについては、
    11  「メタプログラミングの会」の発表スライドをご覧下さい。
    12  </p>
    13  <p>
    14  あと、 やたらとマクロの章が長くなっていますが、 この部分は、
    15  レイヤ機能を入れたら自動的にすごく自然にマクロが入るなーと思って、
    16  おまけで実装してみた程度のものです。
    17  あんまり重要ではないので、適当にスルーして下さいませ。
    18  単に、適当に入れたら適当で微妙な部分が多く残ってしまったので注意書きが増えているだけで…。
    19  </p>
    20  
    21  $(DDOC_MEMBERS
    22  
    23  $(SECTION Syntax, $(SECBODY
    24  <p>
    25  文法について。
    26  字句解析がわりと適当なので、
    27  変数宣言の変数名のところに、数字を変数名として使えて参照できない変数が作れたり、
    28  予約語は予約語として解釈され得ないところでは普通に変数名として使えちゃったりして、
    29  偶にとんでもない見かけのソースが構文解析通りますが、気にしないで適当に使って下さい。
    30  </p>
    31  
    32  $(DDOC_MEMBERS
    33  
    34  $(SECTION 文字コード, $(SECBODY
    35  <p>
    36  UTF-8 のみ対応です。
    37  </p>
    38  ))
    39  
    40  $(SECTION コメント, $(SECBODY
    41  <p>
    42  行コメントは <tt>#</tt> から改行までです。
    43  </p>
    44  <p>
    45  ブロックコメントはありません。
    46  </p>
    47  ))
    48  
    49  $(SECTION BNF, $(SECBODY
    50  <pre>
    51   ID    ::= 適当に識別子っぽい文字列
    52   LAYER ::= "@" ID
    53  
    54   E ::=
    55     $(D_COMMENT # 変数宣言)
    56       | DECL "=" E (";"|"in") E
    57       | DECL "(" PARAMS ")" "{" E "}" (";"|"in") E
    58       | DECL "=" E
    59       | DECL "(" PARAMS ")" "{" E "}"
    60  
    61           where DECL ::= ("var"|"let"|"def"|LAYER) ID | "@" LAYER
    62  
    63     $(D_COMMENT # リテラル)
    64       | INTEGER                        $(D_COMMENT # 非負整数)
    65       | STRING                         $(D_COMMENT # "" でくくった文字列。\" と \\ は使える)
    66       | "{" ENTRYS "}"                 $(D_COMMENT # テーブル)
    67       | "fun" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数)
    68       |  "λ" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数)
    69  
    70     $(D_COMMENT # 関数呼び出し)
    71       | E "(" ARGS")"
    72  
    73           where    ARGS ::= E "," ... "," E
    74                  PARAMS ::= (ID|LAYER)+ "," ... "," (ID|LAYER)+
    75                  ENTRYS ::= ID ":" E    "," ... "," ID ":" E
    76  
    77     $(D_COMMENT # 演算子など)
    78       | "(" E ")"                 $(D_COMMENT # ただの括弧)
    79       | "..."                     $(D_COMMENT # これを実行するとdie)
    80       | E BINOP E                 $(D_COMMENT # 二項演算子いろいろ)
    81       | E "."  ID                 $(D_COMMENT # テーブルのフィールドアクセス)
    82       | E ".?" ID                 $(D_COMMENT # テーブルにフィールドがあるか否か)
    83       | E "{" ENTRYS "}"          $(D_COMMENT # テーブル拡張)
    84       | "if" E ("then"|":"|"then" ":") E
    85       | "if" E ("then"|":"|"then" ":") E "else" ":"? E
    86  
    87     $(D_COMMENT # パターンマッチ)
    88       | "case" E ("when" PATTERN ":" E )* 
    89  
    90           where PATTERN ::= 式がだいたいなんでも書ける気がする
    91  
    92     $(D_COMMENT # レイヤ指定実行)
    93       | LAYER "(" E ")"
    94  </pre>
    95  ))
    96  
    97  $(SECTION 糖衣構文, $(SECBODY
    98  <p>
    99  演算子というものはありません。内部的には全て関数呼び出し構文に書き換えられています。<tt>if</tt> もです。
   100  <br/>
   101  パターンマッチも全部 <tt>if</tt> と <tt>==</tt> と <tt>&amp;&amp;</tt> と
   102  <tt>.</tt> と <tt>.?</tt> を使った関数呼び出し式に書き換えられていますが、
   103  規則の詳細を説明するのが面倒なので適当に想像して下さい。
   104  他の書き換えはこんな感じです。
   105  </p>
   106  <pre>
   107      if E then E         ⇒ if( E, fun(){E}, fun(){} )
   108      if E then E else E  ⇒ if( E, fun(){E}, fun(){E} )
   109      E BINOP E           ⇒ BINOP(E, E)
   110      { ENTRIES }         ⇒ {}{ ENTRIES }
   111      {}                  ⇒ {}()
   112      E {ID:E, ...}       ⇒ .=(E, ID, E) { ... }
   113  </pre>
   114  <p>
   115  変数宣言に色々ありますが、<tt>let</tt> と <tt>var</tt> と <tt>def</tt> は同じ扱いで、
   116  <tt>in</tt> と <tt>;</tt> は同じ扱いです。つまり
   117  </p>
   118  <pre>
   119     let x = E in E
   120     var x = E in E
   121     def x = E in E
   122     let x = E ; E
   123     var x = E ; E
   124     def x = E ; E
   125  </pre>
   126  <p>
   127  以上のどれも同じ意味なので、なんとなく関数型っぽく書きたい気分の日は <tt>let in</tt> を、
   128  手続き型っぽく書きたい気分の日は <tt>var ;</tt> を使うとよいと思います。
   129  <tt>if then else</tt> も微妙にコロンがあったりなかったりバリエーションがありますが好みで使います。
   130  </p>
   131  <p>
   132  関数を宣言するときは、<tt>fun</tt> や <tt>λ</tt> を省略できます。
   133  以下の書き換えが行われます。
   134  </p>
   135  <pre>
   136     def f( ARGS ) { E }; E   ⇒   def f = fun(ARGS){E}; E
   137  </pre>
   138  <p>
   139  他に、もっと手続き型っぽくための書き換え色々
   140  </p>
   141  <pre>
   142     fun () { E; E; E      }   ⇒   fun () { let _ = E in let _ = E in E }
   143     fun () { var x = 100  }   ⇒   fun () { var x = 100; x }
   144     fun () { var x = 100; }   ⇒   fun () { var x = 100; x }
   145     fun () { }                ⇒   fun () { "(empty function body)" }
   146  </pre>
   147  <p>
   148  中身が空の関数に何を返させるかは適当です。今はとりあえず適当に文字列返してます。
   149  </p>
   150  ))
   151  
   152  $(SECTION 変数のスコープ規則, $(SECBODY
   153  <p>
   154  基本的には、let によって常識的な感じに変数のスコープがネストします。
   155  </p>
   156  <pre>
   157     let x=21 in let x=x+x in x    $(D_COMMENT # 42)
   158  </pre>
   159  <p>
   160  一方で、"let rec" のような特別な構文はありませんが、
   161  </p>
   162  <pre>
   163     let f = fun(x) { if x==0 then 1 else x*f(x-1) } in f(10)  $(D_COMMENT # 3628800)
   164  </pre>
   165  <p>
   166  再帰的な関数定義なども、おそらく意図されたとおりに動きます。
   167  内部の詳細は、諸般の事情により、
   168  マジカルで破壊的なスコープ規則になっているのですが、
   169  同名の変数を激しく重ねて使ったりしなければ、
   170  だいたい自然な動きをすると思います、たぶん、はい。
   171  </p>
   172  <p>
   173  ひとつだけ不可思議な動きをするのは、以下のケースです。
   174  </p>
   175  <pre>
   176     let x = 1 in
   177     let f = fun() {x} in
   178     let x = 2 in
   179        f()    $(D_COMMENT # 2!!)
   180  </pre>
   181  <p>
   182  let-in を縦にチェインしたときだけ、同名変数を破壊的に上書きします
   183  (再帰関数の定義が"うまく"いっているのはこの上書きのためです)。
   184  なんでこんなことになっているかというと、
   185  後で説明する「レイヤ」を使ったときに
   186  <tt>let foo = ... in @lay foo = ... in ...</tt>
   187  で他レイヤに重ね書きするため、のつもりです。詳しくは後で。
   188  </p>
   189  ))
   190  )
   191  ))
   192  
   193  
   194  
   195  
   196  $(SECTION Basic Features, $(SECBODY
   197  <p>
   198  特に特徴的でもない部分を簡単にまとめ。
   199  </p>
   200  <ul>
   201    <li>静的型システムはありません。</li>
   202    <li>"ほぼ" 純粋関数型言語です。変数やテーブルのフィールドの破壊的な書き換えはできません。<br/>
   203        ただし、組み込み関数(<tt>print</tt>)と、変数のスコープ規則のマジカルな片隅に副作用があります。</li>
   204  </ul>
   205  <p>
   206  静的型システムがないのは意図的ですが、破壊的代入がないのは、単に実装がめんどかっただけなので、
   207  今後何か増えるかもしれません。増えないかもしれません。
   208  </p>
   209  $(DDOC_MEMBERS
   210  $(SECTION データ型, $(SECBODY
   211  <p>
   212  以下のデータ型があります。
   213  </p>
   214  <ul>
   215    <li>整数:     <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666666789</tt>, ...</li>
   216    <li>文字列:   <tt>"hello, world!"</tt>, ...</li>
   217    <li>関数:     <tt>fun(x){x+1}</tt></li>
   218    <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li>
   219    <li>ボトム:   (特殊なケースで作られます。「レイヤ」の説明参照のこと。)</li>
   220  </ul>
   221  <p>
   222  関数はいわゆる「クロージャ」です。静的スコープで外側の環境にアクセスできます。
   223  テーブルはいわゆるプロトタイプチェーンを持っていて、
   224  自分にないフィールドの場合は親に問い合わせが行く感じになっていますが、
   225  フィールドの書き換えがないので、これは特に意味ないかもしれない…。
   226  </p>
   227  <p>
   228  また、リストを扱うために、いわゆる「cons リスト」を使います。
   229  空リストを <tt>{}</tt>、1個以上要素があるものを <tt>{car: 先頭要素, cdr: 二番目以降のリスト}</tt>
   230  という形で。この形でリストを扱わなければならないという決まりはありませんが、
   231  この形は特別扱いされて <tt>print</tt> で綺麗に出力されたりします。
   232  </p>
   233  ))
   234  $(SECTION パターンマッチ, $(SECBODY
   235  <p>
   236  適当に実装されたパターンマッチがあります。
   237  リストの 2n 番目と 2n+1 番目を足して長さを半分にする関数:
   238  </p>
   239  <pre>
   240      def adjSum(lst)
   241      {
   242        case lst
   243          when {car:x, cdr:{car: y, cdr:z}}: {car: x+y, cdr: adjSum(z)}
   244          when {car:x, cdr:{}}: lst
   245          when {}: {}
   246      }
   247  </pre>
   248  <p>
   249  動かすときには、処理系がそれっぽい if-then-else に展開しています。
   250  <tt>when</tt> を上から試していって、最初にマッチしたところを実行します。
   251  どれにもマッチしないとエラーでプログラム終了します。
   252  </p>
   253  <pre>
   254     PAT ::= "_"                                      $(D_COMMENT # ワイルドカード)
   255           | ID                                       $(D_COMMENT # 変数パターン)
   256           | "{" ID ":" PAT "," ... "," ID : PAT "}"  $(D_COMMENT # テーブルパターン)
   257           | E                                        $(D_COMMENT # 値パターン)
   258  </pre>
   259  <p>
   260  変数パターンは常にマッチして、値をその変数に束縛します。
   261  ワイルドカードも常にマッチしますが、変数束縛しません。
   262  値パターンは、任意の式が書けます。その式を評価した結果と <tt>==</tt> ならマッチします。
   263  外で束縛された変数を値パターンとして配置、は直接はできないので
   264  </p>
   265  <pre>
   266     var x = 123;
   267     case foo
   268       when {val: x+0}: ... $(D_COMMENT # これは {val:123} と同じ)
   269       when {val: x}:   ... $(D_COMMENT # これは任意の foo.?val なら常にマッチ)
   270  </pre>
   271  <p>
   272  適当にちょっと複雑な式にしてやるとよいかも(裏技)。
   273  </p>
   274  <p>
   275  テーブルパターンは、書かれたキーが全てあればマッチします。
   276  <tt>{a: _}</tt> は、<tt>.a</tt> を持ってさえいればマッチするので、
   277  <tt>{a: 123, b: 456}</tt> なんかにもマッチします。
   278  なので、リストに対するパターンを書くときには、car/cdr の場合を先に書かないと
   279  <tt>when {}</tt> を上に書くと全部マッチしちゃいます。注意。
   280  </p>
   281  ))
   282  )
   283  ))
   284  
   285  
   286  
   287  
   288  
   289  $(SECTION Layers, $(SECBODY
   290  <p>
   291  この言語の唯一の特徴的な部分は、「レイヤ」機能です。
   292  </p>
   293  <p>
   294  ひとつのコードに複数の「意味」を持たせるのが、レイヤ機能の目的です。
   295  </p>
   296  $(DDOC_MEMBERS
   297  $(SECTION 概要, $(SECBODY
   298  <p>
   299  普通に Polemy のコードを動かすと、そのコードは「<tt>@value</tt> レイヤ」で動作します。
   300  インタプリタで実験。
   301  </p>
   302  <pre>
   303      $ bin/polemy
   304      Welcome to Polemy 0.1.0
   305      &gt;&gt; 1 + 2
   306      3
   307  </pre>
   308  この、普通に、数字の 1 は数字の 1 として、2 は 2 として、足し算は足し算として実行するのが、
   309  「<tt>@value</tt> レイヤ」です。
   310  レイヤを明示的に指定するには、<tt>レイヤ名( ... )</tt> という構文を使います。
   311  $(RED $(B レイヤ指定式)) と読んでいます。
   312  つまり、さっきのコードは以下のようにも書けます。
   313  <pre>
   314      &gt;&gt; @value( 1 + 2 )
   315      3
   316  </pre>
   317  他のレイヤで動かしてみましょう。適当に。「<tt>@hoge</tt> レイヤ」で。
   318  <pre>
   319      &gt;&gt; @hoge( 3 )
   320      polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\eval.d(138):
   321      [<REPL>:4:8] lift function for @hoge is not registered
   322  </pre>
   323  <p>
   324  エラーになりました。Polemy のインタプリタは、起動時には、<tt>@value</tt>
   325  レイヤでのコードの意味しか知りません。<tt>@hoge</tt> レイヤでは <tt>3</tt>
   326  というのがどんな意味なのか、わかりません!というエラーが出ています。
   327  </p>
   328  <p>
   329  これを教えてあげるためには、<tt>@hoge</tt> レイヤの $(RED $(B リフト関数)) というものを定義します。
   330  </p>
   331  <pre>
   332      &gt;&gt; @@hoge = fun(x){ x*2 }
   333      (function:1bdc5c0:1ba8580)
   334  </pre>
   335  <p>
   336  <tt>@hoge</tt> レイヤでは、<tt>1</tt> というコードの意味は <tt>2</tt>、
   337  <tt>2</tt> というコードの意味は <tt>4</tt>、…、という、全部「2倍した意味」を持っていることにします。
   338  「<tt>@ レイヤ名 = ...</tt>」 という構文を使います。
   339  ここには、「<tt>@value</tt> レイヤでの値 <tt>x</tt> は <tt>@hoge</tt> レイヤではどういう意味になるか?」
   340  を計算して返す関数を登録します。
   341  これで、Polemy にも、<tt>@hoge</tt> レイヤの意味がわかるようになりました。
   342  </p>
   343  <pre>
   344      &gt;&gt; @hoge( 3 )
   345      6
   346  </pre>
   347  <p>
   348  では、1+2 を <tt>@hoge</tt> レイヤで動かしてみましょう。
   349  </p>
   350  <pre>
   351      &gt;&gt; @hoge( 1 + 2 )
   352      polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\eval.d(466):
   353      [<REPL>:3:7] only @value layer can call native function: +
   354      [<REPL>:3:7] +
   355  </pre>
   356  <p>
   357  まだエラーですね。これは 実は、リフト関数は
   358  </p>
   359  <pre>
   360      &gt;&gt; @hoge "+" = fun(x, y) {x}
   361  </pre>
   362  <pre>
   363  [Layers :: Overview]
   364  
   365    Polemy's runtime environment has many "layer"s.
   366    Usual execution run in the @value layer.
   367  
   368      >> 1 + 2
   369      3
   370      >> @value( 1 + 2 )
   371      3
   372  
   373    Here you can see that @LayerName( Expression ) executes the inner Expression in
   374    the @LayerName layer. Other than @value, one other predefined layer exists: @macro.
   375  
   376      >> @macro( 1+2 )
   377      {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>},
   378        is@value:app,
   379      args@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>},
   380                              is@value:int,
   381                            data@value:1},
   382                  cdr@value:{
   383                    car@value:{pos@value:{lineno@value:3, column@value:11, filename@value:<REPL>},
   384                                is@value:int,
   385                              data@value:2},
   386                    cdr@value:{}}},
   387       fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL>},
   388                   is@value:var,
   389                 name@value:+}}
   390  
   391    (Sorry, this pretty printing is not available on the actual interpreter...)
   392    This evaluates the expression 1+2 in the @macro layer. In this layer, the meaning of
   393    the program is its abstract syntax tree.
   394  
   395    You can interleave layers.
   396    The root node of the abstract syntax tree is function "app"lication.
   397  
   398      >> @value(@macro( 1+2 ).is)
   399      app
   400  
   401  
   402  
   403  [Layers :: Defining a new layer]
   404  
   405    To define a new layer, you should first tell how to "lift" existing values two the new layer.
   406    Let us define the "@type" layer, where the meaning of programs is their static type.
   407  
   408      >> @@type = fun(x) {
   409      >>   if( _isint(x) ) { "int" } else {
   410      >>   if( _isfun(x) ) { x } else { "unknown" } }
   411      >> }
   412      (Note: polemy REPL may warn some exception here but please ignore)
   413  
   414    For simplicity, I here deal only with integers.
   415    _isint is a primitive function of Polemy that checks the dynamic type of a value.
   416    For function, leaving it untouched works well for almost all layers.
   417  
   418      >> @type( 1 )
   419      int
   420      >> @type( 2 )
   421      int
   422      >> @type( "foo" )
   423      unknown
   424  
   425    Fine! Let's try to type 1+2.
   426  
   427      >> @type( 1 + 2 )
   428      ...\value.d(119): [<REPL>:6:8] only @value layer can call native function
   429  
   430    Note that the behavior of this program is
   431      - run 1+2 in the @type layer
   432    and NOT
   433      - run 1+2 in @value and obtain 3 and run 3 in the @type.
   434    The problem is, the variable "+" is defined only in the @value layer.
   435    To carry out computation in the @type layer. We need to define it also
   436    in the @type layer.
   437  
   438    To define some variable in a specific layer, use @LayerName in place of
   439    (let|var|def)s.
   440  
   441      >> let x = 2
   442      >> @value x = 2
   443      >> @type x = "int"
   444      >> @hoge x = "fuga"
   445  
   446    For "+", do it like this.
   447  
   448      >> @type "+" = fun(x,y) {@value(
   449      >>   if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" }
   450      >> )}
   451      polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24
   452  
   453    It is just computing the return type from the input type.
   454    Not here that the intended "meaning" of if-then-else is the runtime-branching,
   455    and the meaning of "==" is the value-comparison. These are the @value layer
   456    behavior. So we have defined the function body inside @value layer.
   457    But when we refer the variables x and y, we need its @type layer meaning.
   458    Hence we use @type() there.
   459  
   460    Now we get it.
   461  
   462      >> @type( 1 + 2 )
   463      int
   464  
   465    Well, but do we have to define the @type layer meaning for every variables???
   466    No. After you defined @type "+", you'll automatically get the following:
   467  
   468      >> def double(x) { x + x }
   469      (function:17e4740:1789720)
   470  
   471      >> @type( double(123) )
   472      int
   473  
   474    Every user-defined functions are automatically "lift"ed to the appropriate layer.
   475    Only primitive functions like "+" requires @yourNewLayer annotation.
   476  
   477  
   478  
   479  [Layers :: neutral-layer]
   480  
   481    let|var|def is to define a variable in the "current" layer.
   482    Not necessary to the @value layer.
   483  
   484      >> @value( let x = 1 in @value(x) )
   485      1
   486  
   487      >> @macro( let x = 1 in @value(x) )
   488      polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found
   489  
   490      >> @macro( let x = 1 in @macro(x) )
   491      {pos@value:{lineno@value:15, ...
   492  
   493  
   494  
   495  [Layers :: Layered-Parameters]
   496  
   497      >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} }
   498      (function:1730360:1789720)
   499  
   500    If you annotate function parameters by @LayerNames, when you invoke the function...
   501  
   502      >> foo(1+2)
   503      {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REPL>},
   504                    is@value:app, arg@value:{...
   505      /fst@value:3
   506      /}
   507  
   508    its corresponding arguments are evaluated in the layer and passed to it.
   509    If you specify multiple layers, the argument expression is run multiple times.
   510    If you do not specify any layer for a parameter, it works in the neutral layer.
   511  </pre>
   512  ))
   513  )
   514  ))
   515  
   516  
   517  $(SECTION Macro Layers, $(SECBODY
   518  <p>
   519  Polemy 言語組み込みのレイヤは <code>@value</code> と <code>@macro</code> の二つです。
   520  (内部的にはもういくつかありますが、ユーザから直接は使えません。)
   521  <code>@value</code> は、「普通に」普通のセマンティクスでプログラムを実行するレイヤでした。
   522  <code>@macro</code> は、実は、<code>@value</code> よりも前に実行されるレイヤで、
   523  「プログラムを実行するとその構文木を返す」というセマンティクスで動きます。
   524  </p>
   525  <pre>
   526      (ここに例)
   527  </pre>
   528  <p>
   529  動きとしてはこうです。
   530  </p>
   531  <ol>
   532  <li>関数呼び出し時(とトップレベル環境の実行開始時)に、
   533  	まず、<code>@macro</code> レイヤでコードを実行。</li>
   534  <li>返ってきた構文木を、その関数を呼び出したときのレイヤで実行。</li>
   535  </ol>
   536  <p>
   537  <code>@macro</code> レイヤも所詮ただのレイヤですので、
   538  上で説明した方法で <code>@macro</code> レイヤに関数などを登録しておくことで、
   539  構文木の生成をいじることが可能です。まさにマクロ。
   540  </p>
   541  
   542  $(DDOC_MEMBERS
   543  $(SECTION 概要, $(SECBODY
   544  <p>
   545  samples/macro.pmy にいくつか使い方サンプルが置いてありますので、詳しくはそちらをどうぞ。
   546  </p>
   547  <pre>
   548      &gt;&gt; @macro( twice(print("Hello")) )
   549      {
   550        pos: {lineno:1, column:9, filename:<REPL>},
   551       args: [ { pos: {lineno:1, column:15, filename:<REPL>},
   552                args: [{pos:{lineno:1, column:21, filename:<REPL>},
   553                         is:Str,
   554                       data:Hello}],
   555                  is: App,
   556                 fun: {pos:{lineno:1, column:15, filename:<REPL>}, is:Var, name:print}}
   557             ],
   558         is: App,
   559        fun: {pos:{lineno:1, column:9, filename:<REPL>}, is:Var, name:twice}
   560      }
   561  </pre>
   562  <p>
   563  詳細は気にしなくて構いませんが、とにかく、<tt>@macro</tt> レイヤでは、
   564  基本的には、コードを実行するとそのコードの構文木がでてきます。
   565  この挙動は <tt>@macro</tt> レイヤの変数をセットすることで、カスタマイズできます。
   566  </p>
   567  <pre>
   568      &gt;&gt; @macro twice(x) { x; x } in twice(print("Hello"))
   569      Hello
   570      Hello
   571      Hello
   572  </pre>
   573  <p>
   574  (3回出力されてますが、3個目は <tt>print(x)</tt> の返値は <tt>x</tt> なので、
   575  それがREPLによって印字されているだけです。)
   576  <tt>@macro</tt> レイヤで <tt>in</tt> 以降を実行すると、<tt>print("Hello")</tt> という式を表す構文木が作られ、
   577  それが <tt>twice</tt> 関数に渡されます。<tt>twice</tt> の中身も <tt>@macro</tt> レイヤで実行されるので、
   578  構文木を作ろうとしますが、変数 <tt>x</tt> には <tt>@macro</tt> レイヤで値が入っているので、
   579  その値を読み取って構文木を作成します。
   580  結果として、2回 <tt>print("Hello")</tt> する構文木が作られて、
   581  その後で、それが <tt>@value</tt> レイヤで実行されています。
   582  </p>
   583  <p>
   584  本当にベタに構文木を作るだけなので、変数名の衝突などなどは気にしません。「衛生的でない」マクロです。
   585  </p>
   586  <pre>
   587      @macro LetItBe(x, y) { var $(B it) = x; y };  $(D_COMMENT # y の中で変数 it が使える)
   588      print( LetItBe("myself",  "when I find " ~ $(B it) ~ " in times of trouble") );
   589  </pre>
   590  <p>
   591  変数名に気をつけるには、組み込み関数 <tt>gensym()</tt> を使って頑張って下さい。
   592  </p>
   593  ))
   594  $(SECTION レイヤ切り替え, $(SECBODY
   595  <p>
   596  他のレイヤ同様、<tt>@macro</tt> レイヤを実行中に <tt>@layer( ... )</tt> 構文を使うことで、
   597  別のレイヤでコードを動かすこともできます。よく使う例は、<tt>@value</tt>
   598  レイヤに移ることで構文木を普通に計算して色々プログラム的にいじる用途です。
   599  </p>
   600  <pre>
   601      @macro reverseArgs(e) {$(B @value)(
   602          def rev(xs, acc) {
   603            case xs when {car:x, cdr:xs}: rev(xs, {car:x, cdr:acc}) when {}: acc
   604          };
   605          case @macro(e)
   606            when {is:"App", fun:f, args:as}: {is:"App", fun:f, args:rev(as,{})}
   607            when e: e
   608      )};
   609      print( reverseArgs(1-2) ); $(D_COMMENT # 2-1 == 1)
   610  </pre>
   611  <p>
   612  <tt>reverseArgs</tt> は、関数呼び出しの構文木の、引数の順番を逆転する関数です。
   613  <tt>@macro(e)</tt> によってマクロレイヤにセットされている構文木引数を取り出し、
   614  それを <tt>@value</tt> レイヤによる普通の計算プログラムで操作しています。
   615  <tt>@macro(...)</tt> はいわゆる「準クオート (quasiquote)」、
   616  <tt>@value(...)</tt> は「逆クオート (unquote)」にちょっと近いかもしれません。
   617  </p>
   618  <p>
   619  <tt>@layer(...)</tt> だけでなく、関数のレイヤ指定引数なども同様に使うことができるので、
   620  一部の引数は <tt>@macro</tt>、一部の引数は <tt>@value</tt> レイヤで受け取る関数を書くなど、
   621  さらに色々面白いことが可能です。
   622  </p>
   623  ))
   624  $(SECTION 構文木の構造, $(SECBODY
   625  <p>
   626  構文木がどのようなテーブルで渡されてくるかについては、ソースドキュメントの
   627  <a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/ast.html">polemy.ast</a>
   628  のページをご覧下さい。例えば変数名を表す <code>Var</code> クラスには、
   629  継承の分も合わせて
   630  <tt><a href="http://www.kmonos.net/repos/polemy/doc/tip/doc/failure.html">LexPosition</a> pos;</tt>
   631  と <tt>string name;</tt> の2つのメンバがあるので
   632  </p>
   633  <pre>
   634      { is:   "Var",
   635        pos:  {filename:"foo.pmy", lineno:123, column:45},
   636        name: "x" }
   637  </pre>
   638  <p>
   639  こんな感じのテーブルになります。
   640  クラス名が <tt>is</tt> フィールドに、メンバ変数はそのままの名前で入ります。
   641  配列メンバは cons リストになって入ってきます。
   642  自分で構文木を作る時は、<tt>pos</tt> フィールドだけは省略しても構いません。
   643  </p>
   644  ))
   645  $(SECTION 微妙なところ1, $(SECBODY
   646  <p>
   647  ここまで、<tt>@macro</tt> が本当にただの1レイヤと説明してきましたが、
   648  実はちょっとトリックが潜んでいます。
   649  </p>
   650  <pre>
   651      &gt;&gt; @macro twice(x) {x; x} in twice($(B @value)(print("Hello")))
   652      Hello
   653      Hello
   654      Hello
   655  </pre>
   656  <p>
   657  先ほどの例に <tt>@value</tt> を増やしたものですが、これでもやはり、Hello
   658  が2回 print されるようになります。これは本来はおかしな話で、<tt>print("Hello")</tt>
   659  は <tt>@value</tt> レイヤで実行されて値に落ちるはずなので、1回しか print されないはず。
   660  </p>
   661  <p>
   662  実は、Polemy の中では、<tt>@macro</tt> レイヤと <tt>(rawmacro)</tt>
   663  レイヤという二つの異なるマクロ用レイヤが動いています。
   664  </p>
   665  <ul>
   666  	<li><tt>(rawmacro)</tt> も <tt>@macro</tt> も、コードを動かすとその構文木を返す意味論。</li>
   667  	<li>ただし、<tt>(rawmacro)</tt> も <tt>@macro</tt> も、
   668  		<tt>@macro</tt> レイヤに値のセットされた変数をみつけたときは、
   669  		その変数という構文木を作るのではなく、変数の内容を展開。</li>
   670  	<li>また <tt>@macro</tt> は、
   671  		レイヤ指定式を見ると実行レイヤを切り替て、構文木生成モードをやめてしまう。</li>
   672  	<li><tt>(rawmacro)</tt> は、
   673  		レイヤ指定式を見ても実行レイヤを切り替えないで構文木にする。</li>
   674  </ul>
   675  <p>
   676  ユーザーから直接 <tt>(rawmacro)</tt> は呼べませんが、
   677  「関数やトップレベル実行開始前のマクロ処理は <tt>(rawmacro)</tt> で実行開始」
   678  「<tt>@macro</tt> レイヤ以外で呼び出した関数の仮引数に <tt>@macro</tt> がついていたら、
   679  その実引数は <tt>(rawmacro)</tt> で実行」
   680  という2つのタイミングで <tt>(rawmacro)</tt> が動き出します。
   681  <tt>(rawmacro)</tt> が <tt>@macro</tt> レイヤから変数を見つけてマクロし始める時に、
   682  そこで <tt>@macro</tt> に動作が移ります。
   683  </p>
   684  <p>
   685  こうなっているのは、全部がレイヤ指定式に反応する <tt>@macro</tt> の動作だと、
   686  レイヤを使ったプログラムが全て <tt>@value</tt> 実行時ではなく、
   687  マクロ展開の時点で動き始めてしまって、おかしなことになるためです。
   688  色々考えた結果、とりあえずこの中途半端な混合が具合がよいのではないかということになりました。
   689  </p>
   690  ))
   691  $(SECTION 微妙なところ2, $(SECBODY
   692  <p>
   693  「関数実行開始時に、まずマクロレイヤを実行」と書きましたが、この時、関数内関数まで辿りにいくので、
   694  何重にもネストした関数を使っていると、内側の関数は、何重にもマクロ展開が走ってしまいます。
   695  これはなにかおかしい気がしますね。Scheme などはどうなっているのか調べないと…。
   696  </p>
   697  ))
   698  $(SECTION 微妙なところ3, $(SECBODY
   699  <p>
   700  これはエラーになります。
   701  </p>
   702  <pre>
   703      &gt;&gt; let _ = (@macro twice(x) {x;x} in twice(print("Hello")))
   704      polemy.failure.RuntimeException@C:\Develop\Projects\Polemy\polemy\value.d(109):
   705      [<REPL>:2:35] 'twice' is not set in @value layer
   706  </pre>
   707  <p>
   708  どういうことかというと、<tt>@macro</tt> で定義したマクロはいつから使えるようになるかという話で、
   709  この <tt>@macro twice(x) {x;x} in ...</tt> の部分は <tt>@value</tt> レイヤの式なので、
   710  まずこの式全体のマクロ展開が終わったあとにしか実行されないのです。<tt>twice</tt>
   711  がマクロと見なされはじめるのは、<tt>@macro</tt> 実行が終わった後。
   712  なので、
   713  例えば <tt>twice(print("Hello"))</tt> の部分を無名関数にラップしてやれば、
   714  マクロ展開を遅らせられて、 ちゃんと実行ができます。
   715  </p>
   716  <p>
   717  これだと余りにも不便なので、関数のトップレベルの変数宣言式の列についてだけは、
   718  <tt>@macro</tt> と <tt>@value</tt> の評価を交互にインターリーブするようにしました。
   719  「関数やREPLのトップレベルの最初に宣言したマクロだけは、その関数内で即座に使える」わけです。
   720  これも Scheme の let-syntax などなどの動きを調べて勉強しないと…。
   721  </p>
   722  ))
   723  )
   724  ))
   725  
   726  
   727  $(SECTION Built-in Primitives, $(SECBODY
   728  <p>
   729  組み込み関数・変数の一覧。
   730  </p>
   731  $(DDOC_MEMBERS
   732  
   733  $(SECTION テーブル操作, $(SECBODY
   734    $(TABLE
   735      $(TR $(TH {}) $(TD ()) $(TD 空のテーブルを作る))
   736      $(TR $(TH .) $(TD (t, s)) $(TD テーブル t の名前 s のフィールドの値を取得。なければ <tt>undefined</tt>))
   737      $(TR $(TH .?) $(TD (t, s)) $(TD テーブル t に名前 s のフィールドがあれば 1、なければ 0))
   738      $(TR $(TH .=) $(TD (t, s, v)) $(TD テーブル t を親に持ち、名前 s のフィールドに v が入ったテーブルを作る))
   739    )
   740  ))
   741  <br />
   742  
   743  $(SECTION 制御フロー, $(SECBODY
   744    $(TABLE
   745      $(TR $(TH if) $(TD (n, ft, fe)) $(TD n が非 0 なら <tt>ft()</t>、0 なら <tt>fe()</tt> を実行))
   746    )
   747  ))
   748  <br />
   749  
   750  $(SECTION 演算, $(SECBODY
   751    $(TABLE
   752      $(TR $(TH +) $(TD (n, m)) $(TD 整数 n と整数 m を足して返す))
   753      $(TR $(TH -) $(TD (n, m)) $(TD 整数の引き算))
   754      $(TR $(TH *) $(TD (n, m)) $(TD 整数の掛け算))
   755      $(TR $(TH /) $(TD (n, m)) $(TD 整数の割り算))
   756      $(TR $(TH %) $(TD (n, m)) $(TD 整数の剰余))
   757      $(TR $(TH &amp;&amp;) $(TD (n, m)) $(TD 整数 n と m が両方非 0 なら 1、それ以外では 0))
   758      $(TR $(TH ||) $(TD (n, m)) $(TD 整数 n と m がどちらか非 0 なら 1、それ以外では 0))
   759      $(TR $(TH ~) $(TD (a, b)) $(TD a と b を文字列化して結合))
   760      $(TR $(TH &lt;) $(TD (a, b)) $(TD a と b を比較))
   761      $(TR $(TH &lt;=) $(TD (a, b)) $(TD a と b を比較))
   762      $(TR $(TH &gt;) $(TD (a, b)) $(TD a と b を比較))
   763      $(TR $(TH &gt;=) $(TD (a, b)) $(TD a と b を比較))
   764      $(TR $(TH ==) $(TD (a, b)) $(TD a と b を比較))
   765      $(TR $(TH !=) $(TD (a, b)) $(TD a と b を比較))
   766    )
   767  <p>
   768  注意点として、作者の趣味の問題で、<tt>&amp;&amp;</tt> と <tt>||</tt> は short-circuit 評価をしません。
   769  整数演算の種類が少ないのは、D 言語の std.bigint がビット演算などをサポートしてないためです。
   770  文字列が結合しかできないのは、単に手抜きです。
   771  </p>
   772  ))
   773  
   774  $(SECTION 外部とのやりとり, $(SECBODY
   775    $(TABLE
   776      $(TR $(TH print) $(TD (a)) $(TD a を文字列化標準出力に改行付きで表示して、a を返す))
   777      $(TR $(TH argv) $(TD ) $(TD スクリプトに渡された引数文字列のconsリスト))
   778      $(TR $(TH gensym) $(TD ()) $(TD エセgensym。変数名として他とかぶらなそうな文字列を返します))
   779      $(TR $(TH rand) $(TD (n)) $(TD 0 以上 n 未満の自然数を31bit以内でランダムに生成します))
   780    )
   781  ))
   782  <br />
   783  
   784  $(SECTION データ型判定, $(SECBODY
   785    $(TABLE
   786      $(TR $(TH _isint) $(TD (a)) $(TD a が整数なら 1、でなければ 0))
   787      $(TR $(TH _isstr) $(TD (a)) $(TD a が文字列なら 1、でなければ 0))
   788      $(TR $(TH _isfun) $(TD (a)) $(TD a が関数なら 1、でなければ 0))
   789      $(TR $(TH _istbl) $(TD (a)) $(TD a がテーブルなら 1、でなければ 0))
   790      $(TR $(TH _isbot) $(TD (a)) $(TD a が未定義値なら 1、でなければ 0))
   791    )
   792  ))
   793  )
   794  ))
   795  
   796  )
   797  Macros:
   798      TITLE=Polemy Reference Manual
   799      DOCFILENAME=index.html
   800      SECTION=$(DDOC_DECL $(DDOC_PSYMBOL $1)) $(DDOC_DECL_DD $2)
   801      SECBODY=$0