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/14 05:14:10 PST): q と qq は是非ともほしいです!
- Rui(2006/03/14 05:27:38 PST): そうそう、qw//も欲しい。Perlみたいになりそうだけど……。
(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")
- Shiro(2006/12/09 03:12:43 PST): ふと思ったんですが、「最後に改行を含まない文字列」を
ヒアドキュメントで書きたい時どうすればいいんでしょう? Perlの仕様ではそういう
文字列は書けないような気がします。それが本当に出来ないなら、brokenな仕様だと
思います。
ちなみにMIMEではマルチパートの境界は「改行文字、バウンダリ文字列、改行文字」
と定義されているので、最後に改行を含まないbodyも書けます。ヒアドキュメントの
終了も同様に「改行、TAG、改行」と定義すればいいかもしれません。
(list #<<EOF) abc EOF ;; => "abc" (改行なし) (list #<<EOF) abc EOF ;; => "abc\n" (改行あり)
- Rui(2006/12/09 08:25:39 PST): Perlで改行文字で終わらないヒアドキュメントを書く方法は確かになさそうです。
ヒアドキュメントは行指向で最後に改行文字がつく前提のようで、Rubyやシェルもそういう動作でした。行指向なのは歴史的にシェルから輸入した機能だからじゃないかと思っているのですが証拠がみつかりませんでした(調べてみたところ、ヒアドキュメントはVersion 7 (1979)のBourneシェルから存在した機能のようです。最後の改行の扱いについて記述はありませんでした。http://www.in-ulm.de/~mascheck/bourne/ 。これがヒアドキュメントの起源かどうかも不明。)