GaucheでNCCC API呼び出しに対応 / Guileで補助キーワードの扱いが変わった?
ちょっとこっぴどい風邪をひいてしまっていて、ここ数日は家で明治の文豪みたいになりながらコードを書いたりしていた。クッソ寝不足なことを除けば大分快復したので明日からは平常営業の予定。。
GaucheでNCCC呼び出しに対応
今まで実装したものと思い込んでいたyuniにおけるGaucheのFFI対応が全然未実装だったので実装した。
0.9以降のGaucheにはForeign pointer classのためのテンプレートが標準で付いてくるため、ポインタをwrapするだけであれば非常に短いコードで実現することができる。
クラスの定義を別途行う必要は無く、
YuniPtrCls = Scm_MakeForeignPointerClass(mod, "<yuniptr>", yuniptr_print, NULL, 0);
としてYuniPtrClsを登録するようにしておけば、後は、
extern ScmClass* YuniPtrCls; #define YUNIPTR_UNBOX(obj) SCM_FOREIGN_POINTER_REF(void*, obj) #define YUNIPTR_P(obj) SCM_XTYPEP(obj, YuniPtrCls) #define YUNIPTR_BOX(ptr) Scm_MakeForeignPointer(YuniPtrCls, ptr)
のようなマクロを定義することで、他のScheme型と同じように操作することができる。NMoshのpointer型と異なりyuniのポインタはGC-safeである必要が無い(GCのroot setに含まれない)ので、単純なラッパで十分となる。
Gaucheのコードを書いてていつも思うのは、そろそろvimでtexinfo読むの止めないとなということか(標準ビューアがなかなか使いこなせない)。。ドキュメントは非常に充実しているのですんなり書けた。
Chibi-schemeとは共通のbootstrap部分、つまりmalloc()とかdlsym()のような基本ライブラリを共有している。
このbootstrapライブラリ自体も一つのNCCC関数 yuniffi_bootstrap0 で実現されていて、処理系の実装者はNCCC( http://d.hatena.ne.jp/mjt/20150604/p1 )ライブラリの呼び出し機能とポインタの読み書きさえ実装すれば残りはyuniのライブラリが面倒を見るようにしている。
せっかくなのでTravisCIでのdockerテストにもNCCC APIの呼び出しを含むテストを追加した。これで
- chibi-scheme (R7RS)
- Gauche (R7RS)
- Sagittarius (R7RS)
- Racket (R6RS)
- NMosh (R6RS)
でNCCC APIの呼び出しまで開通したことになる。あとはひたすらSDL2なりPOSIXなりのAPI記述を充実させていけば、これらのAPIを使ったプログラミングを1本のSchemeソースで行う環境ができる。
最近のGuileでyuniが動かない問題
NCCC stubそのものはGuileでも実装しているが、なんと最近のGuileではyuniが動かないことが発覚して対応に追われている。
いろいろやって解ったのは、Guileは標準の補助キーワードを再エクスポートできないようにどこかで変更が掛かったこと。つまり、
- lib-a.scm
(library (lib-a) (export syntax-rules ...) (import (rnrs)))
- b.scm
(import (except (rnrs) syntax-rules) (lib-a)) (define-syntax x (syntax-rules (=>) ((_ a (b ...) c ...) (begin c ...)))) (x some (some some) (display 'OK) (newline))
の2つのファイルが有ったとき、最新のリリース版である2.0.11では正常にsyntax-rulesが展開されるが、最新のgit版ではlib-aのエクスポートする ... と (rnrs)の ... を別物と判断してsyntax-rulesの展開に失敗する。
yuniは基本的にライブラリはR7RSで実装し、R6RSで動作するためには内包するR7RS互換ライブラリを通している。このため、補助キーワードがboundなR7RSに合わせてくれないとかなり困ったことになってしまう。。
幸い、最近のGuileはSRFI-46をサポートしているので、自前の ... と syntax-rulesを実装してexportすれば回避できるのではないかと考えている。