ansify 0.02.00 ごちゃごちゃ更新

パッケージ "ansify" とは別に パッケージ "ansify.ext" を作っりました。ANSI 標準以外の物はこっちから export するようにしま(す|した)。

"ansify.ext" からは以下の関数が export されてます。

  • ansify.ext:optimize-type-check
  • ansify.ext:canonicalize-typespec
  • ansify.ext:read-value

以下の変数で警告を投げるかどうかを設定できます。デフォルトは全部オフになってます。

  • ansify.ext:*warn-on-otherwise-in-middle* (case で
  • ansify.ext:*warn-on-invalid-typespec* (typep とか
  • ansify.ext:*warn-on-undefined-typespec* (同上

"ansify" から疑似 export してたものをちゃんと export するようにしたので `ansify:etypecase` などと書けるようになりました。(`ansify::install` すると "ansify" を use-package してたんですが lisp と盛大に衝突するのでしなくなってます。)

その他の変更点

  • 細々したもの追加
    • `type-of`(structure に対して `lisp:structure` ではなく構造体名を返す)
    • `constantly`
    • `the`
    • `nth-value`
    • `upgraded-complex-part-type`
    • 単に名前が変わっただけ
      • `special-operator-p`
      • `get-setf-expansion`
      • `define-setf-expander`
  • typespec 周りごちゃごちゃ見直し
  • バグ修正(主に typespec 周り、id:miyamuko さんに感謝)

いつもの

local-window-flag

http://xyzzy.s53.xrea.com/reference/wiki.cgi?p=set-local-window-flags で設定する行番号とかのやつ。

  • フラグは on か off か未設定か
  • window と buffer がそれぞれにフラグを覚えてる
  • 優先順位は buffer > window > (グローバルな設定)
  • `get-local-window-flags` は多値で on のフラグと off のフラグを返す
;; 現在の buffer/window で flag が on なのか off なのか
(defun window-flag (flag)
  (labels ((on? (x) (plusp (logand flag x))))
    (multiple-value-bind (buffer-on buffer-off)
        (get-local-window-flags (selected-buffer))
      (cond ((on? buffer-on) t)
            ((on? buffer-off) nil)
            (t (multiple-value-bind (window-on window-off)
                   (get-local-window-flags (selected-window))
                 (cond
                  ((on? window-on) t)
                  ((on? window-off) nil)
                  (t (on? (get-window-flags))))))))))
=> window-flag

たぶん合ってる。もうちょっとスッキリ書けても良さそうなもんなんだが・・・。

ansify 0.01.01 バグ修正

早速 id:miyamuko さんからバグ報告もらったので修正しました。毎度ありがとうございます。

  • case, typecase で `ansify::otherwise` ではなく `lisp:otherwise` を使うように修正
    • xyzzy には otherwise は無いものと思い込んでたけどあった
  • print-unreadable-object で princ にストリーム渡し忘れてたのを修正

ついでにバージョン変数 `ansify::+version+` 作っときました。

case の途中で (otherwise ...)

keys---a designator for a list of objects. In the case of case, the symbols t and otherwise may not be used as the keys designator. To refer to these symbols by themselves as keys, the designators (t) and (otherwise), respectively, must be used instead.

CLHS: Macro CASE, CCASE, ECASE

"may not be used" ってどうすりゃいいんだよ。エラー投げていいのん?と CL 処理系の挙動を調べてみたらバラバラだった・・・。

※処理系のバージョンが古いのは突っ込んであった LispCabinet に付属してたものだからです。

xyzzy デフォルト

無言でマッチする

(case 3
  (x 'x)
  (otherwise 'otherwize)
  (3 :three))
=> otherwize

xyzzy + ansify

無言でマッチしない

(require "ansify")
=> t
(ansify::case 3
  (x 'x)
  (otherwise 'otherwise)
  (3 :three))
=> :three

Clozure CL Version 1.6-r14468M

警告を出してマッチする

CL-USER> (case 3
           (x 'x)
           (otherwise 'otherwise)
           (3 :three))
; Warning: T or OTHERWISE clause in the middle of a CASE statement.  Subsequent clauses ignored.
; While executing: CCL::CASE-AUX, in process repl-thread(10).
OTHERWISE

SBCL 1.0.45

無言でマッチしない

CL-USER> (case 3
           (x 'x)
           (otherwise 'otherwise)
           (3 :three))
:THREE

CLISP 2.48

エラーで止まる

CL-USER> (case 3
           (x 'x)
           (otherwise 'otherwise)
           (3 :three))
---- debugger ----
CASE: the OTHERWISE clause must be the last one
   [Condition of type SYSTEM::SIMPLE-SOURCE-PROGRAM-ERROR]

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*PROCESS-INPUT] Continue reading input.
 2: [ABORT] Return to SLIME's top level.
 3: [CLOSE-CONNECTION] Close SLIME connection.
 4: [ABORT] Abort main loop

setf-values 0.01.02 更新しました

しょーもないミスでおかしな展開形になってたのを修正した(miyamuko さんからパッチ頂きました。ありがとうございます。)のと、変数以外の atom に setf しようとしたのはマクロ展開時にエラーに。

ansify 0.01.00 をリリースしました

今までバラバラに作ってた ANSI Common Lisp からもらってきたようなものを1つにまとめました。
具体的には

が全部入ってます。

使い方(開発者向け)

今まで公開してた condition-restart と symbol-macrolet は lisp パッケージからエクスポートしてましたがその方法だと問題ありなので、ansify では専用のパッケージをを使うようにしました。普通に export すると lisp パッケージのシンボルと衝突するので shadowing-import するようにしてあります。
数が多いんで必要なものを全部 shadowing-import する ansify::install という関数も用意しておきました。

(eval-when (:execute :compile-toplevel :load-toplevel)
  (require "ansify"))

(defpackage :my-package
  ...)

(in-package :my-package)

(eval-when (:execute :compile-toplevel :load-toplevel)
  (ansify::install))

やってることは片っ端から shadowing-import なので、特定のオペレータのみ使いたいなどの場合は個別に shadowing-import したり defpackage の :shadowing-import-from に指定してもだいじょぶです。

(eval-when (:execute :compile-toplevel :load-toplevel)
  (require "ansify"))

(defpackage :my-package
  (:use #:lisp #:editor)
  (:shadowing-import-from :ansify
   #:destructuring-bind #:etypecase ...))

取り込まれた拡張は deprecated になります。

  • condition-restart
  • symbol-macrolet
  • typespec+

は deprecated になります。狙ったわけでもないのに ansify と同時にインストールしておいても問題は起きない*1んですが、ansify の方へ移行お願いします。しばらくはそのまま置いておきますがそのうち消えて無くなります。
condition-restart に含まれていた condition-restart-support.l(eval-region などから再起動を選択できるようにするもの)が ansify には含まれていません。無いと困るという人がいたら twitter か↓コメントか何かで連絡ください。

あと、condition-restart の再起動と ansify の再起動は互換性ないです。ansify::restart-case で用意した再起動は ansify::find-restart で探す必要があります(condition-restart:find-restart では見つけられないです)。

*1:ansify を install したパッケージでは ansify のものが使われる。それ以外のパッケージでは lisp から export されてる旧拡張のものが使われる。

XTAGS #2 飛ぶ

タグジャンプ(jump-tag)できるようにするための何やら。

ローカル変数 ed:tags-find-target

この変数にセットした関数が引数なしで呼び出されるので、カーソル位置の単語を調べて

  • クラス名
  • 名前
  • 関数か否か

を多値で返す。
3つ目の値は、nil なら変数、'lisp:structure なら構造体、それ以外なら関数、と扱われるっぽい(tags-find-entry-1 参照)のでそんな感じで。
この情報を元に XTAGS からジャンプ先のファイル名/ポイントを探してくれる。

ローカル変数 ed:tags-find-point

ジャンプ先のファイル名が見つかったらそのファイルを開いて、この関数が呼び出される。引数は以下の4つ。

  • クラス名(ed:tags-find-target から)
  • 名前(ed:tags-find-target から)
  • 関数か否か(ed:tags-find-target から)
  • ポイント(XTAGS エントリから)

ポイントを返すとそこへカーソルを移動する(その後行頭に移動してしまう)ので、XTAGS エントリに記録するポイントは必ずしも正確でなくてもこの関数で調整したりできる。
nil を返すと元のポイントへ移動する。

その他のタグジャンプ関連ローカル変数

ed::tags-case-insensitive

non-nil だと ed:tags-find-target から XTAGS エントリを探すのが case-insensitive になる。

ed::tags-class-method-separator

クラス名とメソッド名の区切り文字列。C++ なら "::"、Java なら "." とか。

  • XTAGS エントリが見つからない時のメッセージ
  • 該当する名前のエントリが複数あった時の選択ダイアログ
  • ed::tags-make-completion-list で作った補完候補