Diff
Not logged in

Differences From Artifact [6629940451babbd3]:

To Artifact [adcd1590f6f5bc80]:


64 64 | ("var"|"let"|"def"|LAYER) ID "=" E (";"|"in") E 65 65 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" (";"|"in") E 66 66 | ("var"|"let"|"def"|LAYER) ID "=" E 67 67 | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" 68 68 // literal 69 69 | INTEGER 70 70 | STRING 71 - | "{" ENTRYS "}" 72 - | "fun" "(" PARAMS ")" "{" E "}" 71 + | "{" ENTRYS "}" // table 72 + | "fun" "(" PARAMS ")" "{" E "}" // anonymous function 73 73 // function call 74 74 | E "(" ARGS")" 75 75 where ARGS ::= E "," ... "," E 76 76 PARAMS ::= ID LAYER* "," ... "," ID LAYER* 77 77 ENTRYS ::= ID ":" E "," ... "," ID ":" E 78 78 ID ::= 'a-zA-Z0-9_...'+ 79 79 LAYER ::= "@" ID 80 80 // operators 81 81 | "(" E ")" 82 - | E "." ID 83 - | E ".?" ID 82 + | E "." ID // table field access 83 + | E ".?" ID // table field existence check 84 + | E "{" ENTRYS "}" // table extend (pure functionally) 84 85 | E BINOP E 85 86 | "if" "(" E ")" "{" E "}" 86 87 | "if" "(" E ")" "{" E "}" "else "{" E "}" 87 88 // layered exec 88 89 | LAYER "(" E ")" 89 90 90 91 The following are actually rewritten to function calls: 91 92 92 93 - if (E) then{E} else{E} ==> if( E, fun(){E}, fun(){E} ) 93 94 - E BINOP E ==> BINOP(E, E) 94 95 - E.ID ==> . (E, ID) 95 96 - E.?ID ==> .?(E, ID) 96 97 - {} ==> {}() 97 - - {ID:E, ...} ==> .=({...}, ID, E) 98 + - { ENTRIES } ==> {}{ ENTRIES } 99 + - E {ID:E, ...} ==> (.=(E, ID, E)) { ... } 98 100 99 101 Several styles of variable declaration can be used: 100 102 101 103 - fun(x){ fun(y){x} } # K-combinator 102 104 - fun(x){ let f = fun(y){x} in f } # let-in style 103 105 - fun(x){ var f = fun(y){x}; f } # var-; style 104 106 - fun(x){ def f = fun(y){x} in f } # you can use any combination of (let|var|def)-(;|in) ................................................................................ 125 127 - tables: {car: 1, cdr: {car: 2, cdr: {}}} 126 128 - functions: fun(x){x+1} 127 129 as primitive datatypes. Functions capture lexical closures. 128 130 It is almost 'pure' (except the primitve function "print" and some 129 131 trick inside scoping mechanisms). 130 132 131 133 132 -<<Layer>> 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 in 145 + the @LayerName layer. Other than @value, one other predefined layer exists: @macro. 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@value:<REPL>}, 151 + is@value:int, 152 + data@value:1}, 153 + cdr@value:{ 154 + car@value:{pos@value:{lineno@value:3, column@value:11, filename@value:<REPL>}, 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 meaning of 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 the new layer. 177 + Let us define the "@type" layer, where the meaning of programs is their static type. 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 value. 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 layer. 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 function... 272 + 273 + >> foo(1+2) 274 + {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REPL>}, 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 + 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 tree. 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 "y" 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 startup. 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.