Bindatタイプ式は、これまでに説明したタイプに限定されません。Bindatタイプ式をリターンする、任意のLispフォームも可能です。たとえば以下のタイプは24ビットカラー、またはバイトのベクターのいずれかを含むことが可能なデータを記述します:
(bindat-type (len u8) (payload . (if (zerop len) (uint 24) (vec (1- len)))))
さらに複合タイプは通常は連想リストにunpack(または逆にpack)されませんが、以下のスペシャルキーワード引数を使用してこれを変更することができます:
:unpack-val exp
フィールドのリストがこのキーワードで終わる場合には、unpack時リターンされる値は標準のalistではなくexpの値となる。expは名前によって前のフィールドすべてを参照できる。
:pack-val exp
このキーワード引数がフィールドのタイプの後に続く場合には、このフィールドにはalistから抽出するかわりにexpがリターンした値がpackされる。
:pack-var name
このキーワード引数がフィールドのリストの前に前置されている場合には、後続するすべての:pack-val
引数がnameという名前の引数を介して、この複合タイプにpackされた全体値を参照できる。
たとえば以下のように16ビット符号付き整数を記述できます:
(defconst sint16-bindat-spec (let* ((max (ash 1 15)) (wrap (+ max max))) (bindat-type :pack-var v (n uint 16 :pack-val (if (< v 0) (+ v wrap) v)) :unpack-val (if (>= n max) (- n wrap) n))))
これは以下のようになります:
(bindat-pack sint16-bindat-spec -8) ⇒ "\377\370" (bindat-unpack sint16-bindat-spec "\300\100") ⇒ -16320
最後にbindat-defmacro
でBindatタイプ式を使用することによって、Bindatタイプフォームを新たに定義できます:
argsを受け取るnameという名前のBindatタイプ式を新たに定義する。これの挙動はdefmacro
に準ずるが、重要な違いは新たなフォームがBindatタイプ式でのみ使用できることである。