with-exception-handler の仕様を正しく理解しよう その4
Gauche は大まかに srfi-18 の仕様に従っているらしい。
さて実装を追う。
ScmObj Scm_VMWithExceptionHandler(ScmObj handler, ScmObj thunk) { ScmObj current = theVM->exceptionHandler; ScmObj before = Scm_MakeSubr(install_xhandler, handler, 0, 0, SCM_FALSE); ScmObj after = Scm_MakeSubr(install_xhandler, current, 0, 0, SCM_FALSE); return Scm_VMDynamicWind(before, thunk, after); }
static ScmObj install_xhandler(ScmObj *args, int nargs, void *data) { theVM->exceptionHandler = SCM_OBJ(data); return SCM_UNDEFINED; }
ふむ。before/after はそれぞれ current-exception-handler をセットする Scheme の世界の手続き。
ふむ。 dynamic-wind で thunk が戻ったときに current-exception-handler を元に戻すと。
Scm_VMDynamicWind の実装はどうなっているだろうか。
static ScmCContinuationProc dynwind_before_cc; static ScmCContinuationProc dynwind_body_cc; static ScmCContinuationProc dynwind_after_cc; ScmObj Scm_VMDynamicWind(ScmObj before, ScmObj body, ScmObj after) { void *data[3]; /* NB: we don't check types of arguments, since we allo object-apply hooks can be used for them. */ data[0] = (void*)before; data[1] = (void*)body; data[2] = (void*)after; Scm_VMPushCC(dynwind_before_cc, data, 3); return Scm_VMApply0(before); }
ふむ。Scm_VMPushCC が肝か。
/* Arrange C function AFTER to be called after the procedure returns. * Usually followed by Scm_VMApply* function. */
なるほど。
これは真似できるな。
ところで Scheme の世界の dynamic-wind とこれの Scm_VMDynamicWind は同一のものだろうか。
同一のものだった。
ふむむ。(見た目の上だけど)こんなに簡単なのだろうか。
思いついた疑問点はメモしておいて ypsilon に進もう。
ypsilon の with-exception-handler の実装を見る
(define with-exception-handler (lambda (new thunk) (let ((parent (current-exception-handler))) (parameterize ((current-exception-handler (lambda (condition) (parameterize ((current-exception-handler parent)) (new condition))))) (thunk)))))
お。 Scheme で書かれていてシンプルだ。
parameterize が分からない。
srfi-39 か。うーん。難しい。逃げたらだめよ。
おーなるほど。 parameterize は dynamic environment の値を上書きできるのか。
ついでに dynamic-wind も Scheme だ。
(define dynamic-wind (lambda (in body out) (in) (current-dynamic-wind-record (cons (cons in out) (current-dynamic-wind-record))) (call-with-values body (lambda ans (current-dynamic-wind-record (cdr (current-dynamic-wind-record))) (out) (apply values ans)))))
これらは正しく仕様通り動くんだろうか。まだ判断できるだけの力がないなあ。
ypsilon は parameterize を活用しまくっている。
うは parameterize は dynamic-wind で実装されてた。もうわけわかめだわ。
ほとんどの問題点が dynamic-wind に通じることがよく分かった。
このあたりを読めって感じだな。→http://www.scheme.com/tspl3/control.html#./control:h5