423f308350 2010-11-07 kinaba: ----------------------------------------------------------------------------- 423f308350 2010-11-07 kinaba: Polemy 0.1.0 423f308350 2010-11-07 kinaba: by k.inaba (www.kmonos.net) 515502e8d1 2010-11-20 kinaba: Nov 20, 2010 423f308350 2010-11-07 kinaba: ----------------------------------------------------------------------------- 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: <<How to Build>> 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: - Install DMD 423f308350 2010-11-07 kinaba: http://www.digitalmars.com/d/2.0/changelog.html 515502e8d1 2010-11-20 kinaba: Version 2.050 is recommended. Older or newer version may not work. 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: - Build 423f308350 2010-11-07 kinaba: (for Windows) Run build.bat 423f308350 2010-11-07 kinaba: (for Unix) Run build.sh 423f308350 2010-11-07 kinaba: or use your favorite build tools upon main.d and polemy/*.d. 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: Then you will get the executable "polemy" in the "bin" directory. 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: <<License>> 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: d2stacktrace/* 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: is written by Benjamin Thaut and licensed under 2-clause BSD License. 423f308350 2010-11-07 kinaba: See http://3d.benjamin-thaut.de/?p=15 for the detail. 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: (this package is used only for enabling stack-traces during printing exceptions; c48ba67854 2010-11-08 kinaba: it is not used for release builds.) 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: polemy/* 423f308350 2010-11-07 kinaba: main.d 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: All the other parts are written by Kazuhiro Inaba and 423f308350 2010-11-07 kinaba: licensed under NYSL 0.9982 ( http://www.kmonos.net/nysl/ ). 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: <<How to Use>> 423f308350 2010-11-07 kinaba: 9eec42eba1 2010-11-09 kinaba: > polemy 9eec42eba1 2010-11-09 kinaba: starts REPL 9eec42eba1 2010-11-09 kinaba: 9eec42eba1 2010-11-09 kinaba: > polemy foo.pmy 9eec42eba1 2010-11-09 kinaba: executes foo.pmy 9eec42eba1 2010-11-09 kinaba: 515502e8d1 2010-11-20 kinaba: > polemy -l foo.pmy 515502e8d1 2010-11-20 kinaba: after executing foo.pmy, starts REPL 515502e8d1 2010-11-20 kinaba: 3464a035ec 2010-11-20 kinaba: > polemy -l foo.pmy -l bar.pmy buz.pmy 3464a035ec 2010-11-20 kinaba: executes foo.pmy, bar.bmy, and then buz.pmy 3464a035ec 2010-11-20 kinaba: 9eec42eba1 2010-11-09 kinaba: 9eec42eba1 2010-11-09 kinaba: 515502e8d1 2010-11-20 kinaba: <<Syntax>> 9eec42eba1 2010-11-09 kinaba: 515502e8d1 2010-11-20 kinaba: Comment is "# ... \n" 9eec42eba1 2010-11-09 kinaba: 515502e8d1 2010-11-20 kinaba: E ::= 515502e8d1 2010-11-20 kinaba: // declaration 515502e8d1 2010-11-20 kinaba: | ("var"|"let"|"def"|LAYER) ID "=" E (";"|"in") E 515502e8d1 2010-11-20 kinaba: | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" (";"|"in") E 515502e8d1 2010-11-20 kinaba: | ("var"|"let"|"def"|LAYER) ID "=" E 515502e8d1 2010-11-20 kinaba: | ("var"|"let"|"def"|LAYER) ID "(" PARAMS ")" "{" E "}" 515502e8d1 2010-11-20 kinaba: // literal 515502e8d1 2010-11-20 kinaba: | INTEGER 515502e8d1 2010-11-20 kinaba: | STRING 435fa085ec 2010-11-21 kinaba: | "{" ENTRYS "}" // table 435fa085ec 2010-11-21 kinaba: | "fun" "(" PARAMS ")" "{" E "}" // anonymous function 515502e8d1 2010-11-20 kinaba: // function call 515502e8d1 2010-11-20 kinaba: | E "(" ARGS")" 515502e8d1 2010-11-20 kinaba: where ARGS ::= E "," ... "," E 515502e8d1 2010-11-20 kinaba: PARAMS ::= ID LAYER* "," ... "," ID LAYER* 515502e8d1 2010-11-20 kinaba: ENTRYS ::= ID ":" E "," ... "," ID ":" E 515502e8d1 2010-11-20 kinaba: ID ::= 'a-zA-Z0-9_...'+ 515502e8d1 2010-11-20 kinaba: LAYER ::= "@" ID 515502e8d1 2010-11-20 kinaba: // operators 9eec42eba1 2010-11-09 kinaba: | "(" E ")" 435fa085ec 2010-11-21 kinaba: | E "." ID // table field access 435fa085ec 2010-11-21 kinaba: | E ".?" ID // table field existence check 435fa085ec 2010-11-21 kinaba: | E "{" ENTRYS "}" // table extend (pure functionally) 9eec42eba1 2010-11-09 kinaba: | E BINOP E 9eec42eba1 2010-11-09 kinaba: | "if" "(" E ")" "{" E "}" 9eec42eba1 2010-11-09 kinaba: | "if" "(" E ")" "{" E "}" "else "{" E "}" 515502e8d1 2010-11-20 kinaba: // layered exec 515502e8d1 2010-11-20 kinaba: | LAYER "(" E ")" 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: The following are actually rewritten to function calls: 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: - if (E) then{E} else{E} ==> if( E, fun(){E}, fun(){E} ) 515502e8d1 2010-11-20 kinaba: - E BINOP E ==> BINOP(E, E) 515502e8d1 2010-11-20 kinaba: - E.ID ==> . (E, ID) 515502e8d1 2010-11-20 kinaba: - E.?ID ==> .?(E, ID) 515502e8d1 2010-11-20 kinaba: - {} ==> {}() 435fa085ec 2010-11-21 kinaba: - { ENTRIES } ==> {}{ ENTRIES } 435fa085ec 2010-11-21 kinaba: - E {ID:E, ...} ==> (.=(E, ID, E)) { ... } 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: Several styles of variable declaration can be used: 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: - fun(x){ fun(y){x} } # K-combinator 515502e8d1 2010-11-20 kinaba: - fun(x){ let f = fun(y){x} in f } # let-in style 515502e8d1 2010-11-20 kinaba: - fun(x){ var f = fun(y){x}; f } # var-; style 515502e8d1 2010-11-20 kinaba: - fun(x){ def f = fun(y){x} in f } # you can use any combination of (let|var|def)-(;|in) 515502e8d1 2010-11-20 kinaba: - fun(x){ def f(y){x} in f } # syntax sugar for function declaration 515502e8d1 2010-11-20 kinaba: - fun(x){ let f(y){x}; f } # this is also ok 515502e8d1 2010-11-20 kinaba: - fun(x){ var f(y){x} } # omitting (;|in) returns the last declared object directly 515502e8d1 2010-11-20 kinaba: - fun(x,y){x} #< this is not equal to the above ones. functions are no curried. 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: NOTE: Theres no "let rec" syntax, but still recursive definition works 515502e8d1 2010-11-20 kinaba: def f(x) { if(x==0){1}else{x*f(x-1)} } in f(10) #=> 3628800 515502e8d1 2010-11-20 kinaba: yet still the code below also works 515502e8d1 2010-11-20 kinaba: def x=21 in def x=x+x in x #=> 42. 515502e8d1 2010-11-20 kinaba: The internal scoping mechanism is a little tricky (this is for coping with 515502e8d1 2010-11-20 kinaba: the "layer" feature explained below), but I hope that it works as everyone 515502e8d1 2010-11-20 kinaba: expects in most cases, as long as you don't use the same-name-variables heavily :). 515502e8d1 2010-11-20 kinaba: c1f2717799 2010-11-21 kinaba: (Experimental) pattern matching is also available. Here is an example. c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: def adjSum(lst) c1f2717799 2010-11-21 kinaba: { c1f2717799 2010-11-21 kinaba: case( lst ) c1f2717799 2010-11-21 kinaba: when( {car:x, cdr:{car: y, cdr:z}} ) { {car: x+y, cdr: adjSum(z)} } c1f2717799 2010-11-21 kinaba: when( {car:x, cdr:{}} ) { {car: x, cdr: {}} } c1f2717799 2010-11-21 kinaba: when( {} ) { {} } c1f2717799 2010-11-21 kinaba: }; c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: It is expanded to a sequence of if-then-elses prefering the first-match. c1f2717799 2010-11-21 kinaba: Note that {a: _} pattern matches all the tables that have the .a field. c1f2717799 2010-11-21 kinaba: It also matches to {a: 123, b: 456} having extra .b field. So, changing the c1f2717799 2010-11-21 kinaba: order of "when"s in the above code changes the behavior. c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: <<Basic Features>> 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: Polemy is an untyped functional programming language that has 515502e8d1 2010-11-20 kinaba: - integers: 0, 123, 456666666666666666666666666666666666666789, ... 515502e8d1 2010-11-20 kinaba: - strings: "hello, world!\n", ... 515502e8d1 2010-11-20 kinaba: - tables: {car: 1, cdr: {car: 2, cdr: {}}} 515502e8d1 2010-11-20 kinaba: - functions: fun(x){x+1} 515502e8d1 2010-11-20 kinaba: as primitive datatypes. Functions capture lexical closures. 515502e8d1 2010-11-20 kinaba: It is almost 'pure' (except the primitve function "print" and some 515502e8d1 2010-11-20 kinaba: trick inside scoping mechanisms). 515502e8d1 2010-11-20 kinaba: 515502e8d1 2010-11-20 kinaba: 435fa085ec 2010-11-21 kinaba: <<Layers :: Overview>> 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Polemy's runtime environment has many "layer"s. 435fa085ec 2010-11-21 kinaba: Usual execution run in the @value layer. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> 1 + 2 435fa085ec 2010-11-21 kinaba: 3 435fa085ec 2010-11-21 kinaba: >> @value( 1 + 2 ) 435fa085ec 2010-11-21 kinaba: 3 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Here you can see that @LayerName( Expression ) executes the inner Expression in 435fa085ec 2010-11-21 kinaba: the @LayerName layer. Other than @value, one other predefined layer exists: @macro. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @macro( 1+2 ) 435fa085ec 2010-11-21 kinaba: {pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, 435fa085ec 2010-11-21 kinaba: is@value:app, c1f2717799 2010-11-21 kinaba: args@value:{car@value:{pos@value:{lineno@value:3, column@value:9, filename@value:<REPL>}, 435fa085ec 2010-11-21 kinaba: is@value:int, 435fa085ec 2010-11-21 kinaba: data@value:1}, 435fa085ec 2010-11-21 kinaba: cdr@value:{ 435fa085ec 2010-11-21 kinaba: car@value:{pos@value:{lineno@value:3, column@value:11, filename@value:<REPL>}, 435fa085ec 2010-11-21 kinaba: is@value:int, 435fa085ec 2010-11-21 kinaba: data@value:2}, 435fa085ec 2010-11-21 kinaba: cdr@value:{}}}, 435fa085ec 2010-11-21 kinaba: fun@value:{pos@value:{lineno@value:3, column@value:10, filename@value:<REPL>}, 435fa085ec 2010-11-21 kinaba: is@value:var, 435fa085ec 2010-11-21 kinaba: name@value:+}} 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: (Sorry, this pretty printing is not available on the actual interpreter...) 435fa085ec 2010-11-21 kinaba: This evaluates the expression 1+2 in the @macro layer. In this layer, the meaning of 435fa085ec 2010-11-21 kinaba: the program is its abstract syntax tree. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: You can interleave layers. 435fa085ec 2010-11-21 kinaba: The root node of the abstract syntax tree is function "app"lication. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @value(@macro( 1+2 ).is) 435fa085ec 2010-11-21 kinaba: app 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: <<Layers :: Defining a new layer>> 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: To define a new layer, you should first tell how to "lift" existing values two the new layer. 435fa085ec 2010-11-21 kinaba: Let us define the "@type" layer, where the meaning of programs is their static type. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @@type = fun(x) { 435fa085ec 2010-11-21 kinaba: >> if( _isint(x) ) { "int" } else { 435fa085ec 2010-11-21 kinaba: >> if( _isfun(x) ) { x } else { "unknown" } } 435fa085ec 2010-11-21 kinaba: >> } 435fa085ec 2010-11-21 kinaba: (Note: polemy REPL may warn some exception here but please ignore) 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: For simplicity, I here deal only with integers. 435fa085ec 2010-11-21 kinaba: _isint is a primitive function of Polemy that checks the dynamic type of a value. 435fa085ec 2010-11-21 kinaba: For function, leaving it untouched works well for almost all layers. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @type( 1 ) 435fa085ec 2010-11-21 kinaba: int 435fa085ec 2010-11-21 kinaba: >> @type( 2 ) 435fa085ec 2010-11-21 kinaba: int 435fa085ec 2010-11-21 kinaba: >> @type( "foo" ) 435fa085ec 2010-11-21 kinaba: unknown 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Fine! Let's try to type 1+2. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @type( 1 + 2 ) 435fa085ec 2010-11-21 kinaba: ...\value.d(119): [<REPL>:6:8] only @value layer can call native function 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Note that the behavior of this program is 435fa085ec 2010-11-21 kinaba: - run 1+2 in the @type layer 435fa085ec 2010-11-21 kinaba: and NOT 435fa085ec 2010-11-21 kinaba: - run 1+2 in @value and obtain 3 and run 3 in the @type. 435fa085ec 2010-11-21 kinaba: The problem is, the variable "+" is defined only in the @value layer. 435fa085ec 2010-11-21 kinaba: To carry out computation in the @type layer. We need to define it also 435fa085ec 2010-11-21 kinaba: in the @type layer. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: To define some variable in a specific layer, use @LayerName in place of 435fa085ec 2010-11-21 kinaba: (let|var|def)s. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> let x = 2 435fa085ec 2010-11-21 kinaba: >> @value x = 2 435fa085ec 2010-11-21 kinaba: >> @type x = "int" 435fa085ec 2010-11-21 kinaba: >> @hoge x = "fuga" 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: For "+", do it like this. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @type "+" = fun(x,y) {@value( 435fa085ec 2010-11-21 kinaba: >> if( @type(x)=="int" && @type(y)=="int" ) { "int" } else { "typeerror" } 435fa085ec 2010-11-21 kinaba: >> )} 435fa085ec 2010-11-21 kinaba: polemy.value.native!(IntValue,IntValue,IntValue).native.__anonclass24 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: It is just computing the return type from the input type. 435fa085ec 2010-11-21 kinaba: Not here that the intended "meaning" of if-then-else is the runtime-branching, 435fa085ec 2010-11-21 kinaba: and the meaning of "==" is the value-comparison. These are the @value layer 435fa085ec 2010-11-21 kinaba: behavior. So we have defined the function body inside @value layer. 435fa085ec 2010-11-21 kinaba: But when we refer the variables x and y, we need its @type layer meaning. 435fa085ec 2010-11-21 kinaba: Hence we use @type() there. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Now we get it. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @type( 1 + 2 ) 435fa085ec 2010-11-21 kinaba: int 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Well, but do we have to define the @type layer meaning for every variables??? 435fa085ec 2010-11-21 kinaba: No. After you defined @type "+", you'll automatically get the following: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> def double(x) { x + x } 435fa085ec 2010-11-21 kinaba: (function:17e4740:1789720) 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @type( double(123) ) 435fa085ec 2010-11-21 kinaba: int 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Every user-defined functions are automatically "lift"ed to the appropriate layer. 435fa085ec 2010-11-21 kinaba: Only primitive functions like "+" requires @yourNewLayer annotation. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: <<Layers :: neutral-layer>> 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: let|var|def is to define a variable in the "current" layer. 435fa085ec 2010-11-21 kinaba: Not necessary to the @value layer. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @value( let x = 1 in @value(x) ) 435fa085ec 2010-11-21 kinaba: 1 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @macro( let x = 1 in @value(x) ) 435fa085ec 2010-11-21 kinaba: polemy.failure.RuntimeException: [<REPL>:14:29] variable x not found 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @macro( let x = 1 in @macro(x) ) 435fa085ec 2010-11-21 kinaba: {pos@value:{lineno@value:15, ... 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: <<Layers :: Layered-Parameters>> 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> def foo(x @macro @value) { {fst: x, snd: @macro(x)} } 435fa085ec 2010-11-21 kinaba: (function:1730360:1789720) 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: If you annotate function parameters by @LayerNames, when you invoke the function... 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> foo(1+2) 435fa085ec 2010-11-21 kinaba: {snd@value: {pos@value:{lineno@value:17, column@value:5, filename@value:<REPL>}, 435fa085ec 2010-11-21 kinaba: is@value:app, arg@value:{... 435fa085ec 2010-11-21 kinaba: /fst@value:3 435fa085ec 2010-11-21 kinaba: /} 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: its corresponding arguments are evaluated in the layer and passed to it. 435fa085ec 2010-11-21 kinaba: If you specify multiple layers, the argument expression is run multiple times. 435fa085ec 2010-11-21 kinaba: If you do not specify any layer for a parameter, it works in the neutral layer. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: <<@macro layer>> 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: When function is invoked, it first run in the @macro layer, and after that, 435fa085ec 2010-11-21 kinaba: it run in the neutral layer. Here is an example. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @macro twice(x) { x; x } 435fa085ec 2010-11-21 kinaba: >> def f() { twice(print("Hello")); 999 } 435fa085ec 2010-11-21 kinaba: (function:173b6a0:1789720) 435fa085ec 2010-11-21 kinaba: >> f() 435fa085ec 2010-11-21 kinaba: Hello 435fa085ec 2010-11-21 kinaba: Hello 435fa085ec 2010-11-21 kinaba: 999 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: When the interpreter evaluates f(), it first executes 435fa085ec 2010-11-21 kinaba: "twice(print("Hello")); 999" 435fa085ec 2010-11-21 kinaba: in the @macro layer. Basically what it does is to just construct its syntax tree. 435fa085ec 2010-11-21 kinaba: But, since we have defined the "twice" function in the @macro layer, it is 435fa085ec 2010-11-21 kinaba: execute as a function. Resulting syntax tree is 435fa085ec 2010-11-21 kinaba: "print("Hello"); print("Hello"); 999" 435fa085ec 2010-11-21 kinaba: and this is executed on the neutral (in this example, @value) layer. 435fa085ec 2010-11-21 kinaba: This is the reason why you see two "Hello"s. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: [[limitations]] 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: This @macro layer is a very primitive one, and not a perfect macro language. 435fa085ec 2010-11-21 kinaba: Two major limitations are seen in the following "it" example. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> @macro LetItBe(x, y) { let it = x in y }; 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: The variable name is not hygenic, and so without any effort, the syntax tree "y" 435fa085ec 2010-11-21 kinaba: can access the outer variable "it". 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> def foo() { LetItBe( 1+2+3, it*it ) } 435fa085ec 2010-11-21 kinaba: >> foo() 435fa085ec 2010-11-21 kinaba: 36 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Of course, this is not just a limitation; it can sometimes allow us to write 435fa085ec 2010-11-21 kinaba: many interesting macros. 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: The other problem is that the macro expansion is only done at function startup. 435fa085ec 2010-11-21 kinaba: So 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: >> LetItBe( 1+2+3, it*it ) 435fa085ec 2010-11-21 kinaba: ...\value.d(173): [<REPL>:24:1] variable LetItBe is not set in layer @value 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: you cannot directly use the macro in the same scope as the definition. 435fa085ec 2010-11-21 kinaba: You need to wrap it up in a function (like the foo() in the above example). 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: [[quote and unquote]] 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Here is more involved example of code genration. 435fa085ec 2010-11-21 kinaba: From "x", it generates "x*x*x*x*x*x*x*x*x*x". 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: @macro pow10(x) { 435fa085ec 2010-11-21 kinaba: @value( 435fa085ec 2010-11-21 kinaba: def pow(x, n) { 435fa085ec 2010-11-21 kinaba: if( n == 1 ) { x } 435fa085ec 2010-11-21 kinaba: else { 435fa085ec 2010-11-21 kinaba: @macro( @value(x) * @value(pow(x,n-1)) ) 435fa085ec 2010-11-21 kinaba: } 435fa085ec 2010-11-21 kinaba: } 435fa085ec 2010-11-21 kinaba: in 435fa085ec 2010-11-21 kinaba: pow(@macro(x),10) 435fa085ec 2010-11-21 kinaba: ) 435fa085ec 2010-11-21 kinaba: }; 435fa085ec 2010-11-21 kinaba: 435fa085ec 2010-11-21 kinaba: Here, x is a syntax tree but n is an actual integer. If you read carefully, 435fa085ec 2010-11-21 kinaba: you should get what is going on. Basically, @macro can be considered like 435fa085ec 2010-11-21 kinaba: quasiquoting and @value to be an escape from it. c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: <<Primitives>> c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: {} 0-ary create-empty-table c1f2717799 2010-11-21 kinaba: . 2-ary table-get c1f2717799 2010-11-21 kinaba: .? 2-ary table-has? c1f2717799 2010-11-21 kinaba: .= 3-ary table-set c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: if 3-ary if-then-else c1f2717799 2010-11-21 kinaba: 5e924caac9 2010-11-23 kinaba: + - * / % || && 2-ary integer-operations (NOTE! no short-circuit for && and ||.) c1f2717799 2010-11-21 kinaba: < > <= >= == != 2-ary generic comparison 5e924caac9 2010-11-23 kinaba: ~ 2-ary string concatenation (works also for non-string objects) c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: print 1-ary print-to-stdout c1f2717799 2010-11-21 kinaba: c1f2717799 2010-11-21 kinaba: _isint _isstr _isfun _isundefined _istable 1-ary dynamic-type-test c1f2717799 2010-11-21 kinaba: