* 構文 - Script Language [#g9284ebe]
#contents
Last-modified: &lastmod();

** このページについて [#ie2b0c1a]
AngelScript(AS)のスクリプト構文について書きます。
(このページに書かれているサンプルコードの一部はAngelScript公式のドキュメントから転載しています。)

** 「同等」と「同様」の言葉の使い方ついて [#sa64f03f]
文中で「C++と同等」と「C++と同様」という言葉を使っています。
「C++と同等」は「C++とほぼ同じ」という意味合いで,
「C++と同様」は「C++と全く同じ」という意味合いで使っています。
** 字句 [#i3b49282]
*** コメント [#oda6fcbb]
C++と同様に1行コメント,ブロックコメントの2種類が使えます。
#code(c,){{
// 1行コメント
/*
 ブロックコメント
*/
}}

*** 値 [#z1ceda31]
#code(c,){{
// 10進数表現した整数値
int a = 3; 

// 16進数表現した整数値
int b = 0xFFFF;

// 64bit浮動小数
double ca = 1.2345;
double cb = 1.2345e10;

// 32bit浮動小数
float da = 1.2345f;
float db = 1.2345e10f;

// bool値
bool ea = true;
bool eb = false;
}}
** 型 [#c13aa6fe]
*** 組み込み型 [#pb10e35e]
C++と同等の組み込み型が用意されています。

:void|
C++と同様に関数の戻り値に型に使います。

:bool|
C++と同様のもので,true,falseのどちらかの値を持ちます。

:整数|
下記のタイプが存在します。
|型名|最小値|最大値|h
|int8|-128|127|
|int16|-32768|32767|
|int&br;int32|-2147483648|2147483674|
|int64|-92233772036854775808|9223372036854775807|
|uint8|0|255|
|uint16|0|65535|
|uint&br;uint32|0|4294967295|
|uint64|0|18446744073709551615|
公式のドキュメントによると,パフォーマンスを最適化したいのであれば
32bitより小さい型の値はクラスのメンバ変数など,データを保持するもののみに使用し,
それ以外(ローカル変数,一時変数など)は32bitの型の値を使用したほうがいいようです。

:浮動小数|
下記のタイプが存在します。
|型名|値の範囲|一番小さい正の値|最大桁数|h
|float|+/- 3.402823466e+38|1.175494351e-38|6|
|double|+/- 1.7976931348623158e+308|2.2250738585072014e-308|15|
公式のドキュメントによりますと,ASではNaN(Not-aNumber)を0x7fc00000で表現しているようです。
*** 配列 [#k3346995]
配列の変数は次のように宣言します。
#code(c,){{
// int型の配列を宣言
int[] intArray;

// int型の配列を3つ宣言
int[] intArrA,intArrB,intArrC;

// 何も初期化子を指定しなければ,長さ0の配列を作ります
int[] a; // a.length() == 0

// 初期化子に数を指定すると,その数の長さの配列を作ります
int[] b(3); // b.length() == 3

// 配列初期化子を指定すると,それがコピーされた配列を作ります。
int[] c = {1,2,3}; // 先頭から1,2,3がコピーされた配列

}}

配列はC++と同様にインデクス式を使ってアクセスします。
また,配列の長さはlength()メソッドにより取得できます。
#code(c,){{
int[] a = {0,1,2};
for ( uint i = 0; i < a.length(); ++i )
{
    a[i] += 1;
}
}}
*** ユーザー定義型 [#r0f093c7]
ユーザー定義型(クラスや列挙型)の変数はC++と同様に宣言することができます。

#code(c,){{
// objという型のインスタンスが作られる
// デフォルトコンストラクタがあればそれが呼ばれる
obj a;

// objの一時変数を作成し,aに代入する
a = obj();
}}
*** オブジェクトハンドル [#t39c8cfc]
オブジェクトハンドルとはC++でいう参照・ポインタにあたるものです。
参照先のオブジェクトは参照カウンタで寿命を管理しているため,「既に破棄されたデータにアクセスする」という不正なデータアクセスはおこりません。
もしnullなオブジェクトハンドルにアクセスしようとしたら例外が発生しスクリプトの実行が止まります。

#code(c,){{
obj o;
obj@ a; // a はnullで初期化されます
obj@ b = @o; // oの参照をbに代入します

b.ModifyMe(); // o.ModifyMe()と同様のことがおこります

if ( a is null ) // nullかどうかチェックしています。
{
  @a = @b; // aにbが参照しているオブジェクトを代入します。この場合,結果的にoの参照が渡されています。
}

}}
*** 文字列 [#lec9ebac]
ASでの文字列は8bitもしくは16bitのデータの配列として扱われます。

ASではC++と同等のエスケープシーケンス文字が用意されています。
下記がエスケープシーケンス文字をまとめた表です。

|文字|値|意味|h
|¥0|0|null文字|
|¥¥|92|バックスラッシュ|
|¥'|39|シングルコーテーション|
|¥"|34|ダブルコーテーション|
|¥n|10|改行文字 LF|
|¥r|13|改行文字 CR|
|¥t|9|TAB|
|¥xFFFF|0xFFFF|16bitで表した文字|
|¥uFFFF|0xFFFF|unicode16bitで表した文字|
|¥uFFFFFFFF|¥0xFFFFFFFF|unicode32bitで表した文字|

文字列はダブルコーテーションもしくはシングルコーテーション(要オプション設定)で囲んで表します。
#code(c,){{ 
// ダブルコーテーションで囲む例
// 文字列の中にダブルコーテーションを使いたいときは,エスケープ文字を使うこと。
string str1 = "This is a string with \"escape sequences\".";

// シングルコーテーションで囲む例
// シングルコーテーションで囲むと,エスケープ文字を使わずに文中にダブルコーテーションを使うことができる
string str2 = 'If single quotes are used then double quotes can be included without "escape sequences".';

}}

C++と同様に複数の文字列を1つの文字列として連結することができます。
#code(c,){{
// strには "First Line.¥nSecondLine.¥n"が代入される
string str = "First Line.¥n"
  "Second Line.¥n";
}}

ASでは''"""''を使うことで複数行に渡す文字列を簡単に記述することができます。
#code(c,){{
// """ で始まった文字列は """で閉じる
string str = """
First Line.
Second Line.
""";
}}
** 文 [#teb1f49c]
*** 宣言文 [#ae71baed]
#code(c,){{
// 同じ型の変数はカンマで区切ることで複数宣言することができます。
int var = 0, var2 = 10;
object@ handle, handle2;

// C++と同様にconstをつけることができます
const float pi = 3.141592f;

// 組み込み型の変数の初期化子を省略した場合,値は未初期化となり不定になります
int randaomVar;

// オブジェクトハンドルの場合,nullが代入されます
object@ nullHandle;

// ユーザー定義型の場合,デフォルトコンストラクタが呼ばれます
object defaultCtorCalled;

}}
*** 式文 [#o5c9ee2d]
C++同様の式文が使えます。詳しくは式の項をご覧ください。
#code(c,){{
a = b; // 代入演算式
func(); // 関数呼び出し
}}
*** if文 [#p78a09e7]
C++同等のif文が使えます。
#code(c,){{
if( condition ) 
{
  // condition == trueのときに実行する処理
}

if( value < 10 ) 
{
  // valueが10未満のときに実行する処理
}
else
{
  // valueが10以上のときに実行する処理
}
}}

ただし,C++と異なり,C#のように条件部はbool値である必要があります。
#code(c,){{
// 条件部はbool値である必要があるため,次のコードはエラー
int notZeroValue = 1;
if ( notZeroValue ) // エラー:条件がbool値でない
{
}

// 次のように書くこと
if ( notZeroValue != 0 )
{
}

}}
*** for文 [#baebd491]
C++と同等のfor文が使えます。
ただし,条件部はif文と同じようにbool値である必要があります。

#code(c,){{
for ( int n = 0; n < 10; ++n )
{
    // 10回する処理を書く
    // ...
    

    // continueやbreakも書けます
    if ( n == 5 )
    {
        continue;
    }
    if ( n == 9 )
    {
        break;
    }
}

}}
*** while文 [#j461bb07]
C++と同等のwhile文が使えます。
ただし,条件部はif文と同じようにbool値である必要があります。

#code(c,){{  
int i = 0;
while( i < 10 )
{
    i++;

    // continueやbreakも書けます
    if ( i == 5 )
    {
        continue;
    }
    if ( i == 9 )
    {
        break;
    }
}
}}
*** do-while文 [#p5762b82]
C++と同等のdo-while文が使えます。
ただし,条件部はif文と同じようにbool値である必要があります。

#code(c,){{  
int i = 0;
do
{
    i++;

    // continueやbreakも書けます
    if ( i == 5 )
    {
        continue;
    }
    if ( i == 9 )
    {
        break;
    }
}while( i < 10 );
}}
*** switch文 [#g0b99de9]
C++と同様のswitch文が使えます。
#code(c,){{
  switch( value )
  {
  case 0:
    // value == 0のときにここに飛ぶ
    break;

  case 2:
  case constant_value:
    // value == 2 もしくは value == constant_valueのときにここに飛ぶ
    break;

  default:
    // 全ての条件に該当しない場合,ここに飛ぶ
  }
}}
*** return文 [#g7ecfbf7]
C++と同様のreturn文が使えます。

#code(c,){{
float valueOfPI()
{
    return 3.141592f; // 値を返す
}
void function()
{
    return; // 値を返さずに関数の処理を終了する
}

}}
*** スコープブロック文 [#kc357a28]
C++と同様のスコープブロック文が使えます。
#code(c,){{
  {
    int a; 
    float b;

    {
      float a; // aという同じ名前の変数を宣言したため,int aを隠してしまいます

      // float aの値をbに代入しています
      b = a;
    }

    // ここで再びint aにアクセスできるようになります
  }

}}
** 式 [#nb44a3d6]
*** 代入式 [#yeb8cb21]
C++と同様の代入式が使えます。
#code(c,){{
lvalue = rvalue;
}}

*** 代入演算式 [#r0faab26]
C++と同等の代入式が使えます。
ASのシフト演算はC++のものと異なり,左シフト,符号無し右シフト,符号有り右シフトの3種類のシフトが使えます。

#code(c,){{
lvalue += rvalue;
lvalue = value + rvalue;
}}

使用可能な代入演算記号は下記の通りです。
 += -= *= /= = &= |= ^= <<= >>= >>>=
*** 関数呼び出し [#w8040e1c]
C++と同様の関数呼び出しが使えます。
#code(c,){{
func();
func(arg);
func(arg1, arg2);
lvalue = func();
}}
*** 型変換式 [#u9e1576c]
オブジェクトハンドルの型変換の例を下記に示します。
もし,オブジェクトハンドルの型変換に失敗したらnullのオブジェクトハンドルが返されます。
#code(c,){{
  // オブジェクトハンドルの暗黙の変換
  // classがintfを継承しているときのみ可能
  intf @a = @clss();

  // オブジェクトハンドルの明示的な変換
  // 変換に失敗したらnullが返る
  clss @b = cast<clss>(a);
}}

*** 組み込み型の値の変換式 [#fa97d20e]
組み込み型の値の変換の例を下記に示します。
#code(c,){{
  // float -> intの暗黙的な変換が発生
  int a = 1.0f;

  // 明示的な変換。aをfloatに変換している
  float b = float(a)/2;
}}
*** 算術演算式 [#y7543ed9]
C++と同様の算術演算式が使えます。
 c = -(a + b);

|演算記号|説明|左項|右項|結果|h
|+|正符号演算|-|数値|数値|
|-|負符号演算|-|数値|数値|
|+|加算|数値|数値|数値|
|-|減算|数値|数値|数値|
|*|乗算|数値|数値|数値|
|/|除算|数値|数値|数値|
|%|余算|数値|数値|数値|
*** ビット演算式 [#m1f0b534]
C++と同等のビット演算式が使えます。
ASではD言語のように右シフトが2種類に増えています。

 c = ~(a | b);

|演算記号|説明|左項|右項|結果|h
|~|ビット反転|-|数値|数値|
|&|ビット論理積|数値|数値|数値|
|||ビット論理和|数値|数値|数値|
|^|ビット排他論理和|数値|数値|数値|
|<<|左シフト|数値|数値|数値|
|>>|右シフト|数値|数値|数値|
|>>>|算術右シフト|数値|数値|数値|
*** 論理演算式 [#h7b6dcbb]
C++と同等の論理演算式が使えます。
ASでは,not,and,or,xorが既存の演算記号の代わり使うことができます。
 if ( a and b or not c ) {}

|演算記号|説明|左項|右項|結果|h
|not&br;!|論理否定|-|bool値|bool値|
|and&br;&&|論理積|bool値|bool値|bool値|
|or&br;|||論理和|bool値|bool値|bool値|
|xor|排他論理和|bool値|bool値|bool値|
*** 等値式 [#de0709a3]
C++と同様の等値式が使えます。

#code(c,){{
if ( a == b )
{
}
if ( a != b )
{
}
}}
*** 比較式 [#j1bc3347]
C++と同様の比較式が使えます。
#code(c,){{
if ( a < b ) {}
if ( a <= b ) {}
if ( a > b ) {}
if ( a >= b ) {}
}}

*** 同一性式 [#n6064dbf]
2つのオブジェクトハンドルが示すものが同じかどうかを調べる式です。
#code(c,){{
object@ a,b;
if ( a is null )
{
    // aがnullのときに実行される処理
}
if ( a !is null )
{
    // aがnullでないときに実行される処理
}
if ( a is b )
{
    // aとbが同じオブジェクトを指している,もしくは両方ともnull
}
}}


*** インクリメンタル式・デクリメンタル式 [#l7f3b00c]
C++と同様のインクリメンタル式,デクリメンタル式が使えます。
#code(c,){{
// a = i; i += 1; と同じ意味
a = i++;

// i += 1; b = i; と同じ意味
b = ++i;

// c = i; c -=1; と同じ意味
c = i--;

// i -= 1; d = i; と同じ意味
d = --i;
}}
*** インデクス式 [#d8d6583e]
C++と同様のインデクス式が使えます。
添え字に使う型は,インデクス式がオーバーロードできるためオブジェクトのタイプごとに異なります。
 arr[i] = 1;
*** 条件式 [#f2128c3e]
C++と同等の三項条件式が使えます。
if文と同様に,条件部はbool値である必要があります。
 condition ? a : b;
*** メンバアクセス [#k8d2dc13]
 object.property = 1;
 object.method();

C++と同様にオブジェクトのメンバにアクセスできます。

ASではオブジェクトにプロパティアクセサを持つことができるため
メンバ変数にアクセスしているように見えて,実際は関数を呼び出しているということもありえます。
詳細はクラスのプロパティアクセサの項をご覧ください。
*** オブジェクトハンドルアクセス [#p581d30b]
オブジェクトのハンドルにアクセスする際に頭に''@''をつけます。
この記号を使うことで,オブジェクトハンドルが指すオブジェクトを変更したり,参照したりします。

#code(c,){{
  // objectが指すオブジェクトの参照をhandleにコピー
  @handle = @object;

  // handleが指すオブジェクトをnullに設定
  @handle = null;
}}
*** 丸括弧 [#ue94adc4]
C++と同様の丸括弧が使えます。
 a = c * ( a + b );
*** スコープ解決 [#zae249e6]
C++に似たスコープ解決演算子が使えます。
''::''を使うことでグローバル変数・関数を指定することができます。

#code(c,){{
  int value;
  void function()
  {
    int value;        // グローバル変数のvalueを隠してしまう
    ::value = value; // グローバル変数のvalueにローカル変数のvalueを代入している
  } 
}}
** オブジェクトハンドル [#o1d47802]
オブジェクトハンドルはオブジェクトの参照を保持することができる型です。
オブジェクトハンドルを使うことで,1つのオブジェクトを複数の変数からアクセスできるようになります。
C++でいうポインタや参照と同じようなものだと考えてください。
*** オブジェクトハンドル変数の宣言 [#la326047]
オブジェクトハンドルの型は型名 + ''@''で表現します。
 object@ obj_h;
このコードでは,obj_hにnull参照が保持されます。
null参照が保持されている状態は,オブジェクトの参照を保持していない状態と考えてください。

*** メンバへのアクセス [#xf43511b]
オブジェクトハンドルが参照しているオブジェクトのメンバへのアクセスは
通常のオブジェクトのメンバへのアクセスと同じようにアクセスします。
 object obj;
 object@ obj_h;
 obj.Method();
 obj_h.Method();
もし,オブジェクトハンドルがnull参照を保持している状態でメンバへアクセスしようとすると
例外が発生し,実行中のスクリプトが停止します。

*** 値のコピー [#f66cb352]
オブジェクトハンドルの変数に対して代入演算子''=''を使うと,
通常のオブジェクト変数に対して代入演算を記述したときと同じことが行われます。
 object obj;
 object@ obj_h;
 obj_h = obj;
もちろん,オブジェクトハンドルがnull参照を保持している場合は例外が発生します。

*** 参照のコピー [#l6496ebe]
オブジェクトハンドルが保持する参照をコピーしたい場合は''@''記号を使います。
 object obj;
 object@ obj_h;
 @obj_h = @obj;

*** 同一性チェック [#qbfc7e03]
同一性式を使うことで,2つのオブジェクトハンドルが同じオブジェクト参照を保持しているか調べることが出来ます。
 object@ obj_a, obj_b;
 if ( obj_a is obj_b ) {}
 if ( obj_a !is null ) {}
*** オブジェクトの寿命 [#b7126457]
オブジェクトハンドルが参照するオブジェクトは
全てのオブジェクトハンドルから参照を保持されなくなった時点で解放されます。

#code(c,){{
  object@ obj_h;
  {
    object obj;
    @obj_h = @obj;

    // 通常は,スコープブロックの終了時にオブジェクトは解放されます
    // しかし,オブジェクトハンドルが参照を保持しているため,ここでは解放されません
  }

  // obj_hはオブジェクトの参照を保持しているため,メンバにアクセスすることができます
  obj_h.Method();

  // このように,明示的にオブジェクトハンドルの参照を解除するか
  // スコープを抜けるタイミングでオブジェクトは解放されます
  @obj_h = null;
}}
*** ポリモフィズム [#xe49a700]
オブジェクトハンドルを使うことで基底クラス・インターフェースのへの変換やダウンキャストを実現します。

#code(c,){{
  interface I {}
  class A : I {}
  class B : I {}

  // インターフェースとして,オブジェクトハンドルに参照を保持させる
  I @i1 = A();  
  I @i2 = B();

  void function(I @i)
  { 
    // ダウンキャストをする場合,cast演算を使って変換を試みます
    A @a = cast<A>(i);
    if( a is null )
    {
      // ダウンキャストに失敗すればnull参照が格納されます
    }
    else
    { 
      // ダウンキャストに成功すれば有効な参照が格納されます
    }
  }

}}
** 関数 [#q7b2e2c2]
** 変数 [#d428e214]
** インターフェース [#w64b11fd]
ASのインターフェースはC#やD言語と同等のものと考えてもらって構いません。
インターフェースにはC++でいう純粋仮想関数を宣言することができます。
ただし,C#やD言語のインターフェースとは異なり,インターフェースが他のインターフェースを継承することはできません。
その代わり,クラスは複数のインターフェースを継承することができます。

#code(c,){{
  // インターフェースの宣言
  interface MyInterface
  {
    void DoSomething();
  }

  // MyInterfaceを実装するクラスの宣言
  class MyClass : MyInterface
  {
    void DoSomething()
    {
    }
  }

  // 複数のインターフェースの継承例
  interface IntfA {} 
  interface IntfB {}
  class Example : IntfA , IntfB {}

}}
** import [#o4ad69c4]
** 列挙型 [#ff101c74]
C++と同様のenumが使えます。

#code(c,){{
  enum MyEnum
  {
    eValue0,
    eValue2 = 2,
    eValue3,
    eValue200 = eValue2 * 100
  }
}}
** typedef [#c9cfcf91]
** クラス [#ee65bf14]
*** 使い方 [#o29dc089]
*** 演算式オーバーロード [#wd33cb58]
*** プロパティアクセサ [#l3502fb8]

    ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS