¥chapter{スクリプトと名前空間}

スクリプトは、Konoha のプログラムの単位です。プログラムは、スクリプトファイルに記述され、それがロードされたのち、コンパイルされたスクリプトはScript} クラスと名前空間 NameSpace} クラスによって管理されます。本章では、Script}とNameSpace}クラスを紹介しながら、Konoha 特有のスクリプティング機能も紹介する。

== 名前空間 NameSpace}

Konohaは、大規模なソフトウェア開発を想定しているわけでないが、シンプルかつ十分な名前空間の機構を備えています。全てのスクリプトは、最初、デフォルトの名前空間 main| をもっています。

現在の名前空間は、システム変数__ns__|で確認することができます。 

{{{
>>> __ns__
"main"
}}}

システム変数__ns__|は、NameSpace}型で、現在の名前空間のオブジェクトを返す。通常、名前空間は、using文などを通して自動的に一貫性をもって管理されています。

=== クラス識別子とニックネーム*}

クラスは、class 文で宣言されたとき、その名前空間を前置名にして宣言されます。実は、これがKonoha システム内での正式なクラス識別子となります。

{{{
>>> class C ;
>>> C                          // 正式なクラス識別子
main.C
}}}

Konoha は、クラス識別子を型の名前として仕様できない。あくまでもクラス名を用います。それぞれの名前空間は、クラス名とクラス識別子を結びつけたニックネーム表をもっています。

{{{
>>> class C
>>> %dump(__ns__)             // ニックネーム表の確認
Script    main.Script
C         main.C
}}}

=== パッケージとクラス名*}

パッケージは、パッケージ名を名前空間としてもったスクリプトです。例えば、math} パッケージ内の Math}クラスは、クラス識別子はmath.Math|となります。

konoha パッケージ外の名前空間に属すクラス識別子は、自動的にニックネーム表に登録されない。そこで、明示的にニックネーム表に登録する必要があります。

using文は、もしパッケージが未ロードであればパッケージのロードを行ったのち、指定されたクラスをニックネーム表に登録するステートメントです。

{{{
>>> using math.Math;
>>> Math
math.Math
>>> %dump(__ns__)
Script    main.Script
C         main.C
Math      math.Math
}}}

もし指定したパッケージ内にニックネーム表と同じクラス名が存在する場合は、既存の名前を優先する。強制的に新しい名前を用いたい場合は、@Override|を使うこともできます。ただし、予期せぬ混乱をまねく可能性があるのであまりおすすめできない。

もし、パッケージ内の全てのクラスをロードしたい場合は、ワイルドカードを用いることができます。パッケージ内に多くのクラスが存在するときは、こちらを使うと便利です。

{{{
>>> using math.*;
}}}

また、クラス名を省略すると、パッケージのみのロード、もしくは強制的な再ロードを意味する。このときは、ニックネーム表は更新されない。

{{{
>>> using math;
}}}

== スクリプトクラス Script}}

Konoha は、スクリプトファイルを読み始める前に、新しいScript}クラスを生成する。このとき、名前空間ごとに異なるクラスを生成するため、名前空間がmain|であれば、クラス識別子は main.Script|のように生成されます。また、新しく生成されたmain.Script|は、Konohaが標準的に提供する基本パッケージkonoha.Script|の性質を継承しています。

Script}クラスとスクリプトファイルは、ちょうど class Script|宣言のブロック中にスクリプトファイルが置かれたものと考えるとわかりやすい。グローバル（に見えた）変数は、実はScript}クラスのフィールド変数に相当し、関数もScript}のメソッドとなります。Konoha言語では、それぞれ{¥bf スクリプト変数}、{¥bf スクリプト関数}と呼ばれています。

{¥it class Script}
{{{
{
// スクリプトファイル の始まり


// スクリプトファイル の終わり
}
}}}

スクリプトファイルが、通常のクラス宣言と異なる点は、直接、ステートメントを記述できる点です。（これは、{¥bf スクリプトステートメント}と呼ばれています。) 例えば、次はスクリプトステートメントの例です。

{{{
for(i = 0; i < 10; i++) print i;
}}}

スクリプトステートメントは、無名関数によってラップされて実行されます。つまり、上のスクリプトステートメントは、次のlambda()|関数定義と呼び出しと同義です。

{{{
Any lambda() {
   for(i = 0; i < 10; i++) print i;
}
lambda();
}}}

注意：次節で述べるとおり、変数 i|は、lambda()|関数内のローカル変数となるため、注意が必要です。

== スクリプト変数}

スクリプト変数は、Script}クラスのフィールド変数です。グローバル変数のように振る舞うが、実は名前空間が違えば、その名前空間に固有のScript}オブジェクトを通してアクセスしているため、参照されることはない。つまり、スクリプト変数のスコープは名前空間によって分離されています。

{{{
// スクリプト変数
card = new int[54];              // スクリプト変数
}}}

Script}クラスは、特別な@Singleton|クラスとして導入されています。インスタンスの数がひとつに限定されるため、実行中であっても一貫性を乱すことなくフィールド変数を増やすことができます。その上限数は、おおよそ128変数くらいです。上限数がはっきりしない理由は、Konohaの最適化オプションの状態で、UNBOXFIELDが採用された場合、int}とfloat}はそれぞれ2変数分の領域を消費することがあるためです。どちらにしても、通常のプログラミングにおいてスクリプト変数を使い切ることはないし、そのようなスクリプトは（メンテナンス性がないため）書いてはいけない。

ちょっとしたテクニックであるが、スクリプト中で一次的に利用する変数は、ブロックステートメントなどを利用してローカル変数として扱うこともできます。また、スクリプト変数が不足するようなプログラムはメンテナンス不能になるため、書いてはいけない。

{{{
card = new int[54];              // スクリプト変数
{
   int i;  　　　　　　　　　　 // ローカル変数
   for(i = 0; i < |card|; i++) {
      card[i] = Int.random(i);
   }
}
}}}

=== 変数スコープ}

Konoha は、単純化された３つの変数スコープをもつ。変数名は、まずローカル変数を検索し、続いてフィールド変数、最後にスクリプト変数を検索する。明示的に、フィールド変数やスクリプト変数を参照したい場合は、変数名の前に_|, __|をそれぞれ付ける。もしくは、フィールド変数、スクリプト変数を宣言するときにあらかじめ付けておいても構いません。

{{{
>>> String s = "script";         // スクリプト変数
>>> class Person {
>>> String s = "field";　        // フィールド変数
...    void test() {
...         String s = "local";  // ローカル変数
...         print s, _s, __s;
...      }
...   }
>>> t = new T();
>>> t.test()
s="local", _s="field", __s="script"
}}}

=== 定数の定義}

スクリプトの重要な役割は、定数の定義です。Konohaでは、名前ルールによって、グローバル定数、ローカル定数、クラス定数があります。

{{{
GLOBAL_ = 
LOCAL = 
Math.PI_2 = 
}}}

%== スクリプト関数}
%== スクリプトファイル}
%== main()関数}
