#:g1: not-implementedを充実させる

Posted 2021-12-18 23:08:38 GMT

Lisp一人 Advent Calendar 2021 19日目の記事です。

ブログ記事で未実装の関数定義のHaskellでの取扱い方法を読み、Common Lispでも実現できそうだと思いメモしていましたが、いつの間にか九年程経過していました。
元ブログも消滅してしまったようです……。

さて、not-implementedのようなプレイスホルダー自体はCommon Lispでも良く見掛ける手法で、中身はerrorをあげるものになっていることが殆どかと思います。
今回は、コンパイル時には警告、実行時にはエラー、というマクロを定義してみたいと思います。
おまけでコンパイル時に警告を出すtodofixmeも作成してみます。

(define-condition not-implemented-error (simple-error)
  ())

(define-condition not-implemented-warning (simple-warning) ())

(define-condition todo (simple-warning) ())

(define-condition fixme (simple-warning) ())

(defun get-block-name (env) #+sbcl (caar (sb-c::lexenv-blocks env)) #+lispworks (caar (compiler::compiler-environment-benv env)))

(defmacro not-implemented (&environment env) (let ((fmtargs (list :format-control "~S : not implemented for ~A ~A" :format-arguments (list (get-block-name env) (lisp-implementation-type) (lisp-implementation-version))))) (apply #'warn 'not-implemented-warning fmtargs) `(error 'not-implemented-error ,@(mapcar (lambda (a) `',a) fmtargs))))

(defmacro todo (msg &environment env) (warn 'todo :format-control "~S : TODO : ~A" :format-arguments (list (get-block-name env) msg)) nil)

(defmacro fixme (msg &body body &environment env) (warn 'fixme :format-control "~S : FIXME : ~A" :format-arguments (list (get-block-name env) msg)) `(progn ,@body))

使ってみる

(defun foo (x)
  (not-implemented)
  (todo "ご飯食べてから実装する")
  (fixme "治して……"
    (* 42 x)))

3 compiler notes:

g001992.lisp:109:3: warning: foo : not implemented for SBCL 1.4.12

g001992.lisp:110:3: warning: foo : TODO : ご飯食べてから実装する

g001992.lisp:111:3: warning: foo : FIXME : 治して……

Compilation failed.

(foo 8)
!>> foo : not implemented for LispWorks 8.0.0

まとめ

ブロック名を取得するのにANSI CL規格外機能を利用していますが、その他はマクロ展開時にwarnを出しているだけです。
処理系によってはwarnにブロック名をつけるので不要だったりはするのですが。


HTML generated by 3bmd in LispWorks 8.0.0

comments powered by Disqus