Rui:ヒアドキュメント

Rui:ヒアドキュメント

SourceForgeのFeature Requestでみつけたので、ヒアドキュメントについて考えてみた。ヒアドキュメント欲しかったのだ。

Perlのヒアドキュメントではこんなふうに書ける。ヒアドキュメントを重ねられることに注意。

print <<EOF1, <<EOF2;
 abc
EOF1
 def
EOF2

このコードは次のコードと同じ意味になる。

print " abc\n", " def\n";

Perlのヒアドキュメントに対して、Checkenの#<<TAGは重ねることができない。#<<TAGのある場所(次の行ではなくて)から文字列が始まる。つまり、文字列を閉じる記号にダブルクオート以外を選べるリーダ拡張にすぎないので、ヒアドキュメントというよりは、Perlのq/STRING/や、Pythonの...のほうが機能的に近い。

Perl式のヒアドキュメントを実現しようとすると、#<<TAGが現れたとき、まず行の残りの部分をどこかにとっておいた上で、次の行から"TAG"単独の行までを読んで返す必要がある。次にreadを実行したときは、保存しておいた行の残り部分から読み込まないといけない。これはポートに無制限に文字をプッシュバックできれば簡単だけど、そういう機能はないので、実現がちょっと難しい。

Checkenの#<<TAGや、Perlのq/STRING/、Pythonの...などは実現が簡単。

でもどちらかといえば欲しいのはPerl式のヒアドキュメントなのだ。ヒアドキュメントでなければ、行という概念にとらわれず、q/STRING/を実装したほうがよい気がする。ということをChicken式のを実装して思いましたよ。オイオイ。

(2006/03/15 02:32:13 PST)

改めてPerl式のヒアドキュメント実装してみました。

無制限のプッシュバックを許す代わりに、ポートをスタックできるようにしました。ポートにスタックを設けて、そこに別のポートをプッシュできるようにします。スタックが空でなければ、読み出しはスタックトップのポートから行われます。スタックトップのポートがEOFを返すと、そのポートはスタックから取り除かれ、次のスタックトップのポートから改めて読み出しが行われます。スタックがない場合の動作は現状と同じです。

上記のメカニズムを利用して、行の残りの部分を文字列として保存しておき、ヒアドキュメント本体を読み込んだ後、文字列ポートを元のポートにプッシュします。これによって、行の残りの部分が再度ポートから得られるようにしています。

上のアイデアはSFIOからもらっているのですが、実はあまり気に入っていません。もっと一般的な方法がありそうな。実験的ですがパッチ。標準でサポートされていないリーダ拡張を実際のプログラムで使うと後で苦労することになるので、その点注意してください。

なお構文ですが、#<<TAGと#<<`TAGをサポートします。後者は#`"..."に対応します。次のように使えます。

gosh> #<<EOF
abc
EOF
;;  => "abc\n"

gosh> #<<`EOF
,(gauche-version)
EOF
;;  => "0.8.7_pre1\n"

gosh> (list #<<EOF #<<`EOF)
abc
EOF
,(gauche-version)
EOF
;;  => ("abc\n" "0.8.7_pre1\n")
More ...