1 ########################################
2 print("----------");
3
4 @macro twice = fun(x) { x; x }; # Hello Hello
5 twice( print("Hello") );
6
7 ########################################
8 print("----------");
9
10 @macro maxBad(x,y) {
11 if x<y then y else x
12 };
13 @macro maxGood(x,y) {
14 var _x = x; # NOTE: no hygenic macro
15 var _y = y;
16 if _x < _y then _y else _x
17 };
18 def maxFun(x,y) {
19 if x<y then y else x
20 };
21 @macro maxGreat(x,y){@value(
22 var nx = gensym(); # generate fresh symbol
23 var ny = gensym();
24 @macro _x = @macro(nx) {name: nx}; # cheating to create {is:"Var" .. }
25 @macro _y = @macro(ny) {name: ny}; # at macro layer
26 {is: "Let", name: nx, layer: "", init: @macro(x), expr:
27 {is: "Let", name: ny, layer: "", init: @macro(y), expr:
28 @macro(if _x < _y then _y else _x)}} # the expression
29 )};
30
31 print( maxGood(print(1), print(2)) ); # 1 2 2
32 print( maxBad(print(1), print(2)) ); # 1 2 2 2
33 print( maxFun(print(1), print(2)) ); # 1 2 2
34 print( maxGreat(print(1), print(2)) ); # 1 2 2
35 print( maxGreat(print(2), print(1)) ); # 2 1 2
36
37 ########################################
38 print("----------");
39
40 # the variable "it" is inserted to the scope
41 @macro LetItBe(x, y) { var it = x; y };
42 print( LetItBe("myself", "when I find " ~ it ~ " in times of trouble") );
43
44 ########################################
45 print("----------");
46
47 # layerd parameter can also be used for @macro
48 # you can mix @macro and normal parameters!!
49 def 3way(n, c1 @macro, c2 @macro, c3 @macro)
50 {
51 case n*n
52 when 0: c1
53 when 1: c2
54 when 4: c3
55 };
56
57 3way( rand(3), print("One"), print("Two"), print("Three") );
58 3way( rand(3), print("One"), print("Two"), print("Three") );
59 3way( rand(3), print("One"), print("Two"), print("Three") );
60
61 ########################################
62 print("----------");
63
64 # Conversely, we can mix @value parameter in the macro definition
65 @macro times(n @value, e) { @value(
66 if n == 1 then
67 @macro(e)
68 else
69 @macro(e; times(n-1,e))
70 )};
71 times(7, print("Ichimen no Nanohana"));
72
73 # Here, n is bound to the integer 7, not the AST of it.
74
75 ########################################
76 print("----------");
77
78 # Explicit manipulation of AST.
79 # Reverse the order of arguments of the function call expression
80 @macro reverseArgs(e) {@value(
81 def rev(xs, acc) {
82 case xs when {car:x, cdr:xs}: rev(xs, {car:x, cdr:acc}) when {}: acc
83 };
84 case @macro(e)
85 when {is:"App", fun:f, args:as}: {is:"App", fun:f, args:rev(as,{})}
86 when e : e
87 )};
88 print( reverseArgs(1+2) ); # 2+1 == 3
89 print( reverseArgs(1-2) ); # 2-1 == 1
90
91 ########################################
92 print("----------");
93
94 # Both prints "original". Macro respects the neutral layer's "let y="
95 # and "fun(y)". It does not alter the inner scope y
96 @macro test1(y) { fun(y){y}("original") };
97 @macro test2(y) { let y = "original" in y };
98 print( test1("replaced?") );
99 print( test2("replaced?") );
100
101 ########################################
102 print("----------");
103
104 # Macro expansion is done only at the first call.
105 # So by using @macro parameter, it can remember the argument
106 # of the first call.
107 def remember1( x @macro, y ) { if x == y then "yes" else "no" };
108 print( remember1(1, 1) ); # yes 1 == 1
109 print( remember1(2,1) ); # yes "1" == 1
110 print( remember1(2,2) ); # no "1" != 2
111
112 # exactly the same function, but called in different order
113 def remember2( x @macro, y ) { if x == y then "yes" else "no" };
114 print( remember2(2, 2) ); # yes "2" == 2
115 print( remember2(2, 1) ); # no "2" != 1
116 print( remember2(1, 1) ); # no "2" != 1
117
118 # Is this a good thing or a bad thing??
119
120 ########################################
121 print("----------");
122
123 # Trick to extract the AST of a function
124 def foo(x) { x + x };
125 print( @macro(@value(foo)(arg1)) ); # prints AST for "arg1 + arg1"
126
127 # If we wrote @macro(foo(arg1)), it is the AST of "foo(arg1)"
128 # Here, by @value(foo) we obtain the "usual" behavior of foo,
129 # not the macro-like bahavior to construct AST "foo(??)".
130 # But still, by @macro( ... ) layer, the "usual" function is run in
131 # macro mode.