Scrat改めSqratらしい

 さっそく組み込んでみた。0.5っていってるだけあってたりない機能も多い。C++からSquirrelの関数を呼ぶFunctionテンプレートで呼ばれてるsq_callでエラーチェックしてないのはわりと致命的。あと、ファンクターの作りが甘いような? 一時オブジェクトで使わないと、sq_addref と sq_release が狂うらしく落ちる。
 以下テストした時のコード断片。

C++側のコード

// Squirrelに公開するクラス
class ExportClass
{
public:
  ExportClass():i(-1){}
  void test1(){ printf("test1\n"); }
  void test2(){ printf("test2 %d\n",i); }
  int i;
};

using namespace Sqrat;

int main()
{
  // VM生成
  HSQUIRRELVM v = sq_open(1024);

  // 各ハンドラ設定
  sqstd_seterrorhandlers(v);
  sq_setprintfunc(v,printfunc);

  // ExportClassBind
  // テンプレート引数に公開するクラスを指定
  Class<ExportClass> exClass(v);
  // メンバ関数登録
  // 第一引数のテキストは、Squirrel上での名前
  exClass.Func(_SC("test1"),&ExportClass::test1);
  exClass.Func(_SC("test2"),&ExportClass::test2);
  // メンバ変数登録
  // 第一引数のテキストは、Squirrel上での名前
  exClass.Var(_SC("i"),&ExportClass::i);

  // ルートテーブルに登録
  RootTable(v).Bind(_SC("ExportClass"),exClass);

  // 一度、main.nutを読み込み
  // main.nutで定義したSquirrel上のctest関数が登録される
  sq_pushroottable(v);
  SQRESULT r = sqstd_dofile(v,_SC("main.nut"),SQFalse,SQTrue);
  if(SQ_FAILED(r)) PrintError(v);
		
  // スクワール上の関数を呼ぶ
  ExportClass* p = new ExportClass();
  // Functionテンプレートを使う。
  // テンプレパラメタは戻り値。Squirrelに公開したクラスなら
  // それとしても受け取れる
  // コンストラクタの第一引数は関数が登録されてるテーブル。
  // 例だとルートテーブ。第二引数は呼ぶ関数名
  // FunctionテンプレートはFunctorなのでその一時オブジェクトに
  // 必要な引数を渡せば、Squirrel上の関数に引数として渡ります
  ExportClass* p1 
     = Function<ExportClass*>(RootTable(v), _SC("ctest"))(p);

  // VM終了
  sq_close(v);
}

Squirrelのコード

function ctest(instance)
{
  instance.test1();
  instance.i = 1000;
  instance.test2();
	
  ins2 <- ExportClass();
  ins2.i =100000;
  return ins2; // Sqruirrel上で作ったインスタンスも返せる
}

 ちなみに、0.5になって、テンプレ引数がvoidじゃないFucntionテンプレートから、上記のコードで呼ぶコンストラクタがなくなってしまったので、追加しちゃいましょうw

Function(const Object& e, const SQChar* slot):vm(e.GetVM())
                                             ,env(e.GetObject())
{
  sq_addref(vm, &env);
  Object so = e.GetSlot(slot);
  obj = so.GetObject();
  sq_addref(vm, &obj);
}

を、sqratFunction.h の60行目付近に足しちゃえばOK。

ただ、Functionテンプレートの定義を見ると、正式には

ExportClass* p1 
  = Function<ExportClass*>(
                           // テーブルが存在するVM
                           v, 
                           // 関数が登録されてるテーブル
                           RootTable(v), 
                           // 関数が格納されてるスロット
                           RootTable(v).GetSlot(_SC("ctest")))(p);

の模様。
 最初にも書きましたが、Fucntionテンプレートで呼ばれるsq_callはエラーチェックが入ってないので、ctestでエラーが起きても何もわかりません。まぁ、そのうち改善されるでしょうし。自前でも入れても大した手間じゃないんで、ま、いいかなって感じ。dofile/compilier系のシンタックスシュガー用意してくれるとさらに幸せなんだけどw

 あと気を付けるのは、C++←→Squirrelを行き来する時にどっち側で作ったインスタンスなのかを忘れないこと。特にSquirrel側で作ったインスタンスを取得すると、そのインスタンスSquirrelGC管理化なので、C++側でdeleteしてはいけません。