''AngelScript'' LuaとかSquirrelは動的型スクリプト言語。 静的なものがないかと探していたらangelscriptを見つけた。 ちょっといじってみよう。 #contents * リンク [#sb7bd538] http://www.angelcode.com/angelscript/ http://angelscript.pbwiki.com/ http://liw.rulez.jp/index.php?%A5%D7%A5%ED%A5%B0%A5%E9%A5%E0%2FAngelScript * スクリプト実行の順序 [#t99be81c] + エンジン作成 + コールバック登録(エラー,例外時に活躍?) + スクリプトファイルをエンジンに登録 + ビルド(コンパイル) ← さすが静的型。 + 実行 + 後片付け includeは自前で実装しているのね。 * 構文 [#l789f3fc] ** class [#zbe0b959] - public,protected,privateは無し。 - 継承もなし。 - コンストラクタ,デストラクタは有り。 - operatorは可能?(未確認) ** import [#tf87bcd5] 他のmoduleの''関数''(Typeは不可)を自分のmodule内で使うための機能。 なので,一工夫したほうがいいかも。 その一例。 実装クラス(L_MathVector3)はIObjectを必ず継承する。 外部に公開する関数(F_MathVector3_*)はクラス外に宣言し,引数の先頭に必ずIObjectをとる。 他のモジュールは,公開されたその関数を通してアクセスするか,そのラッパークラス(MathVector3)を使ってアクセスする。 :C++コード| #code(c,){{ // IObject型を追加。 engine->RegisterInterface("IObject"); }} :Vector3_Local.as| こいつは,mathモジュールでのみコンパイルされる。 クラスの内部実装を記述している。 #code(c,){{ // module math - local class L_MathVector3 : IObject { L_MathVector3(){ /* */ } float mX; float mY; float mZ; float& x() { return mX; } void normalize() { //... } }; IObject@ F_MathVector3_Constructor() { MathVector3 obj; return @obj; } float& F_MathVector3_x( const IObject@ in obj ) { return cast<L_Vector3>(obj).mX; } void F_MathVector3_normalize( IObject@ obj ) { cast<L_Vector3>(obj).normalize(); } }} :Vector3.as| こいつは,他のmoduleでコンパイルされる。 クラスの内部実装は書かず,内部実装が書かれている関数を呼ぶだけに留める。 #code(c,){{ // module public import IObject@ F_MathVector3_Constructor() from "math"; import float& F_MathVector3_x( const IObject& in ) from "math"; import void F_MathVector3_normalize( const IObject& in ) from "math"; class MathVector3 { MathVector3() { mObj = F_MathVector3_Constructor(); } IObject@ mObj; float& x() { return F_MathVector3_x( mObj ); } void normalize() { F_MathVector3_normalize( mObj ); } }; }} * バイトコード [#t4292d88] 生成されるバイトコードの比較。 ** 組み込み型vs組み込み型のラッパークラス [#j2458c83] #code(c,){{ class MyUInt { MyUInt( const uint& in aVal ) { this.mVal = aVal; } uint mVal; }; void cla() { MyUInt i(0); i.mVal += 1; } //----------------------------------------------------------- Temps: 2, 3 0 0 * PUSH 3 - 12,5 - 1 3 * SUSPEND 2 3 * VAR v1 3 4 * SetV4 v2, 0x0 (i:0, f:0) 5 4 * VAR v2 6 5 * GETREF 0 7 5 * GETREF 1 8 5 * ALLOC 0xa8cebf8, 66 - 13,5 - 11 3 * SUSPEND 12 3 * PSF v1 13 4 * CHKREF 14 4 * RDS4 15 4 * ADDSi 16 17 4 * PopRPtr 18 3 * RDR4 v2 19 3 * ADDIi v2, v2, 1 22 3 * WRTV4 v2 - 14,2 - 23 3 * SUSPEND 24 3 * PSF v1 25 4 * FREE 0xa8cebf8 27 3 * 0: 27 0 * RET 0 }} #code(c,){{ void sca() { uint i = 0; i += 1; } //----------------------------------------------------------- Temps: 2 0 0 * PUSH 2 - 18,5 - 1 2 * SUSPEND 2 2 * SetV4 v1, 0x0 (i:0, f:0) - 19,5 - 4 2 * SUSPEND 5 2 * ADDIi v1, v1, 1 - 20,2 - 8 2 * SUSPEND 9 2 * 0: 9 0 * RET 0 }} 極力組み込み型を使ったほうが良さげ。 ** 普通の関数コールvsメンバ関数コール [#d676c000] #code(c,){{ class Class { void classFunc() { } }; void callClassFunc( Class@ obj ) { obj.classFunc(); } //----------------------------------------------------------- Temps: - 48,5 - 0 0 * SUSPEND 1 0 * PSF v0 2 1 * CHKREF 3 1 * RDS4 4 1 * CALL 68 (void Class::classFunc()) - 49,2 - 6 0 * SUSPEND 7 0 * 0: 7 0 * PSF v0 8 1 * FREE 0xa8d0230 10 0 * RET 1 }} #code(c,){{ void func() { } void callFunc() { func(); } //----------------------------------------------------------- Temps: - 57,5 - 0 0 * SUSPEND 1 0 * CALL 74 (void func()) - 58,2 - 3 0 * SUSPEND 4 0 * 0: 4 0 * RET 0 }} * 改造 [#i55a2deb] 2.14.0を元にいじってます。 ** constメンバ関数対応 [#h421031a] C++コード側からのRegisterでは,constなメンバ関数が登録できるが script側からの登録はノンサポートだったので,ライブラリを改造して対応した。 |