Diff
Not logged in

Differences From Artifact [6629940451babbd3]:

To Artifact [adcd1590f6f5bc80]:


64 | ("var"|"let"|"def"|LAYER) ID "=" E (";"|"in") E 64 | ("var"|"let"|"def"|LAYER) ID "=" E (";"|"in") E 65 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" (";"|"in") E 65 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" (";"|"in") E 66 | ("var"|"let"|"def"|LAYER) ID "=" E 66 | ("var"|"let"|"def"|LAYER) ID "=" E 67 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" 67 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" 68 // literal 68 // literal 69 | INTEGER 69 | INTEGER 70 | STRING 70 | STRING 71 | "{" ENTRYS "}" | 71 | "{" ENTRYS "}" // table 72 | "fun" "(" PARAMS ")" "{" E "}" | 72 | "fun" "(" PARAMS ")" "{" E "}" // anonymous function 73 // function call 73 // function call 74 | E "(" ARGS")" 74 | E "(" ARGS")" 75 where ARGS ::= E "," ... "," E 75 where ARGS ::= E "," ... "," E 76 PARAMS ::= ID LAYER* "," ... "," ID LAYER* 76 PARAMS ::= ID LAYER* "," ... "," ID LAYER* 77 ENTRYS ::= ID ":" E "," ... "," ID ":" E 77 ENTRYS ::= ID ":" E "," ... "," ID ":" E 78 ID ::= 'a-zA-Z0-9_...'+ 78 ID ::= 'a-zA-Z0-9_...'+ 79 LAYER ::= "@" ID 79 LAYER ::= "@" ID 80 // operators 80 // operators 81 | "(" E ")" 81 | "(" E ")" 82 | E "." ID | 82 | E "." ID // table field access 83 | E ".?" ID | 83 | E ".?" ID // table field existence check > 84 | E "{" ENTRYS "}" // table extend (pure functionally) 84 | E BINOP E 85 | E BINOP E 85 | "if" "(" E ")" "{" E "}" 86 | "if" "(" E ")" "{" E "}" 86 | "if" "(" E ")" "{" E "}" "else "{" E "}" 87 | "if" "(" E ")" "{" E "}" "else "{" E "}" 87 // layered exec 88 // layered exec 88 | LAYER "(" E ")" 89 | LAYER "(" E ")" 89 90 90 The following are actually rewritten to function calls: 91 The following are actually rewritten to function calls: 91 92 92 - if (E) then{E} else{E} ==> if( E, fun(){E}, fun(){E} ) 93 - if (E) then{E} else{E} ==> if( E, fun(){E}, fun(){E} ) 93 - E BINOP E ==> BINOP(E, E) 94 - E BINOP E ==> BINOP(E, E) 94 - E.ID ==> . (E, ID) 95 - E.ID ==> . (E, ID) 95 - E.?ID ==> .?(E, ID) 96 - E.?ID ==> .?(E, ID) 96 - {} ==> {}() 97 - {} ==> {}() > 98 - { ENTRIES } ==> {}{ ENTRIES } 97 - {ID:E, ...} ==> .=({...}, ID, E) | 99 - E {ID:E, ...} ==> (.=(E, ID, E)) { ... } 98 100 99 Several styles of variable declaration can be used: 101 Several styles of variable declaration can be used: 100 102 101 - fun(x){ fun(y){x} } # K-combinator 103 - fun(x){ fun(y){x} } # K-combinator 102 - fun(x){ let f = fun(y){x} in f } # let-in style 104 - fun(x){ let f = fun(y){x} in f } # let-in style 103 - fun(x){ var f = fun(y){x}; f } # var-; style 105 - fun(x){ var f = fun(y){x}; f } # var-; style 104 - fun(x){ def f = fun(y){x} in f } # you can use any combination of (let|var| 106 - fun(x){ def f = fun(y){x} in f } # you can use any combination of (let|var| ................................................................................................................................................................................ 125 - tables: {car: 1, cdr: {car: 2, cdr: {}}} 127 - tables: {car: 1, cdr: {car: 2, cdr: {}}} 126 - functions: fun(x){x+1} 128 - functions: fun(x){x+1} 127 as primitive datatypes. Functions capture lexical closures. 129 as primitive datatypes. Functions capture lexical closures. 128 It is almost 'pure' (except the primitve function "print" and some 130 It is almost 'pure' (except the primitve function "print" and some 129 trick inside scoping mechanisms). 131 trick inside scoping mechanisms). 130 132 131 133 > 134 <<Layers :: Overview>> > 135 > 136 Polemy's runtime environment has many "layer"s. > 137 Usual execution run in the @value layer. > 138 > 139 >> 1 + 2 > 140 3 > 141 >> @value( 1 + 2 ) > 142 3 > 143 > 144 Here you can see that @LayerName( Expression ) executes the inner Expression i > 145 the @LayerName layer. Other than @value, one other predefined layer exists: @m > 146 > 147 >> @macro( 1+2 ) > 148 {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, > 149 is@value:app, > 150 arg@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@v > 151 is@value:int, > 152 data@value:1}, > 153 cdr@value:{ > 154 car@value:{pos@value:{lineno@value:3, column@value:11, filenam > 155 is@value:int, > 156 data@value:2}, > 157 cdr@value:{}}}, > 158 fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL > 159 is@value:var, > 160 name@value:+}} > 161 > 162 (Sorry, this pretty printing is not available on the actual interpreter...) > 163 This evaluates the expression 1+2 in the @macro layer. In this layer, the mean > 164 the program is its abstract syntax tree. > 165 > 166 You can interleave layers. > 167 The root node of the abstract syntax tree is function "app"lication. > 168 > 169 >> @value(@macro( 1+2 ).is) > 170 app > 171 > 172 > 173 > 174 <<Layers :: Defining a new layer>> > 175 > 176 To define a new layer, you should first tell how to "lift" existing values two > 177 Let us define the "@type" layer, where the meaning of programs is their static > 178 > 179 >> @@type = fun(x) { > 180 >> if( _isint(x) ) { "int" } else { > 181 >> if( _isfun(x) ) { x } else { "unknown" } } > 182 >> } > 183 (Note: polemy REPL may warn some exception here but please ignore) > 184 > 185 For simplicity, I here deal only with integers. > 186 _isint is a primitive function of Polemy that checks the dynamic type of a val > 187 For function, leaving it untouched works well for almost all layers. > 188 > 189 >> @type( 1 ) > 190 int > 191 >> @type( 2 ) > 192 int > 193 >> @type( "foo" ) > 194 unknown > 195 > 196 Fine! Let's try to type 1+2. > 197 > 198 >> @type( 1 + 2 ) > 199 ...\value.d(119): [<REPL>:6:8] only @value layer can call native function > 200 > 201 Note that the behavior of this program is > 202 - run 1+2 in the @type layer > 203 and NOT > 204 - run 1+2 in @value and obtain 3 and run 3 in the @type. > 205 The problem is, the variable "+" is defined only in the @value layer. > 206 To carry out computation in the @type layer. We need to define it also > 207 in the @type layer. > 208 > 209 To define some variable in a specific layer, use @LayerName in place of > 210 (let|var|def)s. > 211 > 212 >> let x = 2 > 213 >> @value x = 2 > 214 >> @type x = "int" > 215 >> @hoge x = "fuga" > 216 > 217 For "+", do it like this. > 218 > 219 >> @type "+" = fun(x,y) {@value( > 220 >> if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" } > 221 >> )} > 222 polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24 > 223 > 224 It is just computing the return type from the input type. > 225 Not here that the intended "meaning" of if-then-else is the runtime-branching, > 226 and the meaning of "==" is the value-comparison. These are the @value layer > 227 behavior. So we have defined the function body inside @value layer. > 228 But when we refer the variables x and y, we need its @type layer meaning. > 229 Hence we use @type() there. > 230 > 231 Now we get it. > 232 > 233 >> @type( 1 + 2 ) > 234 int > 235 > 236 Well, but do we have to define the @type layer meaning for every variables??? > 237 No. After you defined @type "+", you'll automatically get the following: > 238 > 239 >> def double(x) { x + x } > 240 (function:17e4740:1789720) > 241 > 242 >> @type( double(123) ) > 243 int > 244 > 245 Every user-defined functions are automatically "lift"ed to the appropriate lay > 246 Only primitive functions like "+" requires @yourNewLayer annotation. > 247 > 248 > 249 > 250 <<Layers :: neutral-layer>> > 251 > 252 let|var|def is to define a variable in the "current" layer. > 253 Not necessary to the @value layer. > 254 > 255 >> @value( let x = 1 in @value(x) ) > 256 1 > 257 > 258 >> @macro( let x = 1 in @value(x) ) > 259 polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found > 260 > 261 >> @macro( let x = 1 in @macro(x) ) > 262 {pos@value:{lineno@value:15, ... > 263 > 264 > 265 > 266 <<Layers :: Layered-Parameters>> > 267 > 268 >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} } > 269 (function:1730360:1789720) > 270 > 271 If you annotate function parameters by @LayerNames, when you invoke the functi > 272 > 273 >> foo(1+2) > 274 {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REP > 275 is@value:app, arg@value:{... > 276 /fst@value:3 > 277 /} > 278 > 279 its corresponding arguments are evaluated in the layer and passed to it. > 280 If you specify multiple layers, the argument expression is run multiple times. > 281 If you do not specify any layer for a parameter, it works in the neutral layer > 282 > 283 > 284 132 <<Layer>> | 285 <<@macro layer>> > 286 > 287 When function is invoked, it first run in the @macro layer, and after that, > 288 it run in the neutral layer. Here is an example. > 289 > 290 >> @macro twice(x) { x; x } > 291 >> def f() { twice(print("Hello")); 999 } > 292 (function:173b6a0:1789720) > 293 >> f() > 294 Hello > 295 Hello > 296 999 > 297 > 298 When the interpreter evaluates f(), it first executes > 299 "twice(print("Hello")); 999" > 300 in the @macro layer. Basically what it does is to just construct its syntax t > 301 But, since we have defined the "twice" function in the @macro layer, it is > 302 execute as a function. Resulting syntax tree is > 303 "print("Hello"); print("Hello"); 999" > 304 and this is executed on the neutral (in this example, @value) layer. > 305 This is the reason why you see two "Hello"s. > 306 > 307 > 308 > 309 [[limitations]] > 310 > 311 This @macro layer is a very primitive one, and not a perfect macro language. > 312 Two major limitations are seen in the following "it" example. > 313 > 314 >> @macro LetItBe(x, y) { let it = x in y }; > 315 > 316 The variable name is not hygenic, and so without any effort, the syntax tree > 317 can access the outer variable "it". > 318 > 319 >> def foo() { LetItBe( 1+2+3, it*it ) } > 320 >> foo() > 321 36 > 322 > 323 Of course, this is not just a limitation; it can sometimes allow us to write > 324 many interesting macros. > 325 > 326 The other problem is that the macro expansion is only done at function startu > 327 So > 328 > 329 >> LetItBe( 1+2+3, it*it ) > 330 ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value > 331 > 332 you cannot directly use the macro in the same scope as the definition. > 333 You need to wrap it up in a function (like the foo() in the above example). > 334 > 335 > 336 > 337 [[quote and unquote]] > 338 > 339 Here is more involved example of code genration. > 340 From "x", it generates "x*x*x*x*x*x*x*x*x*x". > 341 > 342 @macro pow10(x) { > 343 @value( > 344 def pow(x, n) { > 345 if( n == 1 ) { x } > 346 else { > 347 @macro( @value(x) * @value(pow(x,n-1)) ) > 348 } > 349 } > 350 in > 351 pow(@macro(x),10) > 352 ) > 353 }; 133 354 134 to be written | 355 Here, x is a syntax tree but n is an actual integer. If you read carefully, > 356 you should get what is going on. Basically, @macro can be considered like > 357 quasiquoting and @value to be an escape from it.