AngelScript
LuaとかSquirrelは動的型スクリプト言語。
静的なものがないかと探していたらangelscriptを見つけた。
ちょっといじってみよう。
リンク
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
スクリプト実行の順序
- エンジン作成
- コールバック登録(エラー,例外時に活躍?)
- スクリプトファイルをエンジンに登録
- ビルド(コンパイル) ← さすが静的型。
- 実行
- 後片付け
includeは自前で実装しているのね。
構文
class
- public,protected,privateは無し。
- 継承もなし。
- コンストラクタ,デストラクタは有り。
- operatorは可能?(未確認)
import
他のmoduleの関数(Typeは不可)を自分のmodule内で使うための機能。
なので,一工夫したほうがいいかも。
その一例。
実装クラス(L_MathVector3)はIObjectを必ず継承する。
外部に公開する関数(F_MathVector3_*)はクラス外に宣言し,引数の先頭に必ずIObjectをとる。
他のモジュールは,公開されたその関数を通してアクセスするか,そのラッパークラス(MathVector3)を使ってアクセスする。
- C++コード
-
1
2
|
| engine->RegisterInterface("IObject");
|
- Vector3_Local.as
- こいつは,mathモジュールでのみコンパイルされる。
クラスの内部実装を記述している。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
-
|
|
|
|
|
|
-
|
!
|
|
-
|
!
!
-
|
|
!
-
|
!
-
|
!
| 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でコンパイルされる。
クラスの内部実装は書かず,内部実装が書かれている関数を呼ぶだけに留める。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
-
|
-
|
!
|
|
|
-
|
!
|
|
-
|
!
!
| 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 );
}
};
|
バイトコード
生成されるバイトコードの比較。
組み込み型vs組み込み型のラッパークラス
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
-
|
-
|
!
|
!
-
|
|
!
| 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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
-
|
|
!
| 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メンバ関数コール
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
-
|
-
!
!
-
|
!
| 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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
-
!
-
|
!
| 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
|
改造
2.14.0を元にいじってます。
constメンバ関数対応
C++コード側からのRegisterでは,constなメンバ関数が登録できるが
script側からの登録はノンサポートだったので,ライブラリを改造して対応した。