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 2 Polemy 0.1.0
3 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 9 - Install DMD
12 10 http://www.digitalmars.com/d/2.0/changelog.html
13 11 Version 2.050 is recommended. Older or newer version may not work.
14 12
15 13 - Build
16 14 (for Windows) Run build.bat
................................................................................
17 15 (for Unix) Run build.sh
18 16 or use your favorite build tools upon main.d and polemy/*.d.
19 17
20 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 24 d2stacktrace/*
27 25
28 26 is written by Benjamin Thaut and licensed under 2-clause BSD License.
29 27 See http://3d.benjamin-thaut.de/?p=15 for the detail.
30 28
31 29 (this package is used only for enabling stack-traces during printing exceptions;
................................................................................
35 33 main.d
36 34
37 35 All the other parts are written by Kazuhiro Inaba and
38 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 42 > polemy
45 43 starts REPL
46 44
47 45 > polemy foo.pmy
48 46 executes foo.pmy
49 47
................................................................................
51 49 after executing foo.pmy, starts REPL
52 50
53 51 > polemy -l foo.pmy -l bar.pmy buz.pmy
54 52 executes foo.pmy, bar.bmy, and then buz.pmy
55 53
56 54
57 55
58 -<<Syntax>>
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 ")"
56 +[Language Reference]
90 57
91 -The following are actually rewritten to function calls:
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|def)-(;|in)
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 object directly
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 heavily :).
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 in
161 - the @LayerName layer. Other than @value, one other predefined layer exists: @macro.
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@value:<REPL>},
167 - is@value:int,
168 - data@value:1},
169 - cdr@value:{
170 - car@value:{pos@value:{lineno@value:3, column@value:11, filename@value:<REPL>},
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 meaning of
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 the new layer.
193 - Let us define the "@type" layer, where the meaning of programs is their static type.
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 value.
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 layer.
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 function...
288 -
289 - >> foo(1+2)
290 - {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REPL>},
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 tree.
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 "y"
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 startup.
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 && and ||.)
387 - < > <= >= == != 2-ary generic comparison
388 - ~ 2-ary string concatenation (works also for non-string objects)
389 -
390 - print 1-ary print-to-stdout
391 -
392 - _isint _isstr _isfun _isundefined _istable 1-ary dynamic-type-test
58 + See doc/index.html (in Japanese)
393 59