CALL STACK を使いたい、のだけど

元々やりたいことは buffer にある expression を read して eval、的なこと。で condition を signal ったら CALL STACK を表示したい。

stack-trace という関数があって、呼び出すと CALL STACK を出力してくれる。のだけど、signal ったのを handler-case なりで拾って stack-trace すると、その時点での CALL STACK、つまり stack-trace の呼び出しのとこからになってしまう。

toggle-trace-on-error で、だと *Trace Output* に出力してくれちゃうので使いにくい、と思ったのだけど、xyzzy は si::*trace-on-error* が non-nil だったら *error-output* に CALL STACK を出力してるだけで、*error-output* を他の stream にしてしまえばそっちに出力させることができた。

(let ((si::*trace-on-error* t)
      (*error-output* *standard-output*))
  (when :true
    (format nil "~A"
            (+ 33 (= :foo :bar)))))
>CALL STACK 17: (= :foo :bar)
>CALL STACK 16: (+ calculating arguments...)
>CALL STACK 15: (format calculating arguments...)
>CALL STACK 14: (progn ((format nil "~A" ...)))
>CALL STACK 13: (if (:true (progn (format nil "~A" ...))))
>CALL STACK 12: (when (:true (format nil "~A" ...)))
>CALL STACK 11: (let (((system:*trace-on-error* t) (*error-output* *standard-output*)) (when :true (format nil "~A" ...))))
>CALL STACK 10: (eval (let ((system:*trace-on-error* t) (*error-output* *standard-output*)) (when :true (format nil "~A" ...))))
>CALL STACK  9: (system:*byte-code ...)
>CALL STACK  8: (eval-region 349 492 #<buffer stream 82383804>)
>CALL STACK  7: (system:*byte-code ...)
>CALL STACK  6: (editor::eval-last-print-sexp1 #<buffer stream 82383804> 349 492)
>CALL STACK  5: (system:*byte-code ...)
>CALL STACK  4: (eval-last-sexp #<buffer stream 82383804>)
>CALL STACK  3: (system:*byte-code ...)
>CALL STACK  2: (#<lexical-closure: eval-print-last-sexp>)
>CALL STACK  1: (command-execute eval-print-last-sexp)
不正なデータ型です: :foo: number

後は

  • handler-case なりで回復したら出力しなくていい。
  • command-execute とか eval-expression とかまではいらない。上の例なら `(when :true ...)` のとこからでいい。

なんだけど、めんどいことになりそうだ。一旦 string-output-stream に出力させて string として取り出したのを parse(?)して、くらいしか思いつかん。