Hatena::Groupcadr

kozima の日記

2010-01-07

eval-print-last-sexp の出力を逆引き CL 書式に

| 00:01

改造してみた。わりと強引だし,うまくいかない例は作ればたくさんありますが。

(defun mylib-eval-last-sexp-to-string ()
  (let ((res (make-string-output-stream))
        (out (make-string-output-stream)))
    (let ((*standard-output* out))
      (eval-last-sexp res))
    (values (get-output-stream-string res)
            (get-output-stream-string out))))

(defun mylib-eval-print-last-sexp ()
  (interactive "*")
  (multiple-value-bind (result output)
      (mylib-eval-last-sexp-to-string)
    (flet ((format-output (string stream)
             (when (plusp (length string))
               (format stream "~&~{;-> ~A~%~@{;   ~A~%~}~}"
                       (split-string string "\n" t))))
           (format-result (string stream)
             (if (plusp (length string))
                 (format stream "~&~{;=> ~A~%~@{;   ~A~%~}~}"
                         (split-string string "\n" t))
               (format stream "~&;=> No value~%"))))
      (with-output-to-selected-buffer
        (format-output output *standard-output*)
        (format-result result *standard-output*)))))

2009-10-21

with-narrow-to-region

| 23:59

ふと、頻出パターンなのにマクロになってないのはなんでだろうと思った。

(defmacro with-narrow-to-region ((from to) &body body)
  `(save-restriction
     (narrow-to-region ,from ,to)
     ,@body))

一行しか違わないんだからマクロにするまでもない、といわれればそうかもしれません。

外側に save-excursion もつけたバージョンがあってもいいかも。

2009-09-25

自作制御構造のインデント

| 20:45

マクロ定義の引数リストに &body があったら勝手にインデントをそれっぽくするようにするとどうだろうと思って、とりあえず xyzzy で適当にやってみました。

(shadow 'defmacro "user")

(lisp::defmacro defmacro (name (&rest lambda-list) &body body)
  (let* ((p1 (position '&body lambda-list))
         (pos (and p1
                   (count-if-not (lambda (x)
                                   (member x lambda-list-keywords))
                                 lambda-list
                                 :end p1))))
    ` (progn
        ,(when pos `(setf (get ',name 'lisp-indent-hook) ,pos))
        (lisp::defmacro ,name ,lambda-list ,@body))))

(setf (get 'defmacro 'lisp-indent-hook) 'defun)

(defmacro awhen (test &body body)
  `(let ((it ,test))
     (when it ,@body)))

(awhen 'hoge
  (print it))

emacs でも似たようなことはできると思いますが、もともと declaration の部分で指定できたと思うので必要ないかもしれません。

2009-08-22

bug in compiler?

| 19:09

handler-case が bug ってる? - 日々ごちゃごちゃと考える に書いてあった関数を何も考えずに disassemble してみました。

Function test:
stack frame max:    3
stack depth max:    3
argument list:      (x)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   3: make-closure              (lambda (x) x)
   5: const-nil                 
   6: adjust-stack              0
   8: const-nil                 
   9: local-set-discard         LOCALVAR-1
  11: list-n                    0
  13: global-ref                system:*condition-handlers*
  15: cons                      
  16: local-set-discard         LOCALVAR-2
  21: special                   30, (system:*condition-handlers*)
  22: local-ref                 LOCALVAR-2
  24: adjust-stack              2
  26: local-ref                 x
  28: goto                      34
  30: discard                   
  31: const-nil                 
  32: goto                      36
  34: list-multiple-value       
  35: call-multiple-value       
  36: RET                       

22, 26 で (nil (((or error reader-error quit) . #<lexical-closure: (anonymous)>)))x がスタックに積まれて、これが funcall されるからエラー、ということなのでしょうか。

xyzzy lisp のバイトコードの仕様をだいぶ忘れていますが、adjust-stack の引数が変なような……。

2009-08-07

コマンドの dispatch

| 22:32

id:knenet:20090807:1249610063 に反応してみる。

この手のことをやりたいとき、こんな感じのやり方をわりと見かけるような気がします。

(defvar *region-op-map* nil)
(unless *region-op-map*
  (let ((keymap (make-sparse-keymap)))
    (mapc (lambda (x) (define-key keymap (car x) (cadr x)))
          '((#\C-w kill-region)
            (#\C-g quit)
            (#\w copy-region-as-kill)
            ;; etc, etc.
            ))
    (setf *region-op-map* keymap)))

(global-set-key #\C-w *region-op-map*)

細かい挙動は違います。こちらの方が簡単ですが、二つ目のキーを dispatch するところで挙動の自由度が低い(というかほとんどない)のです。