GaucheFest:koguro
GaucheFest:19th
c-wrapperのinfoドキュメントをもうちょっとちゃんと書きます。
と思ってc-wrapper.c-ffiモジュールのドキュメントを書こうとしたら、関数やらクラスやらがたくさんあって面倒だったので、Schemeのコードからtexinfoのひな形(とそれにまつわるいくつかのファイル)を自動生成するスクリプトを作りました→Gauche:scm2texi
(GaucheFest:16thでのgdocをもうちょっと強化させたものという位置づけですが、実際はgdocの存在を完全に忘れていて再実装していた...orz)。
GaucheFest:18th
c-wrapperにstub生成の機能を追加しようかと考えています。
GaucheFest:16th
ソースコードからtexinfo形式のドキュメント(のひな形)とMakefile.inを作成するコマンド(gdoc)を作ってみました(gdoc-0.1.tgz)。モジュールの中で公開される関数・マクロ・クラス定義を見つけ出し、その直前にかかれているコメントをもとにしてドキュメントを作り出します。
例えば、
(define-module foo (export bar)) ;; bar is the function which returns v + 1. (define (bar v) (+ v 1)) ;; This function is private. (define (baz v) v) (provide "foo")
といったソースコードを作っておいて、gdoc foo.scm doc を実行すると、docディレクトリ以下に
\input texinfo @c -*-texinfo-*- @comment %**start of header @setfilename foo-ref.info @settitle foo reference manual ...(長いので省略)... @defun bar v bar is the function which returns @var{v} + 1. @end defun ...(さらに続くので省略。ただしbazのドキュメントは生成されない)...
といったtexinfoドキュメント(foo-ref.texi)が生成されます。あとはこれをもとにドキュメントをちゃんと書き直していくという作業になります(あとconfigure.acも作っとかないといけないです)。
これはJavadocと似ていますが、ドキュメントをソースコードに埋め込めるというものではありません。gdocはあくまでドキュメントのひな形をソースコードから生成するだけで、一度生成したらあとはドキュメント自体をメンテナンスしていくという考え方で作っています。ドキュメントとソースコードの章立てや構成は必ずしも一致しないと思うので、分離してメンテナンスできた方がよいと思うのですがどうなんでしょう?
- koguro(2006/10/08 03:42:11 PDT): クラス索引が作成できなかったバグを修正して、変数のドキュメントも生成できるようにしました(gdoc-0.1)。
GaucheFest:15th
テストケース作成支援のためのツールを作りました(拙作のEmacs用のユーティリティに含めてあります gca-20060903.tar.gz)。 単体テストをきちんと書くのは面倒ですが、通常コードを書くときは、無意識のうちにgosh上で動作確認をしつつコードを書き進めているかと思います。この動作確認の結果を基に単体テストを作成してしまおうというのがこのツールです。
インストールの仕方は、tarballの中のgca.elのコメントを参照してください。動作確認は GNU Emacs 22.0.50と21.3.1で行いました。中でいろいろ変なことをしているので、バージョンが違うと動かないかもしれません(多分XEmacsでは無理かと思います)。
あと、このgca.elの簡単なデモ用ムービーも作ってみました。単体テストの生成・シンボルの補完・ドキュメント検索・(use ...)の挿入・テンプレートを使ったstub作成支援など一連の機能を見ることができます(単にEmacsの画面を写しているだけなので分かりにくくて退屈ですが...)。
GaucheFest:11th
- 2006/06/11 02:36:07 PDT: Objective-Cに対応したc-wrapper 0.4.0をリリースしました。
c-wrapperのObjective-C対応の作業を行いました。使い方は見てのとおりObjective-Cそのままです。NSRangeなどの構造体も扱えますが、NSMakeRangeなどの一部の関数はstaticなインライン関数となっているためc-wrapperからは呼び出せません。直接メンバ変数に値を設定する必要があります。
gosh> (use objc-wrapper) #<undef> gosh> (c-load-library "/System/Library/Frameworks/Foundation.framework/Foundation") #<undef> gosh> (c-load-library "/System/Library/Frameworks/Cocoa.framework/Cocoa") #<undef> gosh> (c-include "Cocoa/Cocoa.h") #<undef> gosh> [[NSAutoreleasePool 'alloc] 'init] #<c-ptr:<c-struct:objc_object> 0x510710> gosh> (NSLog [NSString :stringWithCString "Hello" :encoding NSASCIIStringEncoding]) 2006-05-13 20:27:25.447 gosh[19268] Hello #<undef> gosh> (define ss [[NSSpeechSynthesizer 'alloc] 'init]) ss gosh> [ss :startSpeakingString (@ "Hello, again")] ;; (@ "...")でNSStringが作れます 1
あと、GOGGとは違い、NSObjectに対するGCのサポートはないので、オブジェクトのリファレンスカウントは手動で操作してください。その代わりといっては何ですが任意のポインタオブジェクトに対してデストラクタを設定できるようにしました。GC時に指定したλ式が呼ばれます(いろいろ試行錯誤しているので、ここらへんのAPIはあとで変更されるかもしれません)。
gosh> (define a (malloc 10)) a gosh> (set-destructor! a (lambda (ptr) (free ptr) (print "free!!"))) #<undef>
その他に、やってみたらこんなこともできました(多分Rubyとかでもできると思います)。実用的かどうかは分かりませんがPythonスクリプトをGaucheに埋め込めます。
gosh> (c-load-library "libpython") #<undef> gosh> (c-include "python2.3/Python.h") #<undef> gosh> (Py_Initialize) #<undef> gosh> (PyRun_SimpleString "print \"Hello, world\"") Hello, world 0
GaucheFest:9th
GaucheFestでc-wrapperのドキュメントを書いていました。
texinfoでちゃんと作ろうかと思っていたのですが、時間が足りなかったのでとりあえず暫定的なドキュメントで公開します。
- さっそく遊びたくてc-wrapperをダウンロードさせてもらいました。
NetBSD-2.0.2だと、c-grammar.scmからc-grammar.yy.scmを生成するところで、
なぜかgaucheのintlib.c 1447行目のアサーションがコールされる模様。
こんな感じなんでHELP MEー!.... gmake[1]: Entering directory `/usr/home/cut-sea/devel/c-wrapper-0.1/lib' /usr/local/bin/gosh -I. -ulalr c-wrapper/c-grammar.scm "intlib.c", line 1447 (intlib_cenv_lookup): Assertion failed: SCM_IDENTIFIERP(name) gmake[1]: *** [c-wrapper/c-grammar.yy.scm] エラー 1 gmake[1]: Leaving directory `/usr/home/cut-sea/devel/c-wrapper-0.1/lib' gmake: *** [all] エラー 2
念のため手動でロードしてみる。lalr自体のuseは大丈夫そう。cut-sea@nkisi> pwd /usr/home/cut-sea/devel/c-wrapper-0.1 cut-sea@nkisi> cd lib cut-sea@nkisi> gosh -I. -ulalr gosh> lalr-parser #<macro lalr-parser> gosh> (load "c-wrapper/c-grammar.scm") "intlib.c", line 1447 (intlib_cenv_lookup): Assertion failed: SCM_IDENTIFIERP(name)
ちなみにGauche-0.8.7_pre1にpthreadパッチあたってますが、問題のintlib.c自体は Gauche-0.8.6とdiffはなかったです。static ScmObj intlib_cenv_lookup(ScmObj *SCM_FP, int SCM_ARGCNT, void *data_) { ScmObj cenv_scm; ScmObj cenv; ScmObj name_scm; ScmObj name; ScmObj lookup_as_scm; ScmObj lookup_as; SCM_ENTER_SUBR("cenv-lookup"); cenv_scm = SCM_ARGREF(0); cenv = (cenv_scm); name_scm = SCM_ARGREF(1); name = (name_scm); lookup_as_scm = SCM_ARGREF(2); lookup_as = (lookup_as_scm); { ScmObj frames, fp, vp; int name_identifier = SCM_IDENTIFIERP(name); SCM_ASSERT(SCM_VECTORP(cenv)); frames = SCM_VECTOR_ELEMENT(cenv, 1); SCM_FOR_EACH(fp, frames) { if (name_identifier && SCM_IDENTIFIER(name)->env == fp) { /* strip identifier if we're in the same env (kludge). */ name = SCM_OBJ(SCM_IDENTIFIER(name)->name); } if (SCM_CAAR(fp) > lookup_as) continue; /* see PERFORMANCE KLUDGE above */ /* We inline assq here to squeeze performance. */ SCM_FOR_EACH(vp, SCM_CDAR(fp)) { if (SCM_EQ(name, SCM_CAAR(vp))) return SCM_CDAR(vp); } } if (SCM_SYMBOLP(name)) { ScmObj mod = SCM_VECTOR_ELEMENT(cenv, 0); SCM_ASSERT(SCM_MODULEP(mod)); return Scm_MakeIdentifier(SCM_SYMBOL(name), SCM_MODULE(mod), SCM_NIL); } else { SCM_ASSERT(SCM_IDENTIFIERP(name)); ←ここが1447行目 return name; } } }
- koguro (2006/03/04 18:43:16 PST): うーん、すぐにはよく分からないです。手持ちの環境にNetBSDを入れてみて試してみますが、とりあえず使うだけなら他の環境でc-grammar.yy.scmを生成してコピーしてみてください。
- Shiro(2006/03/04 19:09:42 PST): そのassertion failure、GC絡みで見ることがあります。
その部分を
if (!SCM_IDENTIFIERP(name)) Scm_Printf(SCM_CURERR, "!!! %S?n", name);
みたいに書き換えて走らせて、表示されるものから見当がつけられるかもしれません。 - koguro(2006/03/04 19:36:02 PST): FreeBSDでGauche 0.8.7_pre1を入れて試してみたらエラーが再現できました。そのところのnameは"('ptr '*)"となっています。このリストが使われている箇所はc-grammar.scmの335行目です。
(LPAREN declarator RPAREN) : (match $2 ((('ptr '*) rests ...) rests) ((('ptr '* a ...) rests ...) (cons (cons ptr a) rests)) (else $2))
あと、エラーが発生する原因となるcenv-lookupを呼んでいる箇所は、compile.scmのmodule-qualified-variable?のようです(compile.scmから呼んでいるcenv-lookupの名前を全部変えて調べてみました)。ここのexprに(('ptr '*) rests |...|)が入っており、先頭のリストを調べようとして落ちています。 - koguro(2006/03/04 20:16:28 PST): ((('a 'b) 'c |...|))を評価するだけで、必ず上記のエラーが発生するようです。Gauche:Bugsに追加しました。