Differences From Artifact [78aa08fe5254309c]:
- File
readme.txt
- 2010-11-23 10:37:54 - part of checkin [5e924caac9] on branch trunk - added AST-rewriting macro sample. (user: kinaba) [annotate]
To Artifact [1c7e412d38c82eb6]:
- File
readme.txt
- 2010-11-24 03:30:56 - part of checkin [20be503cae] on branch trunk - set up referece manual (user: kinaba) [annotate]
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