JavaScriptでマクロが使えるというsweet.js を使ってみました。
macro forOf {
case (var $name:ident of $array) $body => {
(function(array) {
for (var i = 0, len = array.length; i < len; i++) {
var $name = array[i];
$body
}
})($array);
}
}
macro nullSafety {
case ($obj . $prop(.)...) => {
$obj == null ? $obj : nullSafety($obj, $prop(.)...)
}
case ($obj(.)..., $prop) => {
$obj(.)....$prop
}
case ($obj(.)..., $p1 . $p2(.)...) => {
$obj(.)....$p1 == null ? $obj(.)....$p1 : nullSafety($obj(.)....$p1, $p2(.)...)
}
}
macro zip {
case ($($n:ident of $array:lit)(,)...) $body => {
(function() {
var len = Math.min($($array.length)(,)...);
for (var i = 0; i < len; i++) {
var $($n = $array[i])(,)...;
$body
}
})();
}
}
forOf (var a of [1,2,3]) {
console.log(a);
}
// (function (array$1) {
// for (var i$3 = 0, len$4 = array$1.length; i$3 < len$4; i$3++) {
// var a$5 = array$1[i$3];
// {
// console.log(a$5);
// }
// }
// }([
// 1,
// 2,
// 3
// ]));
var a = { b: { c: 123 } };
console.log(nullSafety(a.b));
console.log(nullSafety(a.b.c));
console.log(nullSafety(a.b.c.d));
console.log(nullSafety(a.b.c.d.e));
console.log(nullSafety(a.b.c.d.e.f));
// var a = {b: {c: 123}};
// console.log(a == null ? a : a.b);
// console.log(a == null ? a : a.b == null ? a.b : a.b.c);
// console.log(a == null ? a : a.b == null ? a.b : a.b.c == null ? a.b.c : a.b.c.d);
// console.log(a == null ? a : a.b == null ? a.b : a.b.c == null ? a.b.c : a.b.c.d == null ? a.b.c.d : a.b.c.d.e);
// console.log(a == null ? a : a.b == null ? a.b : a.b.c == null ? a.b.c : a.b.c.d == null ? a.b.c.d : a.b.c.d.e == null ? a.b.c.d.e : a.b.c.d.e.f);
var a = [1, 2, 3];
var b = [2, 3, 4, 5];
var c = [3, 4, 5, 6, 7];
zip (x of a, y of b, z of c) {
console.log(x + y + z);
}
// var a = [
// 1,
// 2,
// 3
// ];
// var b = [
// 2,
// 3,
// 4,
// 5
// ];
// var c = [
// 3,
// 4,
// 5,
// 6,
// 7
// ];
// (function () {
// var len$28 = Math.min(a.length, b.length, c.length);
// for (var i$29 = 0; i$29 < len$28; i$29++) {
// var x$30 = a[i$29], y$31 = b[i$29], z$32 = c[i$29];
// {
// console.log(x$30 + y$31 + z$32);
// }
// }
// }());
forOfはES.nextのfor-of です、といってもDense Arrayにしか対応していませんが。$arrayを束縛するために無名関数で囲っています。Closure CompilerのADVANCEDモードを使えばこの関数呼び出しを消せるのですが、マクロ側で何か対処したいですね。Lispのgensym的なことはできないのでしょうか。
次のnullSafetyは途中にnullがあっても安全にプロパティチェーンをたどれるようなコードに展開されます。繰り返しパターンがどのcaseに適用されているのか追いかけるのに苦労しました。
最後のzipはpythonなり配列操作ライブラリによくあるやつです。これはforOfと違い配列を束縛していないので、zip(a of func1(), b of func2()) のようなことをすると関数が何度も呼び出されてしまいます。$array…はargumentsなどに束縛できるのですが、そうすると$n…への代入が書けなくなってしまいました。
あとはLispのunquoteのようにマクロ展開時に式を評価させる方法が見つかりませんでした。
とはいえ色々とおもしろそうなので、隙があれば今のプロダクトで使おうと計画中です。その為にもちゃんとConstなんとかさんのツール群を追いかけて自分で機能追加できるくらいにならなくては。
関連文書:
最近のコメント