2004年 12月 07日

xyzzy io-mode

io-mode.zip, io-mode.l

簡単そうなので作ってみる。殆ど c-mode のパクりなわけだけど……結局インデントレベル計算するところしか作ってないわけで、そしてそれも括弧しか使わない Io では数えるだけなわけで的な。とはいえアフォだからかなり詰ったんですけども orz

ioServer の Regex て何か変じゃありませんか。nextMatch と firstMatch が全く同じ挙動名気がする。つーかマニュアル書くなら効果的なサンプルと一緒に書いて欲しいなって思う。戻り値も書いてないこと多すぎ。むしろ最初から String replace に正規表現とれるようにしれと。正規表現がデフォで使えないとかキツすぎて死にます。

io-mode readme, iolanguage

iolanguage 引数のデフォルト値

リファレンスを見た限りではメソッドの引数を省略したときの値を指定できないっぽい。ようは可変長変数を使うんだと思うんだけど、これまた長い。んなわけで適当にマクロ化するメソッドを定義しとく。もしかしたらこんなことやらないでももっといい方法があるかもしれない。

/*
pos     : 引数の位置
name    : 代入されるスロットのキー (勝手に初期化)
default : デフォルトの値
*/
Object opt := method(pos, name, default,
if (sender doString("thisMessage argAt(" .. pos .. ")")) then (
sender doString(name .. " := sender doMessage(thisMessage argAt(" .. pos .. "))")
) else (
sender setSlot(name, default)
)
)

んで以下のように使う。

List join := method(
opt(0, "sep", "")
ret := ""
self foreach(index, value,
ret = ret .. value
if (index < self count - 1) then (
ret = ret .. sep
)
)
ret
)
l := List clone push("aaa") push("bbb") push("ccc")
l join(", ") print //=> "aaa, bbb, ccc"
l join print //=> "aaabbbccc"

Ruby の Array#join っぽいことをしてみる。 String join というメソッドがあるけど何かこのメソッドは位置がおかしいし、セパレータを引数にとれない。っぽい というのはデフォルト引数が "" きめうちだから。Io に $, がないから (なくていい) ってことです。あーあと再帰的に join してないや。to_s メソッドとかないからその辺もやってないし。ようは List の中身が String 以外だと例外はきますよと。

どうでもいいけど if を書くときに thenelse を使うのは構造的違和感がある。でも可読性はこっちのほうがいいし、case がないうえに if の引数として書く場合 elseif が書けないからどっちにしろ書くことにはなるんだけど。if の引数に全部書くほうはワンライナー向けかしら。

iolanguage Directory items

何で Directory が ioServer なのかはとりあえず置いておいて、Directory items が File しか返さない。Returns a list object containing File and Directory objects ですよ。ついでに list object じゃなくて List object だろうとか思ったけど理解できるからとりあえずフットノート。いや英文解釈が間違っているのかもしれないとか思いつつしかし常識的に考えて (まぁたしかに Directory も File ではあるけど) Directory を File として返さないだろうとか、むしろ File としてしか返さなくて File にタイプを識別するメソッドがなかったら使えないよねって思ったから File にそんなメソッドあるのかなって思ったらなかった。そういや File Primitive にはファイルの更新時間を取得するメソッドもない気が。つまるところ今のデフォルトの Io では blosxom クローンは作れないっぽい。

てか Regexp, Directory を IoVM の Primitive に……

iolanguage メソッドの引数の評価

素朴な疑問にひっかかった。if とか else もメソッドで、引数にメッセージをとるけど、何でこの引数は評価されずに渡されるんだろう。ちょっと解りにくいから実際にコードを書いてみる。

if (Nil) then (
"not print" print
) else (
"print" print
)

この場合もちろん not print は出力されないし、それが願う動作。しかしながら "not print" print も引数だから、メソッドに渡される前に評価されて not print と出力されるんじゃないかと悩んだ。というか正確に言えば if をユーザから定義するときに評価されてしまってハマった。以下にハマったコードを示す

myif := method(test,
ifObj := Object clone
ifObj test := test
ifObj do (
mythen := method(msg,
if (test, sender doMessage(thisMessage argAt(0)))
self
)
myelse := method(msg,
if (test isNil, sender doMessage(thisMessage argAt(0)))
self
)
)
)
myif (Nil) mythen (
"nil" print
) myelse (
"aaa" print
)

これは予想に反して nilnilaaa と出力される。引数が渡される前に評価されしまっているからだ。リファレンス見ててもよくわからないので、適当に書き直していたらできた。書き直した結果を書いてみる。

myif := method(test,
ifObj := Object clone
ifObj test := test
ifObj do (
mythen := method(
if (test, sender doMessage(thisMessage argAt(0)))
self
)
myelse := method(
if (test isNil, sender doMessage(thisMessage argAt(0)))
self
)
)
)

何が変わったかっていうと method の仮引数を書かないようにしただけ。仮引数を書くと評価されてしまうらしい。微妙な罠。プログラミングガイドに明記してもいいじゃん! とはいえこれを踏まえてから読み直すと The thisMessage slot that is preset (see next section) in locals can be used to access the unevaluated argument messages. と書かれていてといっても原文は引用しただけで日本語訳から探した。 (強調はされていない) 頭がよければ thisMessage スロットには未評価なメッセージが入っていて、仮引数を書かなくても呼び出せる。もしかして仮引数を書かなければメッセージは評価されないんじゃないか、なんて推論できる (苦しい) かもしれないけど、俺には無理!

2004年 12月 06日

Programming Language Io

ちょっと触った感じではいい感じ。ソースがそこそこ綺麗に書ける。大規模になったときはわからないけども。全部オブジェクト、と考えていいのかな。以下 Io (プロトタイプベース) と Ruby (クラスベース) と ECMAScript (プロトタイプベース) のコード片を比べてみる。

foo := Object clone
foo test := method(x,
x
)
write(foo test("test"))
foo = Object.clone
def foo.test(x)
x
end
print(foo.test("test"))
foo = new Object;
foo.test = function (x) {
return x;
};
WScript.Echo(foo.test("test"));

ECMAScript は標準出力の方法を定めていないので、ここでは WSH の cscript から実行していることにしてみる。

パッと見た感じ殆ど同じ。Io の場合、スロットに新しく代入するときは := (=setSlot) で = (=updateSlot) は既に存在するスロットを更新する。updateSlot はチェインを辿って見つけたスロットに代入し、該当するスロットがなければ例外になる。と思う。setSlot はレシーバに新しいスロットを作る。ついでに、Io のトップレベルで使われる関数のように見えるものもメソッドで、このメソッドのレシーバは見えない Lobby というもの。全てメッセージ。素敵だ。Ruby も関数のように見えるものは self を省略しただけ。ただ、Io の場合は他の言語では制御構造に見えるものもメッセージ。if とか for とか while も Lobby のメソッド。素敵すぎ!

上のやつは違うみたいだ。Lobby の proto には Object が入ってるから実際には Object に定義されてるメソッドみたい。リファレンスにも getSlot とかは Object に書いてある。

Ruby はクラスベースだからホントは比べにくいと思うけど、とりあえず特異メソッド定義としてみる。特異メソッドは属するところがそのオブジェクト自身になる (普通のメソッドはそのオブジェクトのクラスに属してる) からちょっとプロトタイプっぽい。foo.clone で特異メソッドも引き継げるしね。

ECMAScipt はソレっぽい。ECMAScript の = は常にレシーバにスロットを作るっぽい。自動的にチェインを辿って該当するスロットに代入する方法はないぽい?

関係ないけど、Io のインタプリタを ck から実行すると、実行が終わったあとに全ての出力がクリアされちゃう。ついでに起動するときになんか表示してる半透明ウィンドウが全部フラッシュする。

放り込んだらそのまま動くとか書いてあったので、Linux Binaries をダウンロードして XREA にうぷろーど&実行権限付与。んで適当に foo.io とか作って実行権限とかやってみたけど必要なライブラリが足りないといわれて動かなかった。無念。

ムカツクから鯖上で build できんのかとやってみたけどリソース制限にひっかかって無理だった。もうめんどい。適当にローカルで弄ってよう。

って。ああああああ。新しい鯖だと動く。 s101 で ioServer を動かしてみたらできた。何も苦労せずにできた。泣けるよ。ひどく泣けるよ。

正規表現が標準で使えないのは痛すぎる。やばすぎる。

2004年 12月 03日

Ruby における elsif

Ruby の elsif が嫌い。elsif 書くなら case & when 使う。なんか elsif ってソースのバランスが変。

if a =~ /foo/
# do
elsif a =~ /bar/
# do
elsif a =~ /baz/
# do
end
case
when a =~ /foo/
# do
when a =~ /bar/
# do
when a =~ /baz/
# do
end
2004年 12月 02日

CSS/Ruby

思いつきでごにょったら Ruby のオブジェクトとして再現できた。めでたしめでたし。んでごちゃってみたけど用途すくな。読み込むだけだからなぁ……

2004年 12月 01日

CSS/Ruby

スキャナ&パーサーだけで力尽きた…… racc css.y

ホントはアクション部分も少し書いたんだけど、どうも上手くいかないので削除って、とりあえず分離させておくことにしてみた。パーサーから構文木作るところって普通はどういう風に実装するだろう。再帰定義の部分で汚くなっちゃうんだよなぁ。スーパー簡単なサンプルが欲しい……

あーあと、Invalid なものが突っ込まれたとき、その部分を無視してパースを続ける、っていうのはどうやって書くんだろう。謎ががががが。

パースエラーは error に還元される。だから、右辺の正しい場所に error を置いとけば無視できると。CSS の ruleset を処理中にパースエラーが起きたら ruleset : error とか書いておけばそこを飛ばして次のやつを探す?みたいな? 適当にやってみよう。

error トークン書くと on_error 呼ばれないのか。なんかどういう風にエラーを処理するのかわからん。

2004年 11月 24日

namazu のカスタマイズ

テンプレートに XSLT を使う namazu.cgi の代替を書いて置き換えた。これで namazu だけ HTML4.01 だったり、適用している CSS が違うということがなくなった。

Ruby 拡張ライブラリの search-namazu を使ってクエリ投げて、いったんデータを XML に変換。んでそれを XSLT エンジンに渡してやる。

遠回りだけど、namazu のやつだけ統一感がないのはいくないからこれでよし。もちろん common.xsl が適用されているからスタイルシート追加したきゃ common.xsl を書き換えるだけ。全部変わる!

あーそうだ。Ruby 用の XSLT エンジンがなかったから sablot を使った。何か CGI 経由でコンパイルするっていう方法がずっと頭から抜けてて、Ruby で XSLT エンジンつかえないじゃん!って思ってた。想像力が減ってる。だめだ。

2004年 11月 22日

RDF on Ruby

なにやら w3.org ドメインにあるじゃないですか! っていってもどれほど使えるかわかりませんけど……