Cyanのマクロの基本
マクロで式を作る時、Lispと同じく準クオートとアンクオートを使うのが簡単だけど、もう1つPorter.new()やMessenger.new()を使う方法がある。
cyan> p = '(a b c) => a(b(c)) cyan> p.slots() => %{ callee => a, args => &(b(c)), parent => #<Porter> } cyan> m = '(a + b + c) => a.(+)(b).(+)(c) cyan> m.slots() => %{ receiver => a.(+)(b), args => &(c), message => (+), parent => #<Messenger> }
上の関数適用の形の式がPorterで、下のメソッド呼び出しの形の式がMessenger。
生成するには、Porter.new(callee, args), Messenger(receiver, message, args)とする。
例
def(mkblock)^(list): `begin(?Block.new(list)) mac(p2m)^(body): mkblock body.list.map^(p): m := Messenger.new(p.callee, p.args[0].callee, &(p.args[0].args[0])) `(say ?p.to_s() + " => " + ?m.to_s() + " = " + (?m).to_s()) def(test)^: p2m: 10 rem 4 20 rem 5 28 rem 6
Block.newは、式のリスト[exp1, exp2, ... , expN]を受け取ってブロック{ exp1, exp2, ... ,expN }を返す。で、begin関数はブロックを受け取って、中の式を順番に評価する。
実行
cyan> test() 10(rem(4)) => 10.rem(4) = 2 20(rem(5)) => 20.rem(5) = 0 28(rem(6)) => 28.rem(6) = 4 => "28(rem(6)) => 28.rem(6) = 4"
メソッド呼び出しの式(Messenger)を作る時、messageを可変にしたい場合に準クオート&アンクオートを使おうとしても
cyan> mac(bad)^(mes): `(5.?mes(3)) (stdin):1: error: syntax error: unexpected Unquote, expecting Symbol cyan> mac(bad)^(mes): `(5.?(mes)(3)) (stdin):1: error: syntax error: unexpected Unquote, expecting Symbol cyan> mac(bad)^(mes): `(5.(?mes)(3)) (stdin):1: error: syntax error: unexpected Unquote, expecting Operator
書きようがないのでMessenger.new()を使いましょう、ということでよいのかな。
参考: 擬似クラス