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