Diff
Not logged in

Differences From Artifact [78aa08fe5254309c]:

To Artifact [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