さくらんぼのlambda日記

lambdaちっくなことからゲーム開発までいろいろ書きます。

複数行の文字列を作成する

そろそろこの題目から抜けだしたかったのですが
どうやら前回の修正でも駄目らしいですorz

ヒアドキュメントを正確に実装するならば
終端を示す文字列は

  • 行頭にある
  • その行はその終端を表す文字列のみである

という条件を満たす必要があるらしいです。

確かにRubyで実際にやってみるとそうなりますね。

s = <<EOS
This is test.

Ruby, the Object Oriented Script Language.
EOSs

とか

s = <<EOS
This is test.

Ruby, the Object Oriented Script Language.
sEOS

と入力してみると、エラーでsに文字列は代入されません。

s = <<EOS
This is test.

Ruby, the Object Oriented Script Language.
EOSs
EOS

こういう入力ですとOKなので、先程の条件通りですね。

では、上記の条件に合わせてリードマクロを変更します。

(defun |#<-reader| (stream sub-char numarg)
  (declare (ignore sub-car numarg))
  (let (chars)
    (do ((curr (read-char stream)
	       (read-char stream)))
	((char= #\newline curr))
      (push curr chars))
    (let* ((pattern (coerce (nreverse chars) 'string))
	   (pointer pattern)
	   (output))
      (do ((curr (read-line stream)
		 (read-line stream)))
	  ((null curr))
	(if (string= pattern curr)
	    (return))
	(setq output (concatenate 'string output curr (make-string 1 :initial-element #\newline))))
      (string-right-trim '(#\Newline) output )
      )))

(set-dispatch-macro-character
 #\# #\< #'|#<-reader|)

ではLet's Try。

(setq hoge #<END
this is 
test
string
END
)
"this is 
test
string"

こんどこそ完成ですね!

ちなみにヒアドキュメントの条件を満たしていない場合にはリーダが動作しつづけてEOFまで読んでしまいエラーになります。
自分で追加した構文にも係らず言語自体のエラーを出してくれるのは有り難いですね。