Common Lisp用コードフォーマッタ
Code formatter for Common Lisp
Meta note.
対象読者
- Common Lispのコードフォーマッタを探している人。
Introdunction.
自作ライブラリをQuicklispに登録しようとしたら「お前のコードのフォーマット、コミュニティで一般的なフォーマットじゃねぇからそのへん直してから出直しな」(超意訳)と門前払いされました。
一人でほそぼそと書いてると変な癖がついていけませんね。
手動で直すのは骨なのでフォーマッタを作った次第。
ここではREADMEを翻訳しておきます。
TRIVIAL-FORMATTER 9.0.0
これは何か?
CommonLisp用のコードフォーマッタです。
trivial-formatterのソースコードを参照してください。
このファイルはtrivial-formatter自体によってフォーマットされています。
使用法
(trivial-formatter:fmt :your-system :supersede)
詳細については、specファイルを参照してください。
線幅。
デフォルトは実装によって異なります。
(おそらく80です。)
通常の一般的なLispプリティ印刷システムの方法で、つまり *PRINT-RIGHT-MARGIN*
を使用して制御できます。
(let ((*print-right-margin* 100)) ; <--- 線幅を100で指定。
(trivial-formatter:fmt :your-system :supersede))
厳密モード。
デバッガーを呼び出すと、一部の実装(eclなど)は:cl-userパッケージに入ります。
このような場合、loop
マクロのバックトレースフォームは醜くなります。
(LOOP YOUR-PROJECT::FOR YOUR-PROJECT::I YOUR-PROJECT::UPFROM 0 ...)
キーワードシンボルをループマクロキーワードとして使用すると、このような醜い形式を回避できます。
(LOOP :FOR YOUR-PROJECT::I :UPFROM 0 ...)
strictモードでは、trivial-formatterは、ループマクロキーワードをキーワードシンボルにフォーマットします。
有効にするには、 *strict-loop-keyword-p*
を t
にバインドします。
* (let ((trivial-formatter:*strict-loop-keyword-p* t))
(trivial-formatter:fmt :your-system :supersede))
開発者から
Reader
ソースコードに特別なリーダーマクロがある場合、trivial-foramtterは不明なリーダーマクロに関するエラーを通知します。
このような場合、trivial-formatterはreadtable、特にNAMED-READTABLESに大きく依存するため、通常の一般的なLispの方法でリーダーを拡張できます。
これを拡張するには、リーダーマクロ関数が中間オブジェクトを返す必要があります。
(let ((*readtable* (named-readtables:copy-named-readtable 'as-code)))
(set-macro-character #\! (lambda (stream char) `(,char ,(read stream))))
(read-as-code))
!hoge
=> (#\! HOGE)
詳細については、clhs
およびnamed-readtablesを参照してください。
プリンター。
中間オブジェクトを作成するときは、そのためのプリティプリント関数を作成する必要があります。
Trivial-formatterはプリティプリントシステムに大きく依存しているため、通常の一般的なLispの方法で拡張できます。
(defun !-printer (stream exp)
(format stream "~<~A~S~:>" exp))
(set-pprint-dispatch '(cons (eql #\!) (cons * null)) '!-printer)
(print-as-code '(#\! hoge))
=> !hoge
詳細については、clhsを参照してください。
外部フォーマッタをロードします。
trivial-formatterは、外部フォーマッターをロードできます。
外部フォーマッタとして拡張コードを書くことができます。
外部フォーマッターファイルには「formatters.lisp」という名前を付ける必要があります。
trivial-formatterは、 *foreign-formatters-directories*
からファイルを検索します。
デフォルトは、quicklispのlocal-projectsディレクトリとroswellのlocal-projectsディレクトリです。
パッケージtrivial-formatter-user。
trivial-formatter-userでは、deformatter、pprint-fun-call、およびpprint-linear-eltを通常の一般的なlispシンボルとともに使用できます。
PPRINT-FUN-CALL
pprint-fun-callは、キーと値のペアを考慮します。
(pprint-fun-call nil '(asdf:component-pathname component :direction :output :if-does-not-exist :create :if-exists if-exists))
(ASDF:COMPONENT-PATHNAME COMPONENT
:DIRECTION :OUTPUT
:IF-DOES-NOT-EXIST :CREATE
:IF-EXISTS IF-EXISTS))
NIL
PPRINT-LINEAR-ELT
pprint-linear-elt
は現在のインデントを設定し、すべてのcdr
要素に改行を入れます。
(pprint-linear-elt nil '(asdf:component-pathname component :direction :output :if-does-not-exist :create :if-exists if-exists))
(ASDF:COMPONENT-PATHNAME COMPONENT
:DIRECTION
:OUTPUT
:IF-DOES-NOT-EXIST
:CREATE
:IF-EXISTS
IF-EXISTS))
NIL
DEFORMATTER
deformatterは、パッケージの存在とシンボルの競合、およびset-pprint-dispatchに注意を払います。
(macroexpand-1 '(deformatter package symbol (stream exp)
(format stream "~A" exp)))
(WHEN (FIND-PACKAGE "PACKAGE")
(DEFUN #:PPRINT-SYMBOL3440 (STREAM EXP) (FORMAT STREAM "~A" EXP))
(SET-PPRINT-DISPATCH
`(CONS (MEMBER ,(UIOP/PACKAGE:FIND-SYMBOL* "SYMBOL" "PACKAGE")))
'#:PPRINT-SYMBOL3440)
'#:PPRINT-SYMBOL3440)
TRIVIAL-FORMATTER-USER:SET-PPRINT-DISPATCH
プリティプリント機能を一時的に設定したい場合は、 *print-pprint-dispatch*
をバインドし、 cl:set-pprint-dispatch
の代わりにtrivial-formatter-user:set-pprint-dispatch
を使用する必要があります。そうでなければ、一時的機能は決して機能しません。
cl:set-pprint-dispatch
はパッケージ:trivial-formatter-user
でシャドウされています。
(deformatter sxql where (stream exp)
(let ((*print-pprint-dispatch* (copy-pprint-dispatch)))
(set-pprint-dispatch '(cons (member :and :or)) 'pprint-linear-elt)
(pprint-fun-call stream exp)))
製品の目標
ライセンス
mit
開発
sbcl / 2.0.9
テスト済み
- sbcl / 2.0.9
- ccl / 1.12 ; cclがansi規格に違反しているために失敗しました。
- ecl / 20.4.24
注意
trivial-formatterは、少なくとも上記の処理系で移植可能に機能します。
しかし、それは決して同じように機能することを意味するものではありません。
たとえば、「if」形式は異なります。
sbclは、要素が短い場合でも改行を出力しますが、他の処理系ではそうではない場合があります。
#+sbcl
(if a
b
c)
#+(or ecl ccl)
(if a b c)
既知の問題。
clisp
clispはサポートされていません。
clispの発言
The Lisp Pretty Printer implementation is not perfect yet.
ccl
現在、ansi規格に違反しているため、cclのサポートを一時的に停止しています。
? (pprint-dispatch t nil)
=> error
table---a pprint dispatch table, or nil.
幸い、この問題はすでに修正されています。
次のcclリリースを待つか、ソースから現在のcclをビルドしてください。
Reader。
リーダーマクロが競合する場合、そのようなリーダーマクロは黙って無視されます。
新しいリーダーマクロを追加することはできますが、既存のリーダーマクロを変更することはできません。
フォーマット制御
trivial-formatterは~newlineフォーマットコントロールのインデントを調整できません。
インストール
trivial-formatterをインストールするには、roswellをお勧めします。
$ ros install hyotang666/trivial-formatter
実行中のlisp環境にtrivial-formatterをロードするには、replで以下を評価します。
* (ql:quickload :trivial-formatter)
Discussion