Check-in [20be503cae]
Not logged in
Overview
SHA1 Hash:20be503cae05074ce66a474f0b525a2489d4eb8b
Date: 2010-11-24 12:30:56
User: kinaba
Comment:set up referece manual
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified .poseidon from [2aef71c310b2301f] to [836851406ea9429f].

7 <filter>*.d</filter> 7 <filter>*.d</filter> 8 <showemptyfolder>0</showemptyfolder> 8 <showemptyfolder>0</showemptyfolder> 9 <buildSpec> 9 <buildSpec> 10 <buildType>0</buildType> 10 <buildType>0</buildType> 11 <mainFile>main.d</mainFile> 11 <mainFile>main.d</mainFile> 12 <Args /> 12 <Args /> 13 <options> 13 <options> 14 <dmd> -D -Dddoc -g -unittest </dmd> | 14 <dmd> -g -unittest </dmd> 15 <tool /> 15 <tool /> 16 <lib /> 16 <lib /> 17 <implib /> 17 <implib /> 18 <extra>doc\candydoc\candy.ddoc doc\candydoc\modules.ddoc | 18 <extra /> 19 <toolextra /> 19 <toolextra /> 20 <merge>0</merge> 20 <merge>0</merge> 21 <nonfiles>0</nonfiles> 21 <nonfiles>0</nonfiles> 22 <useimplib>0</useimplib> 22 <useimplib>0</useimplib> 23 <mapfile>0</mapfile> 23 <mapfile>0</mapfile> 24 <gcstub>0</gcstub> 24 <gcstub>0</gcstub> 25 </options> 25 </options> ................................................................................................................................................................................ 48 </source> 48 </source> 49 <interface /> 49 <interface /> 50 <resource /> 50 <resource /> 51 <othersDMD /> 51 <othersDMD /> 52 <others> 52 <others> 53 <name>build.bat</name> 53 <name>build.bat</name> 54 <name>build.sh</name> 54 <name>build.sh</name> 55 <name>doc\candydoc\candy.ddoc</name> | 55 <name>builddoc.bat</name> 56 <name>doc\candydoc\modules.ddoc</name> 56 <name>doc\candydoc\modules.ddoc</name> > 57 <name>index.dd</name> 57 <name>readme.txt</name> 58 <name>readme.txt</name> 58 </others> 59 </others> 59 </projectFiles> 60 </projectFiles> 60 <includePaths /> 61 <includePaths /> 61 <linkLibrarys /> 62 <linkLibrarys /> 62 <importExpressions /> 63 <importExpressions /> 63 </buildSpec> 64 </buildSpec> 64 </projectDescription> 65 </projectDescription>

Added builddoc.bat version [3483396bbcf61fe3]

> 1 @setlocal ENABLEDELAYEDEXPANSION > 2 @set ARGS= > 3 @for %%I in (main.d polemy\*.d tricks\*.d) do @set ARGS=!ARGS! %%I > 4 @if not exist bin mkdir bin > 5 @echo dmd -o- -D -Dddoc index.dd doc\candydoc\candy.ddoc doc\candydoc\modules.dd > 6 @dmd -o- -D -Dddoc index.dd doc\candydoc\candy.ddoc doc\candydoc\modules.ddoc %A

Modified doc/candydoc/modules.ddoc from [0a368b5142d88e21] to [78fbfc498c081cb1].

1 MODULES = 1 MODULES = > 2 $(MODULE index) 2 $(MODULE main) 3 $(MODULE main) 3 $(MODULE tricks.tricks) 4 $(MODULE tricks.tricks) 4 $(MODULE tricks.test) 5 $(MODULE tricks.test) 5 $(MODULE polemy._common) 6 $(MODULE polemy._common) 6 $(MODULE polemy.failure) 7 $(MODULE polemy.failure) 7 $(MODULE polemy.layer) 8 $(MODULE polemy.layer) 8 $(MODULE polemy.fresh) 9 $(MODULE polemy.fresh)

Added index.dd version [f78a001ef162c560]

> 1 Ddoc > 2 $(DDOC_AUTHORS k.inaba) > 3 $(DDOC_LICENSE NYSL 0.9982 (http://www.kmonos.net/nysl/)) > 4 > 5 <p> > 6 このファイルは、言語仕様などの簡単な説明です。 > 7 </p> > 8 <p> > 9 あとついでに、左のサイドバーの "Package" タブをクリックすると実装のソースのドキュメントが読めます。 > 10 </p> > 11 > 12 $(DDOC_MEMBERS > 13 > 14 $(SECTION Syntax, $(SECBODY > 15 > 16 <p> > 17 文法について。 > 18 字句解析がわりと適当なので、 > 19 変数宣言の変数名のところに、数字を変数名として使えて照できない変数が作れたり、 > 20 予約語は予約語として解釈され得ないところでは普通に変名として使えちゃったりして、 > 21 偶にとんでもない見かけのソースが構文解析通りますが、にしないで適当に使って下さい。 > 22 </p> > 23 > 24 $(DDOC_MEMBERS > 25 > 26 $(SECTION 文字コード, $(SECBODY > 27 <p> > 28 UTF-8 のみ対応です。 > 29 </p> > 30 )) > 31 > 32 $(SECTION コメント, $(SECBODY > 33 <p> > 34 行コメントは <tt>#</tt> から改行までです。 > 35 </p> > 36 <p> > 37 ブロックコメントはありません。 > 38 </p> > 39 )) > 40 > 41 $(SECTION BNF, $(SECBODY > 42 <pre> > 43 ID ::= 適当に識別子っぽい文字列 > 44 LAYER ::= "@" ID > 45 > 46 E ::= > 47 $(D_COMMENT # 変数宣言) > 48 | ("var"|"let"|"def"|LAYER) ID "=" E (";"|"in") E > 49 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" (";"|"in") E > 50 | ("var"|"let"|"def"|LAYER) ID "=" E > 51 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" > 52 > 53 $(D_COMMENT # リテラル) > 54 | INTEGER $(D_COMMENT # 非負整数) > 55 | STRING $(D_COMMENT # "" でくくった文字列\" と \\ は使える) > 56 | "{" ENTRYS "}" $(D_COMMENT # テーブル) > 57 | "fun" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数) > 58 | "λ" "(" PARAMS ")" "{" E "}" $(D_COMMENT # 無名関数) > 59 > 60 $(D_COMMENT # 関数呼び出し) > 61 | E "(" ARGS")" > 62 > 63 where ARGS ::= E "," ... "," E > 64 PARAMS ::= (ID|LAYER)+ "," ... "," (ID|LAYER)+ > 65 ENTRYS ::= ID ":" E "," ... "," ID ":" E > 66 > 67 $(D_COMMENT # 演算子など) > 68 | "(" E ")" $(D_COMMENT # ただの括弧) > 69 | E BINOP E $(D_COMMENT # 二項演算子いろいろ) > 70 | E "." ID $(D_COMMENT # テーブルのフィールドアクセス) > 71 | E ".?" ID $(D_COMMENT # テーブルにフィールドがあるか否か) > 72 | E "{" ENTRYS "}" $(D_COMMENT # テーブル拡張) > 73 | "if" "(" E ")" "{" E "}" > 74 | "if" "(" E ")" "{" E "}" "else "{" E "}" > 75 > 76 $(D_COMMENT # パターンマッチ) > 77 | "case" "(" E ")" ("when" "(" PATTERN ")" "{" E "}")* > 78 > 79 where PATTERN ::= 式がだいたいなんでも書ける気がする > 80 > 81 $(D_COMMENT # レイヤ指定実行) > 82 | LAYER "(" E ")" > 83 </pre> > 84 )) > 85 > 86 $(SECTION 糖衣構文, $(SECBODY > 87 <p> > 88 演算子というものはありません。内部的には全て関数呼びし構文に書き換えられています。<tt>if</tt> もです。 > 89 <br/> > 90 パターンマッチも全部 <tt>if</tt> と <tt>==</tt> と <tt>&amp;&amp;</tt> と > 91 <tt>.</tt> と <tt>.?</tt> を使った関数呼び出し式に書き換えらていますが、 > 92 規則の詳細を説明するのが面倒なので適当に想像して下さ。 > 93 他の書き換えはこんな感じです。 > 94 </p> > 95 <pre> > 96 if (E) then{E} ⇒ if( E, fun(){E}, fun(){} ) > 97 if (E) then{E} else{E} ⇒ if( E, fun(){E}, fun(){E} ) > 98 E BINOP E ⇒ BINOP(E, E) > 99 { ENTRIES } ⇒ {}{ ENTRIES } > 100 {} ⇒ {}() > 101 E {ID:E, ...} ⇒ .=(E, ID, E) { ... } > 102 </pre> > 103 <p> > 104 変数宣言に色々ありますが、<tt>let</tt> と <tt>var</tt> と <tt>def</tt> は同じ扱いで、 > 105 <tt>in</tt> と <tt>;</tt> は同じ扱いです。つまり > 106 </p> > 107 <pre> > 108 let x = E in E > 109 var x = E in E > 110 def x = E in E > 111 let x = E ; E > 112 var x = E ; E > 113 def x = E ; E > 114 </pre> > 115 <p> > 116 以上のどれも同じ意味なので、なんとなく関数型っぽく書たい気分の日は <tt>let in</tt> を、 > 117 手続き型っぽく書きたい気分の日は <tt>var ;</tt> を使うとよでしょう。 > 118 </p> > 119 <p> > 120 関数を宣言するときは、<tt>fun</tt> や <tt>λ</tt> を省略できます。 > 121 以下の書き換えが行われます。 > 122 </p> > 123 <pre> > 124 def f( ARGS ) { E }; E ⇒ def f = fun(ARGS){E}; E > 125 </pre> > 126 <p> > 127 他に、もっと手続き型っぽくための書き換え色々 > 128 </p> > 129 <pre> > 130 fun () { E; E; E } ⇒ fun () { let _ = E in let _ = E in E } > 131 fun () { var x = 100 } ⇒ fun () { var x = 100; x } > 132 fun () { var x = 100; } ⇒ fun () { var x = 100; x } > 133 fun () { } ⇒ fun () { "(empty function body)" } > 134 </pre> > 135 <p> > 136 中身が空の関数に何を返させるかは適当です。今はとりあず適当に文字列返してます。 > 137 </p> > 138 )) > 139 > 140 $(SECTION 変数のスコープ規則, $(SECBODY > 141 <p> > 142 NOTE: Theres no "let rec" syntax, but still recursive definition works > 143 def f(x) { if(x==0){1}else{x*f(x-1)} } in f(10) #=> 3628800 > 144 yet still the code below also works > 145 def x=21 in def x=x+x in x #=> 42. > 146 The internal scoping mechanism is a little tricky (this is for coping with > 147 the "layer" feature explained below), but I hope that it works as everyone > 148 expects in most cases, as long as you don't use the same-name-variables heavil > 149 </p> > 150 )) > 151 > 152 )) > 153 > 154 > 155 > 156 > 157 $(SECTION Basic Features, $(SECBODY > 158 <p> > 159 特に特徴的でもない部分を簡単にまとめ。 > 160 </p> > 161 <ul> > 162 <li>静的型システムはありません。</li> > 163 <li>"ほぼ" 純粋関数型言語です。変数やテーブルのフィードの破壊的な書き換えはできません。<br/> > 164 ただし、組み込み関数(<tt>print</tt>)と、変数のスコープ規則のマジカルな片隅に副作用があります。</li> > 165 </ul> > 166 <p> > 167 静的型システムがないのは意図的ですが、破壊的代入がなのは、単に実装がめんどかっただけなので、 > 168 今後何か増えるかもしれません。増えないかもしれません > 169 </p> > 170 $(DDOC_MEMBERS > 171 $(SECTION データ型, $(SECBODY > 172 <p> > 173 以下のデータ型があります。 > 174 </p> > 175 <ul> > 176 <li>整数: <tt>0</tt>, <tt>123</tt>, <tt>456666666666666666666666666666666666 > 177 <li>文字列: <tt>"hello, world!"</tt>, ...</li> > 178 <li>関数: <tt>fun(x){x+1}</tt></li> > 179 <li>テーブル: <tt>{car: 1, cdr: {car: 2, cdr: {}}}</tt></li> > 180 <li>未定義値: (テーブルの、存在しないフィールドにアクスしたりすると作れます)</li> > 181 </ul> > 182 <p> > 183 関数はいわゆる「クロージャ」です。静的スコープで外側環境にアクセスできます。 > 184 テーブルはいわゆるプロトタイプチェーンを持っていて、 > 185 自分にないフィールドの場合は親に問い合わせが行く感じなっていますが、 > 186 フィールドの書き換えがないので、これは特に意味ないかしれない…。 > 187 </p> > 188 )) > 189 $(SECTION パターンマッチ, $(SECBODY > 190 pattern matching is also available. Here is an example. > 191 > 192 def adjSum(lst) > 193 { > 194 case( lst ) > 195 when( {car:x, cdr:{car: y, cdr:z}} ) { {car: x+y, cdr: adjSum(z)} } > 196 when( {car:x, cdr:{}} ) { {car: x, cdr: {}} } > 197 when( {} ) { {} } > 198 }; > 199 > 200 It is expanded to a sequence of if-then-elses prefering the first-match. > 201 Note that {a: _} pattern matches all the tables that have the .a field. > 202 It also matches to {a: 123, b: 456} having extra .b field. So, changing the > 203 order of "when"s in the above code changes the behavior. > 204 )) > 205 ) > 206 )) > 207 > 208 > 209 > 210 > 211 > 212 $(SECTION Layers, $(SECBODY > 213 <pre> > 214 [Layers :: Overview] > 215 > 216 Polemy's runtime environment has many "layer"s. > 217 Usual execution run in the @value layer. > 218 > 219 >> 1 + 2 > 220 3 > 221 >> @value( 1 + 2 ) > 222 3 > 223 > 224 Here you can see that @LayerName( Expression ) executes the inner Expression i > 225 the @LayerName layer. Other than @value, one other predefined layer exists: @m > 226 > 227 >> @macro( 1+2 ) > 228 {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, > 229 is@value:app, > 230 args@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@v > 231 is@value:int, > 232 data@value:1}, > 233 cdr@value:{ > 234 car@value:{pos@value:{lineno@value:3, column@value:11, filenam > 235 is@value:int, > 236 data@value:2}, > 237 cdr@value:{}}}, > 238 fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL > 239 is@value:var, > 240 name@value:+}} > 241 > 242 (Sorry, this pretty printing is not available on the actual interpreter...) > 243 This evaluates the expression 1+2 in the @macro layer. In this layer, the mean > 244 the program is its abstract syntax tree. > 245 > 246 You can interleave layers. > 247 The root node of the abstract syntax tree is function "app"lication. > 248 > 249 >> @value(@macro( 1+2 ).is) > 250 app > 251 > 252 > 253 > 254 [Layers :: Defining a new layer] > 255 > 256 To define a new layer, you should first tell how to "lift" existing values two > 257 Let us define the "@type" layer, where the meaning of programs is their static > 258 > 259 >> @@type = fun(x) { > 260 >> if( _isint(x) ) { "int" } else { > 261 >> if( _isfun(x) ) { x } else { "unknown" } } > 262 >> } > 263 (Note: polemy REPL may warn some exception here but please ignore) > 264 > 265 For simplicity, I here deal only with integers. > 266 _isint is a primitive function of Polemy that checks the dynamic type of a val > 267 For function, leaving it untouched works well for almost all layers. > 268 > 269 >> @type( 1 ) > 270 int > 271 >> @type( 2 ) > 272 int > 273 >> @type( "foo" ) > 274 unknown > 275 > 276 Fine! Let's try to type 1+2. > 277 > 278 >> @type( 1 + 2 ) > 279 ...\value.d(119): [<REPL>:6:8] only @value layer can call native function > 280 > 281 Note that the behavior of this program is > 282 - run 1+2 in the @type layer > 283 and NOT > 284 - run 1+2 in @value and obtain 3 and run 3 in the @type. > 285 The problem is, the variable "+" is defined only in the @value layer. > 286 To carry out computation in the @type layer. We need to define it also > 287 in the @type layer. > 288 > 289 To define some variable in a specific layer, use @LayerName in place of > 290 (let|var|def)s. > 291 > 292 >> let x = 2 > 293 >> @value x = 2 > 294 >> @type x = "int" > 295 >> @hoge x = "fuga" > 296 > 297 For "+", do it like this. > 298 > 299 >> @type "+" = fun(x,y) {@value( > 300 >> if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" } > 301 >> )} > 302 polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24 > 303 > 304 It is just computing the return type from the input type. > 305 Not here that the intended "meaning" of if-then-else is the runtime-branching, > 306 and the meaning of "==" is the value-comparison. These are the @value layer > 307 behavior. So we have defined the function body inside @value layer. > 308 But when we refer the variables x and y, we need its @type layer meaning. > 309 Hence we use @type() there. > 310 > 311 Now we get it. > 312 > 313 >> @type( 1 + 2 ) > 314 int > 315 > 316 Well, but do we have to define the @type layer meaning for every variables??? > 317 No. After you defined @type "+", you'll automatically get the following: > 318 > 319 >> def double(x) { x + x } > 320 (function:17e4740:1789720) > 321 > 322 >> @type( double(123) ) > 323 int > 324 > 325 Every user-defined functions are automatically "lift"ed to the appropriate lay > 326 Only primitive functions like "+" requires @yourNewLayer annotation. > 327 > 328 > 329 > 330 [Layers :: neutral-layer] > 331 > 332 let|var|def is to define a variable in the "current" layer. > 333 Not necessary to the @value layer. > 334 > 335 >> @value( let x = 1 in @value(x) ) > 336 1 > 337 > 338 >> @macro( let x = 1 in @value(x) ) > 339 polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found > 340 > 341 >> @macro( let x = 1 in @macro(x) ) > 342 {pos@value:{lineno@value:15, ... > 343 > 344 > 345 > 346 [Layers :: Layered-Parameters] > 347 > 348 >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} } > 349 (function:1730360:1789720) > 350 > 351 If you annotate function parameters by @LayerNames, when you invoke the functi > 352 > 353 >> foo(1+2) > 354 {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REP > 355 is@value:app, arg@value:{... > 356 /fst@value:3 > 357 /} > 358 > 359 its corresponding arguments are evaluated in the layer and passed to it. > 360 If you specify multiple layers, the argument expression is run multiple times. > 361 If you do not specify any layer for a parameter, it works in the neutral layer > 362 > 363 > 364 > 365 [@macro layer] > 366 > 367 When function is invoked, it first run in the @macro layer, and after that, > 368 it run in the neutral layer. Here is an example. > 369 > 370 >> @macro twice(x) { x; x } > 371 >> def f() { twice(print("Hello")); 999 } > 372 (function:173b6a0:1789720) > 373 >> f() > 374 Hello > 375 Hello > 376 999 > 377 > 378 When the interpreter evaluates f(), it first executes > 379 "twice(print("Hello")); 999" > 380 in the @macro layer. Basically what it does is to just construct its syntax t > 381 But, since we have defined the "twice" function in the @macro layer, it is > 382 execute as a function. Resulting syntax tree is > 383 "print("Hello"); print("Hello"); 999" > 384 and this is executed on the neutral (in this example, @value) layer. > 385 This is the reason why you see two "Hello"s. > 386 > 387 > 388 > 389 [[limitations]] > 390 > 391 This @macro layer is a very primitive one, and not a perfect macro language. > 392 Two major limitations are seen in the following "it" example. > 393 > 394 >> @macro LetItBe(x, y) { let it = x in y }; > 395 > 396 The variable name is not hygenic, and so without any effort, the syntax tree > 397 can access the outer variable "it". > 398 > 399 >> def foo() { LetItBe( 1+2+3, it*it ) } > 400 >> foo() > 401 36 > 402 > 403 Of course, this is not just a limitation; it can sometimes allow us to write > 404 many interesting macros. > 405 > 406 The other problem is that the macro expansion is only done at function startu > 407 So > 408 > 409 >> LetItBe( 1+2+3, it*it ) > 410 ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value > 411 > 412 you cannot directly use the macro in the same scope as the definition. > 413 You need to wrap it up in a function (like the foo() in the above example). > 414 > 415 > 416 > 417 [[quote and unquote]] > 418 > 419 Here is more involved example of code genration. > 420 From "x", it generates "x*x*x*x*x*x*x*x*x*x". > 421 > 422 @macro pow10(x) { > 423 @value( > 424 def pow(x, n) { > 425 if( n == 1 ) { x } > 426 else { > 427 @macro( @value(x) * @value(pow(x,n-1)) ) > 428 } > 429 } > 430 in > 431 pow(@macro(x),10) > 432 ) > 433 }; > 434 > 435 Here, x is a syntax tree but n is an actual integer. If you read carefully, > 436 you should get what is going on. Basically, @macro can be considered like > 437 quasiquoting and @value to be an escape from it. > 438 </pre> > 439 )) > 440 > 441 > 442 $(SECTION Built-in Primitives, $(SECBODY > 443 <p> > 444 組み込み関数・変数の一覧。 > 445 </p> > 446 $(DDOC_MEMBERS > 447 > 448 $(SECTION テーブル操作, $(SECBODY > 449 $(TABLE > 450 $(TR $(TH {}) $(TD ()) $(TD 空のテーブルを作る)) > 451 $(TR $(TH .) $(TD (t, s)) $(TD テーブル t の名前 s のフィールドの値を取得。なければ <tt>undefined</ > 452 $(TR $(TH .?) $(TD (t, s)) $(TD テーブル t に名前 s のフィールがあれば 1、なければ 0)) > 453 $(TR $(TH .=) $(TD (t, s, v)) $(TD テーブル t を親に持ち、名前 s のフィールドに v が入ったテーブルを作る)) > 454 ) > 455 )) > 456 <br /> > 457 > 458 $(SECTION 制御フロー, $(SECBODY > 459 $(TABLE > 460 $(TR $(TH if) $(TD (n, ft, fe)) $(TD n が非 0 なら <tt>ft()</t>、0 な <tt>fe()</t > 461 ) > 462 )) > 463 <br /> > 464 > 465 $(SECTION 演算, $(SECBODY > 466 $(TABLE > 467 $(TR $(TH +) $(TD (n, m)) $(TD 整数 n と整数 m を足して返す)) > 468 $(TR $(TH -) $(TD (n, m)) $(TD 整数の引き算)) > 469 $(TR $(TH *) $(TD (n, m)) $(TD 整数の掛け算)) > 470 $(TR $(TH /) $(TD (n, m)) $(TD 整数の割り算)) > 471 $(TR $(TH %) $(TD (n, m)) $(TD 整数の剰余)) > 472 $(TR $(TH &amp;&amp;) $(TD (n, m)) $(TD 整数 n と m が両方非 0 なら 1、それ以外では 0)) > 473 $(TR $(TH ||) $(TD (n, m)) $(TD 整数 n と m がどちらか非 0 なら 1、それ以外では 0)) > 474 $(TR $(TH ~) $(TD (a, b)) $(TD a と b を文字列化して結合)) > 475 $(TR $(TH &lt;) $(TD (a, b)) $(TD a と b を比較)) > 476 $(TR $(TH &lt;=) $(TD (a, b)) $(TD a と b を比較)) > 477 $(TR $(TH &gt;) $(TD (a, b)) $(TD a と b を比較)) > 478 $(TR $(TH &gt;=) $(TD (a, b)) $(TD a と b を比較)) > 479 $(TR $(TH ==) $(TD (a, b)) $(TD a と b を比較)) > 480 $(TR $(TH !=) $(TD (a, b)) $(TD a と b を比較)) > 481 ) > 482 <p> > 483 注意点として、作者の趣味の問題で、<tt>&amp;&amp;</tt> と <tt>||</tt> は short-circuit 評価をしません。 > 484 整数演算の種類が少ないのは、D 言語の std.bigint がビット演算などをサポートしてないためです。 > 485 文字列が結合しかできないのは、単に手抜きです。 > 486 </p> > 487 )) > 488 > 489 $(SECTION 外部とのやりとり, $(SECBODY > 490 $(TABLE > 491 $(TR $(TH print) $(TD (a)) $(TD a を文字列化標準出力に改行付きで表示)) > 492 $(TR $(TH argv) $(TD ) $(TD スクリプトに渡された引数文字列のconsリスト)) > 493 ) > 494 )) > 495 <br /> > 496 > 497 $(SECTION データ型判定, $(SECBODY > 498 $(TABLE > 499 $(TR $(TH _isint) $(TD (a)) $(TD a が整数なら 1、でなければ 0)) > 500 $(TR $(TH _isstr) $(TD (a)) $(TD a が文字列なら 1、でなければ 0)) > 501 $(TR $(TH _isfun) $(TD (a)) $(TD a が関数なら 1、でなければ 0)) > 502 $(TR $(TH _istable) $(TD (a)) $(TD a がテーブルなら 1、でなけれ 0)) > 503 $(TR $(TH _isundefined) $(TD (a)) $(TD a が未定義値なら 1、でなければ 0)) > 504 ) > 505 )) > 506 ) > 507 )) > 508 > 509 ) > 510 Macros: > 511 TITLE=Polemy Reference Manual > 512 DOCFILENAME=index.html > 513 SECTION=$(DDOC_DECL $(DDOC_PSYMBOL $1)) $(DDOC_DECL_DD $2) > 514 SECBODY=$0

Modified polemy/eval.d from [cd1c3d2598ac30ce] to [e0978d70034e5fac].

245 text("non-function ", _f, " is registered as the lift fu 245 text("non-function ", _f, " is registered as the lift fu 246 } 246 } 247 247 248 Value createNewFunction(Fun e, Table ctx) 248 Value createNewFunction(Fun e, Table ctx) 249 { 249 { 250 class UserDefinedFunValue : FunValue 250 class UserDefinedFunValue : FunValue 251 { 251 { 252 Fun ast; | 252 Fun ast; 253 Table defCtx; | 253 Table defCtx; 254 override const(Parameter[]) params() { return ast.params 254 override const(Parameter[]) params() { return ast.params 255 override Table definitionContext() { return defCtx; } | 255 override Table definitionContext() { return defCtx; } 256 256 257 this(Fun ast, Table defCtx) { this.ast=ast; this.defCtx= 257 this(Fun ast, Table defCtx) { this.ast=ast; this.defCtx= 258 override string toString() const { return sprintf!"(func 258 override string toString() const { return sprintf!"(func 259 override bool opEquals(Object rhs_) const /// member-by- | 259 override int opCmp(Object rhs) { 260 { < > 260 if(auto r = cast(UserDefinedFunValue)rhs) { 261 if( auto rhs = cast(typeof(this))rhs_ ) | 261 if(auto i = this.ast.opCmp(r.ast)) 262 return this.ast==rhs.ast && this.defCtx= | 262 return i; 263 assert(false, sprintf!"Cannot compare %s with %s | 263 return this.defCtx.opCmp(r.defCtx); 264 } | 264 } 265 override hash_t toHash() const /// member-by-member hash | 265 if(auto r = cast(Value)rhs) return typeid(thi 266 { < 267 return typeid(this.ast).getHash(&this.ast) + typ < > 266 throw genex!RuntimeException("comparison with va 268 } 267 } 269 override int opCmp(Object rhs_) /// member-by-member com | 268 mixin SimpleToHash; 270 { < 271 if( auto rhs = cast(typeof(this))rhs_ ) < 272 { < 273 if(auto i = this.ast.opCmp(rhs.ast)) < 274 return i; < 275 return this.defCtx.opCmp(rhs.defCtx); < 276 } < 277 assert(false, sprintf!"Cannot compare %s with %s < 278 } < 279 269 > 270 AST afterMacroAST; 280 override Value invoke(Layer lay, Table ctx, LexPosition 271 override Value invoke(Layer lay, Table ctx, LexPosition 281 { 272 { 282 if( isASTLayer(lay) ) 273 if( isASTLayer(lay) ) 283 return eval(ast.funbody, lay, ctx); 274 return eval(ast.funbody, lay, ctx); 284 if( afterMacroAST is null ) 275 if( afterMacroAST is null ) 285 { 276 { 286 auto va = macroAndEval(e.funbody, lay, c 277 auto va = macroAndEval(e.funbody, lay, c 287 afterMacroAST = va[1]; 278 afterMacroAST = va[1]; 288 return va[0]; 279 return va[0]; 289 } 280 } 290 else 281 else 291 return eval(afterMacroAST, lay, ctx); 282 return eval(afterMacroAST, lay, ctx); 292 } 283 } 293 < 294 AST afterMacroAST; < 295 } 284 } 296 return new UserDefinedFunValue(e,ctx); 285 return new UserDefinedFunValue(e,ctx); 297 } 286 } 298 287 299 public: 288 public: 300 /// Add primitive function to the global context 289 /// Add primitive function to the global context 301 void addPrimitive(R,T...)(string name, Layer defLay, R delegate (T) dg) 290 void addPrimitive(R,T...)(string name, Layer defLay, R delegate (T) dg) ................................................................................................................................................................................ 305 override const(Parameter[]) params() { return params_dat 294 override const(Parameter[]) params() { return params_dat 306 override Table definitionContext() { return theContext 295 override Table definitionContext() { return theContext 307 296 308 override string toString() { return sprintf!"(native:%x) 297 override string toString() { return sprintf!"(native:%x) 309 override int opCmp(Object rhs) { 298 override int opCmp(Object rhs) { 310 if(auto r = cast(NativeFunValue)rhs) return type 299 if(auto r = cast(NativeFunValue)rhs) return type 311 if(auto r = cast(Value)rhs) return type 300 if(auto r = cast(Value)rhs) return type 312 throw genex!RuntimeException(LexPosition.dummy, | 301 throw genex!RuntimeException(LexPosition.dummy, 313 } 302 } 314 mixin SimpleToHash; 303 mixin SimpleToHash; 315 304 316 R delegate(T) dg; 305 R delegate(T) dg; 317 Parameter[] params_data; 306 Parameter[] params_data; 318 307 319 this(R delegate(T) dg) 308 this(R delegate(T) dg)

Modified polemy/failure.d from [1bc945d1d318d417] to [9cdb01160429b059].

1 /** | 1 /** 2 * Authors: k.inaba 2 * Authors: k.inaba 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 4 * 4 * 5 * Error Information for Polemy Programming Language 5 * Error Information for Polemy Programming Language 6 */ 6 */ 7 module polemy.failure; 7 module polemy.failure; 8 import polemy._common; 8 import polemy._common;

Modified polemy/fresh.d from [72c1e0f374b13246] to [15707244447f6971].

1 /** | 1 /** 2 * Authors: k.inaba 2 * Authors: k.inaba 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 4 * 4 * 5 * Interpreter-wise fresh ID generator. 5 * Interpreter-wise fresh ID generator. 6 */ 6 */ 7 module polemy.fresh; 7 module polemy.fresh; 8 import polemy._common; 8 import polemy._common;

Modified polemy/layer.d from [bd983db748e0ad6a] to [ec0e00bb40d202e7].

1 /** | 1 /** 2 * Authors: k.inaba 2 * Authors: k.inaba 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 4 * 4 * 5 * Definition of constants related to the layers. 5 * Definition of constants related to the layers. 6 */ 6 */ 7 module polemy.layer; 7 module polemy.layer; 8 import polemy._common; 8 import polemy._common;

Modified polemy/parse.d from [bacc00f3f91907a9] to [64474993b2d6bb44].

433 SinglePattern[] parsePattern(string[] path = null) 433 SinglePattern[] parsePattern(string[] path = null) 434 { 434 { 435 SinglePattern[] result; 435 SinglePattern[] result; 436 if( tryEat("{") ) 436 if( tryEat("{") ) 437 { 437 { 438 if( !tryEat("}") ) { 438 if( !tryEat("}") ) { 439 do { 439 do { 440 string key = eatId("in table pattern"); | 440 string key = eatId("in table pattern", A 441 eat(":", "after field-id in table patter 441 eat(":", "after field-id in table patter 442 result ~= parsePattern(path ~ key); 442 result ~= parsePattern(path ~ key); 443 } while( tryEat(",") ); 443 } while( tryEat(",") ); 444 eat("}", "at the end of table pattern"); 444 eat("}", "at the end of table pattern"); 445 } 445 } 446 } 446 } 447 else 447 else

Modified polemy/value.d from [43e26264d772abeb] to [dc69a053821951bd].

27 this(long n) { this.data = n; } 27 this(long n) { this.data = n; } 28 this(BigInt n) { this.data = n; } 28 this(BigInt n) { this.data = n; } 29 this(string n) { this.data = BigInt(n); } 29 this(string n) { this.data = BigInt(n); } 30 override string toString() const { return toDecimalString(cast(BigInt)da 30 override string toString() const { return toDecimalString(cast(BigInt)da 31 override int opCmp(Object rhs) { 31 override int opCmp(Object rhs) { 32 if(auto r = cast(IntValue)rhs) return data.opCmp(r.data); 32 if(auto r = cast(IntValue)rhs) return data.opCmp(r.data); 33 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid( 33 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid( 34 throw genex!RuntimeException(LexPosition.dummy, "comparison with | 34 throw genex!RuntimeException("comparison with value and somithin 35 } 35 } 36 mixin SimpleToHash; 36 mixin SimpleToHash; 37 } 37 } 38 38 39 /// 39 /// 40 class StrValue : Value 40 class StrValue : Value 41 { 41 { ................................................................................................................................................................................ 42 string data; 42 string data; 43 43 44 mixin SimpleConstructor; 44 mixin SimpleConstructor; 45 override string toString() const { return data; } 45 override string toString() const { return data; } 46 override int opCmp(Object rhs) { 46 override int opCmp(Object rhs) { 47 if(auto r = cast(StrValue)rhs) return typeid(string).compare(&da 47 if(auto r = cast(StrValue)rhs) return typeid(string).compare(&da 48 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid( 48 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid( 49 throw genex!RuntimeException(LexPosition.dummy, "comparison with | 49 throw genex!RuntimeException("comparison with value and somithin 50 } 50 } 51 mixin SimpleToHash; 51 mixin SimpleToHash; 52 } 52 } 53 53 54 /// 54 /// 55 class UndefinedValue : Value 55 class UndefinedValue : Value 56 { 56 { 57 mixin SimpleConstructor; 57 mixin SimpleConstructor; 58 override string toString() const { return "<undefined>"; } 58 override string toString() const { return "<undefined>"; } 59 override int opCmp(Object rhs) { 59 override int opCmp(Object rhs) { 60 if(auto r = cast(StrValue)rhs) return 0; 60 if(auto r = cast(StrValue)rhs) return 0; 61 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid( 61 if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid( 62 throw genex!RuntimeException(LexPosition.dummy, "comparison with | 62 throw genex!RuntimeException("comparison with value and somithin 63 } 63 } 64 mixin SimpleToHash; 64 mixin SimpleToHash; 65 } 65 } 66 66 67 /// 67 /// 68 abstract class FunValue : Value 68 abstract class FunValue : Value 69 { 69 {

Modified readme.txt from [78aa08fe5254309c] to [1c7e412d38c82eb6].

1 ----------------------------------------------------------------------------- 1 ----------------------------------------------------------------------------- 2 Polemy 0.1.0 2 Polemy 0.1.0 3 by k.inaba (www.kmonos.net) 3 by k.inaba (www.kmonos.net) 4 Nov 20, 2010 | 4 Nov 24, 2010 5 ----------------------------------------------------------------------------- 5 ----------------------------------------------------------------------------- 6 6 7 < 8 < 9 <<How to Build>> | 7 [How to Build] 10 8 11 - Install DMD 9 - Install DMD 12 http://www.digitalmars.com/d/2.0/changelog.html 10 http://www.digitalmars.com/d/2.0/changelog.html 13 Version 2.050 is recommended. Older or newer version may not work. 11 Version 2.050 is recommended. Older or newer version may not work. 14 12 15 - Build 13 - Build 16 (for Windows) Run build.bat 14 (for Windows) Run build.bat ................................................................................................................................................................................ 17 (for Unix) Run build.sh 15 (for Unix) Run build.sh 18 or use your favorite build tools upon main.d and polemy/*.d. 16 or use your favorite build tools upon main.d and polemy/*.d. 19 17 20 Then you will get the executable "polemy" in the "bin" directory. 18 Then you will get the executable "polemy" in the "bin" directory. 21 19 22 20 23 21 24 <<License>> | 22 [License] 25 23 26 d2stacktrace/* 24 d2stacktrace/* 27 25 28 is written by Benjamin Thaut and licensed under 2-clause BSD License. 26 is written by Benjamin Thaut and licensed under 2-clause BSD License. 29 See http://3d.benjamin-thaut.de/?p=15 for the detail. 27 See http://3d.benjamin-thaut.de/?p=15 for the detail. 30 28 31 (this package is used only for enabling stack-traces during printing excepti 29 (this package is used only for enabling stack-traces during printing excepti ................................................................................................................................................................................ 35 main.d 33 main.d 36 34 37 All the other parts are written by Kazuhiro Inaba and 35 All the other parts are written by Kazuhiro Inaba and 38 licensed under NYSL 0.9982 ( http://www.kmonos.net/nysl/ ). 36 licensed under NYSL 0.9982 ( http://www.kmonos.net/nysl/ ). 39 37 40 38 41 39 42 <<How to Use>> | 40 [How to Use] 43 41 44 > polemy 42 > polemy 45 starts REPL 43 starts REPL 46 44 47 > polemy foo.pmy 45 > polemy foo.pmy 48 executes foo.pmy 46 executes foo.pmy 49 47 ................................................................................................................................................................................ 51 after executing foo.pmy, starts REPL 49 after executing foo.pmy, starts REPL 52 50 53 > polemy -l foo.pmy -l bar.pmy buz.pmy 51 > polemy -l foo.pmy -l bar.pmy buz.pmy 54 executes foo.pmy, bar.bmy, and then buz.pmy 52 executes foo.pmy, bar.bmy, and then buz.pmy 55 53 56 54 57 55 58 <<Syntax>> | 56 [Language Reference] 59 < 60 Comment is "# ... \n" < 61 < 62 E ::= < 63 // declaration < 64 | ("var"|"let"|"def"|LAYER) ID "=" E (";"|"in") E < 65 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" (";"|"in") E < 66 | ("var"|"let"|"def"|LAYER) ID "=" E < 67 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" < 68 // literal < 69 | INTEGER < 70 | STRING < 71 | "{" ENTRYS "}" // table < 72 | "fun" "(" PARAMS ")" "{" E "}" // anonymous function < 73 // function call < 74 | E "(" ARGS")" < 75 where ARGS ::= E "," ... "," E < 76 PARAMS ::= ID LAYER* "," ... "," ID LAYER* < 77 ENTRYS ::= ID ":" E "," ... "," ID ":" E < 78 ID ::= 'a-zA-Z0-9_...'+ < 79 LAYER ::= "@" ID < 80 // operators < 81 | "(" E ")" < 82 | E "." ID // table field access < 83 | E ".?" ID // table field existence check < 84 | E "{" ENTRYS "}" // table extend (pure functionally) < 85 | E BINOP E < 86 | "if" "(" E ")" "{" E "}" < 87 | "if" "(" E ")" "{" E "}" "else "{" E "}" < 88 // layered exec < 89 | LAYER "(" E ")" < 90 57 91 The following are actually rewritten to function calls: | 58 See doc/index.html (in Japanese) 92 < 93 - if (E) then{E} else{E} ==> if( E, fun(){E}, fun(){E} ) < 94 - E BINOP E ==> BINOP(E, E) < 95 - E.ID ==> . (E, ID) < 96 - E.?ID ==> .?(E, ID) < 97 - {} ==> {}() < 98 - { ENTRIES } ==> {}{ ENTRIES } < 99 - E {ID:E, ...} ==> (.=(E, ID, E)) { ... } < 100 < 101 Several styles of variable declaration can be used: < 102 < 103 - fun(x){ fun(y){x} } # K-combinator < 104 - fun(x){ let f = fun(y){x} in f } # let-in style < 105 - fun(x){ var f = fun(y){x}; f } # var-; style < 106 - fun(x){ def f = fun(y){x} in f } # you can use any combination of (let|var| < 107 - fun(x){ def f(y){x} in f } # syntax sugar for function declaration < 108 - fun(x){ let f(y){x}; f } # this is also ok < 109 - fun(x){ var f(y){x} } # omitting (;|in) returns the last declared objec < 110 - fun(x,y){x} #< this is not equal to the above ones. functions are no curried < 111 < 112 NOTE: Theres no "let rec" syntax, but still recursive definition works < 113 def f(x) { if(x==0){1}else{x*f(x-1)} } in f(10) #=> 3628800 < 114 yet still the code below also works < 115 def x=21 in def x=x+x in x #=> 42. < 116 The internal scoping mechanism is a little tricky (this is for coping with < 117 the "layer" feature explained below), but I hope that it works as everyone < 118 expects in most cases, as long as you don't use the same-name-variables heavil < 119 < 120 (Experimental) pattern matching is also available. Here is an example. < 121 < 122 def adjSum(lst) < 123 { < 124 case( lst ) < 125 when( {car:x, cdr:{car: y, cdr:z}} ) { {car: x+y, cdr: adjSum(z)} } < 126 when( {car:x, cdr:{}} ) { {car: x, cdr: {}} } < 127 when( {} ) { {} } < 128 }; < 129 < 130 It is expanded to a sequence of if-then-elses prefering the first-match. < 131 Note that {a: _} pattern matches all the tables that have the .a field. < 132 It also matches to {a: 123, b: 456} having extra .b field. So, changing the < 133 order of "when"s in the above code changes the behavior. < 134 < 135 < 136 < 137 < 138 <<Basic Features>> < 139 < 140 Polemy is an untyped functional programming language that has < 141 - integers: 0, 123, 456666666666666666666666666666666666666789, ... < 142 - strings: "hello, world!\n", ... < 143 - tables: {car: 1, cdr: {car: 2, cdr: {}}} < 144 - functions: fun(x){x+1} < 145 as primitive datatypes. Functions capture lexical closures. < 146 It is almost 'pure' (except the primitve function "print" and some < 147 trick inside scoping mechanisms). < 148 < 149 < 150 <<Layers :: Overview>> < 151 < 152 Polemy's runtime environment has many "layer"s. < 153 Usual execution run in the @value layer. < 154 < 155 >> 1 + 2 < 156 3 < 157 >> @value( 1 + 2 ) < 158 3 < 159 < 160 Here you can see that @LayerName( Expression ) executes the inner Expression i < 161 the @LayerName layer. Other than @value, one other predefined layer exists: @m < 162 < 163 >> @macro( 1+2 ) < 164 {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, < 165 is@value:app, < 166 args@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@v < 167 is@value:int, < 168 data@value:1}, < 169 cdr@value:{ < 170 car@value:{pos@value:{lineno@value:3, column@value:11, filenam < 171 is@value:int, < 172 data@value:2}, < 173 cdr@value:{}}}, < 174 fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL < 175 is@value:var, < 176 name@value:+}} < 177 < 178 (Sorry, this pretty printing is not available on the actual interpreter...) < 179 This evaluates the expression 1+2 in the @macro layer. In this layer, the mean < 180 the program is its abstract syntax tree. < 181 < 182 You can interleave layers. < 183 The root node of the abstract syntax tree is function "app"lication. < 184 < 185 >> @value(@macro( 1+2 ).is) < 186 app < 187 < 188 < 189 < 190 <<Layers :: Defining a new layer>> < 191 < 192 To define a new layer, you should first tell how to "lift" existing values two < 193 Let us define the "@type" layer, where the meaning of programs is their static < 194 < 195 >> @@type = fun(x) { < 196 >> if( _isint(x) ) { "int" } else { < 197 >> if( _isfun(x) ) { x } else { "unknown" } } < 198 >> } < 199 (Note: polemy REPL may warn some exception here but please ignore) < 200 < 201 For simplicity, I here deal only with integers. < 202 _isint is a primitive function of Polemy that checks the dynamic type of a val < 203 For function, leaving it untouched works well for almost all layers. < 204 < 205 >> @type( 1 ) < 206 int < 207 >> @type( 2 ) < 208 int < 209 >> @type( "foo" ) < 210 unknown < 211 < 212 Fine! Let's try to type 1+2. < 213 < 214 >> @type( 1 + 2 ) < 215 ...\value.d(119): [<REPL>:6:8] only @value layer can call native function < 216 < 217 Note that the behavior of this program is < 218 - run 1+2 in the @type layer < 219 and NOT < 220 - run 1+2 in @value and obtain 3 and run 3 in the @type. < 221 The problem is, the variable "+" is defined only in the @value layer. < 222 To carry out computation in the @type layer. We need to define it also < 223 in the @type layer. < 224 < 225 To define some variable in a specific layer, use @LayerName in place of < 226 (let|var|def)s. < 227 < 228 >> let x = 2 < 229 >> @value x = 2 < 230 >> @type x = "int" < 231 >> @hoge x = "fuga" < 232 < 233 For "+", do it like this. < 234 < 235 >> @type "+" = fun(x,y) {@value( < 236 >> if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" } < 237 >> )} < 238 polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24 < 239 < 240 It is just computing the return type from the input type. < 241 Not here that the intended "meaning" of if-then-else is the runtime-branching, < 242 and the meaning of "==" is the value-comparison. These are the @value layer < 243 behavior. So we have defined the function body inside @value layer. < 244 But when we refer the variables x and y, we need its @type layer meaning. < 245 Hence we use @type() there. < 246 < 247 Now we get it. < 248 < 249 >> @type( 1 + 2 ) < 250 int < 251 < 252 Well, but do we have to define the @type layer meaning for every variables??? < 253 No. After you defined @type "+", you'll automatically get the following: < 254 < 255 >> def double(x) { x + x } < 256 (function:17e4740:1789720) < 257 < 258 >> @type( double(123) ) < 259 int < 260 < 261 Every user-defined functions are automatically "lift"ed to the appropriate lay < 262 Only primitive functions like "+" requires @yourNewLayer annotation. < 263 < 264 < 265 < 266 <<Layers :: neutral-layer>> < 267 < 268 let|var|def is to define a variable in the "current" layer. < 269 Not necessary to the @value layer. < 270 < 271 >> @value( let x = 1 in @value(x) ) < 272 1 < 273 < 274 >> @macro( let x = 1 in @value(x) ) < 275 polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found < 276 < 277 >> @macro( let x = 1 in @macro(x) ) < 278 {pos@value:{lineno@value:15, ... < 279 < 280 < 281 < 282 <<Layers :: Layered-Parameters>> < 283 < 284 >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} } < 285 (function:1730360:1789720) < 286 < 287 If you annotate function parameters by @LayerNames, when you invoke the functi < 288 < 289 >> foo(1+2) < 290 {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REP < 291 is@value:app, arg@value:{... < 292 /fst@value:3 < 293 /} < 294 < 295 its corresponding arguments are evaluated in the layer and passed to it. < 296 If you specify multiple layers, the argument expression is run multiple times. < 297 If you do not specify any layer for a parameter, it works in the neutral layer < 298 < 299 < 300 < 301 <<@macro layer>> < 302 < 303 When function is invoked, it first run in the @macro layer, and after that, < 304 it run in the neutral layer. Here is an example. < 305 < 306 >> @macro twice(x) { x; x } < 307 >> def f() { twice(print("Hello")); 999 } < 308 (function:173b6a0:1789720) < 309 >> f() < 310 Hello < 311 Hello < 312 999 < 313 < 314 When the interpreter evaluates f(), it first executes < 315 "twice(print("Hello")); 999" < 316 in the @macro layer. Basically what it does is to just construct its syntax t < 317 But, since we have defined the "twice" function in the @macro layer, it is < 318 execute as a function. Resulting syntax tree is < 319 "print("Hello"); print("Hello"); 999" < 320 and this is executed on the neutral (in this example, @value) layer. < 321 This is the reason why you see two "Hello"s. < 322 < 323 < 324 < 325 [[limitations]] < 326 < 327 This @macro layer is a very primitive one, and not a perfect macro language. < 328 Two major limitations are seen in the following "it" example. < 329 < 330 >> @macro LetItBe(x, y) { let it = x in y }; < 331 < 332 The variable name is not hygenic, and so without any effort, the syntax tree < 333 can access the outer variable "it". < 334 < 335 >> def foo() { LetItBe( 1+2+3, it*it ) } < 336 >> foo() < 337 36 < 338 < 339 Of course, this is not just a limitation; it can sometimes allow us to write < 340 many interesting macros. < 341 < 342 The other problem is that the macro expansion is only done at function startu < 343 So < 344 < 345 >> LetItBe( 1+2+3, it*it ) < 346 ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value < 347 < 348 you cannot directly use the macro in the same scope as the definition. < 349 You need to wrap it up in a function (like the foo() in the above example). < 350 < 351 < 352 < 353 [[quote and unquote]] < 354 < 355 Here is more involved example of code genration. < 356 From "x", it generates "x*x*x*x*x*x*x*x*x*x". < 357 < 358 @macro pow10(x) { < 359 @value( < 360 def pow(x, n) { < 361 if( n == 1 ) { x } < 362 else { < 363 @macro( @value(x) * @value(pow(x,n-1)) ) < 364 } < 365 } < 366 in < 367 pow(@macro(x),10) < 368 ) < 369 }; < 370 < 371 Here, x is a syntax tree but n is an actual integer. If you read carefully, < 372 you should get what is going on. Basically, @macro can be considered like < 373 quasiquoting and @value to be an escape from it. < 374 < 375 < 376 < 377 <<Primitives>> < 378 < 379 {} 0-ary create-empty-table < 380 . 2-ary table-get < 381 .? 2-ary table-has? < 382 .= 3-ary table-set < 383 < 384 if 3-ary if-then-else < 385 < 386 + - * / % || && 2-ary integer-operations (NOTE! no short-circuit for && an < 387 < > <= >= == != 2-ary generic comparison < 388 ~ 2-ary string concatenation (works also for non-string obje < 389 < 390 print 1-ary print-to-stdout < 391 < 392 _isint _isstr _isfun _isundefined _istable 1-ary dynamic-type-test < 393 59