MikoScript 言語仕様

 箱

 本言語では、変数、関数、オブジェクト等は、内部的には、全て「箱」で実現されてい
ます。基本的な使い方いおいて、これらは、一般的な通念と大差はないので、特に「箱」
を意識する必要はありません。しかし、これらを「箱」という概念で認識しておくと、本
言語が提供する各種の高度な機能を理解しやすくなります。
 本章では、箱の基本事項について述べます。箱の各種類ごとの詳細については、関係各
章で詳説します。

●箱の特性
 「箱」は、文字通り、入れ物としての機能を持ちます。箱の中には、整数、浮動小数点
数、文字列などの基本データだけでなく、参照、配列、関数をも格納できます。さらに、
箱の中には、別の箱を何個でも入れることができます。また、空にすることもできます。
箱は、特定のデータ型に固定されているわけではなく、その中身を任意に変更できます。

 箱には、名前が付きます。その箱名には、日本語も使えます。箱名は、その箱を含む箱
内で一義的で、同一箱内に、同一名の箱が複数個存在することはできません。別の箱内な
ら、同一名の箱があってもかまいせん。

 箱の中にデータを入れる時、つまり、箱へ代入する時、その箱の存在を事前に宣言して
おく必要はありません。代入先の箱は、代入の実行時に、所定のスコープ内で検索され、
もし見つからなければ、その時点で自動的に生成されます。しかし、箱の中身を読み出す
場合、その箱が存在しないと、例外が発生します。

 箱の中身が、他の箱への参照である場合、その箱は、参照先の箱のエイリアス(別名)
であるかのようにアクセスできます。箱はまた、通常の配列にも、連想配列にもなります。
連想配列では、その中の箱に、連想名でアクセスします。箱はさらに、通常の関数にも、
オブジェクトのメンバー関数にもなり得ます。また、DLLの呼び出し関数等にもなり
得ます。

 箱は、所定の原則に基づいて、任意に、生成、破棄、複製、移動、入れ替え、改名が可
能です。また、箱に関する各種の情報(存在性、名前、中身の種別、中身のサイズ、入れ
子の深さ、内包する箱の数、上位の箱など)は、任意に取得できます。

 箱は、任意に入れ子にできます。つまり、箱の中には、別の箱を何個でも入れることが
でき、また、その箱の中の各箱にも、同様に、別の箱を何個でも入れることができます。
これによって、箱の階層構造が形成できます。この階層構造は、言うまでもなく、動的に
可変です。

 箱の中の各箱は、任意に、並べ替えることができます。また、箱の中の各箱の出し入れ
は、当然、自由にできますが、FIFO(先入れ先出し)形式や、スタック(後入れ先出
し)形式や、双方向キュー形式などで、行なうこともできます。

 箱が破棄されると、その中の箱も全て破棄されます。

 箱の中には、他の箱の中へのスコープが設定できます。このスコープが設定されると、
その箱の中から、スコープ先の箱の中に、直接アクセスできるようになります。つまり、
その箱の中に、他の箱の中身が、あたかも追加されたようになります。このスコープは、
何個でも、任意に、追加/削除できます。このスコープは、透過的で、スコープ先の箱の
中に、さらに別の箱へのスコープが設定されていると、その箱にも直接アクセスできるよ
うになります。たとえば、箱Aに箱Bへのスコープが設定されていて、箱Bに箱Cへのス
コープが設定されている場合、箱Aから箱Cの中にも直接アクセスできます。

 オブジェクトは、階層構造をなす箱の複合体です。この階層構造は、プログラムのコン
パイル時に決定されるのではなく、実行時に自由に変化できます。
 構造体やクラスは、単なる雛型ではなく、これらもまたオブジェクトです。つまり、オ
ブジェクトは、構造体やクラスの役割を担えるということです。
 クラス間の継承関係は、前述のスコープの設定によって実現されます。したがって、そ
の継承関係は、任意に追加/削除でき、また、多重継承も可能です。
 箱は宣言なしに使用できるので、オブジェクトのメンバーの箱を、容易に仮想にできま
す。つまり、プログラムした時点では、実在しない仮想の箱でも、実行時点で、継承した
スコープ内に存在すれば、その箱が実際の対象になります。この仮想のメンバー箱は、仮
想関数としても、仮想変数としても使えます。

 箱には、入出力形式を設定できます。ファイルやバッファ内のデータの入出力は、この
入出力形式に基づいて行なわれます。そのため、各データ形態(行単位やバイト単位など)
ごとに個別の入出力関数を呼び出す必要はなく、同一の関数で、各種の形態の入出力が行
なえます。また、構造体に関しては、その各メンバーごとに逐一入出力を行なうのではな
く、全メンバーに対して、その各々の入出力形式に応じて、一気に入出力を行なうことも
できます。

●箱の種類
 箱には、構造的に大きく分けて、「値を入れる箱」と「箱を入れる箱」の2種類があり
ます。「箱を入れる箱」の中には、「値を入れる箱」でも「箱を入れる箱」でも、入れる
ことができます。これによって、箱の階層構造が形成されます。箱の階層構造全体を総称
して、「複合箱」と言います。複合箱の最も外側の箱は、必ず「箱を入れる箱」になり、
これが、その複合箱を代表します。

 箱は、その中身によって、以下の種類に分類できます。このうち、複合箱になる場合は、
(※)が付いています。この印がなければ、「値を入れる箱」です。
    ・空
    ・整数値/浮動小数点数値
    ・文字列
    ・参照
    ・関数
    ・連想配列(※)
    ・純粋配列
    ・構造体/クラス/インスタンス/オブジェクト(※)
    ・システム組み込み関数
    ・システム組み込みクラス(※)
    ・DLL呼び出し関数/DLLデータ参照

●箱の経路
 本言語システム内には多数の箱がありますが、どの箱もどこかの「場所」に登録されて
います。箱の登録されている場所を示すのが「箱の経路」です。箱の経路は、以下に挙げ
る「システムスコープ」のうちのどれかが基点になり、以降、「箱名の並び」が、外側か
ら内側へ向かって対象の箱まで続きます。「箱名の並び」は、各「箱名」を「.」または
「::」の演算子で区切って表わします、単一の箱名の場合は、その箱名だけになります。
例えば、
      A          箱 A
      A.B        箱 A の中の箱 B
      S::X.Y     箱 S の中の箱 X の中の箱 Y
 箱名は、角括弧 [ ] 演算子を使って「連想名」にすることもできます。例えば、
      Item[1]
      Age[ "太郎" ]
      [ "花子", "好き", "旅行" ]
 システムスコープは、「箱名の並び」の前に、特別な前置演算子を付けるか、あるいは、
付けないかによって、規定されます。この関係を、以下に示します。
      ::P     グローバルスコープ
       .P     メンバースコープ
       ^P     モジュールローカルスコープ
       $P     スレッドローカルスコープ
       @P     関数スタティックスコープ
        P     デフォールトスコープ
ここで、P は、任意の箱名の並びで、上記の各表記は、それぞれのスコープを基点とした
「箱名の並び P」によって規定される箱を意味します。

なお、ここで述べた演算子、スコープ、連想名に関しては、以下の各章で詳述しています。
      ・スコープ
      ・演算子
      ・連想配列

●箱の操作例
 箱の操作には、いろいろありますが、その表記は簡単です。以下にその例を示します。
    A = 1;          // 箱 A に整数値 1 を代入
    B = "Script";   // 箱 B に文字列 "Script" を代入
    C.X = 12.3;     // 箱 C の中の箱 X に、浮動小数点数値 12.3 を代入
    C.Y = A;        // 箱 C の中の箱 Y に、箱 A を複製する
    C.Z <- B;       // 箱 C の中の箱 Z に、箱 B を移動する(箱 B は無くなる)
    B'exist?        // 箱 B が存在すれば真、さもなければ偽
    D'new!;         // 箱 D を新規に生成する(中身は空)
    D'inherit( C ); // 箱 D に箱 C の中身を継承させる(箱 C 内のスコープを追加)
    E = "Great" + D.Z;  // 箱 E に文字列 "GreatScript" が入る( ここまでの操作で、
                        //   D.Z は箱 D に継承された箱 C 内の箱 Z になっている )
    R := C.X;       // 箱 R に、箱 C の中の箱 X への参照を設定
    R'name          // 箱 R の参照先の箱(箱 C の中の箱 X )の名前(この場合 "X" )
    R'level         // 箱 R の参照先の箱(箱 C の中の箱 X )の入れ子の深さを取得
                    //  (この場合 2 )
    R'up            // 箱 R の参照先の箱(箱 C の中の箱 X )の上位の箱( 箱 C )へ
                    //   の参照を取得
    R'up'count      // 箱 R の参照先の箱の上位の箱内にある箱の数(この場合 3 )
    C'sort( "+n" ); // 箱 C の中の各箱を箱名の昇順に並べ替える
    C'push( A );    // 箱 C 内の末尾に箱 A を入れる(箱 A は箱 C 内に移動)
    U <- C'first;   // 箱 C 内の最初の箱を取り出して、箱 U に移動
    V <- C'last;    // 箱 C 内の最後の箱を取り出して、箱 V に移動
    delete C;       // 箱 C を削除する(その中の箱も全て削除される)

●箱の操作関数一覧
 本言語には、箱の各種の操作用に、リレー型関数が組み込まれています。これらは、
「箱の操作」で説明します。ここでは、その一覧を示します。なお、以下では、A が、
操作対象の箱になります。
    A'exist?    箱 A の存在確認( 存在すれば「真」さもなくば「偽」 )
    A'empty!    箱 A の中身を空にする
    A'new!      箱 A を新規生成する(中身は空になる)
    A'name      箱 A の箱名を返す
    A'size      箱 A の中身のデータのサイズを返す
    A'type      箱 A の中身のデータの型式名を返す
    A'attr      箱 A の属性を取得/設定
    A'count     箱 A の中の箱の数を返す
    A'level     箱 A が最上位箱から何階層目にあるか(入れ子の深さ)を返す
    A'cbox!     箱 A を強制的に「箱を入れる箱」にする
    A'cbox?     箱 A が「箱を入れる箱」なら「真」さもなくば「偽」を返す
    A'queue!    箱 A を事象キュー用の箱として新規生成、または、強制変更する
    A'ref       箱 A への参照を返す
    A'ref?      箱 A は他の箱への参照か?
    A'alias     箱 A への最初の参照箱へのアクセス
    A'alias(i)  箱 A への第 i 番目の参照箱へのアクセス

    A'up        箱 A の上位の箱(箱 A が入っている箱)への参照を返す
    A'first     箱 A 内の最初の箱への参照を返す
    A'first(i)  箱 A 内の最初の箱から i 個先の箱への参照を返す
    A'last      箱 A 内の最後の箱への参照を返す
    A'last(i)   箱 A 内の最後の箱から i 個前の箱への参照を返す
    A'next      箱 A 内の現指示箱の次の箱への参照を返す
    A'next(i)   箱 A 内の現指示箱から i 個先の箱への参照を返す
    A'prev      箱 A 内の現指示箱の前の箱への参照を返す
    A'prev(i)   箱 A 内の現指示箱から i 個前の箱への参照を返す
    A'after     箱 A の後置箱への参照を返す
    A'before    箱 A の前置箱への参照を返す
    A'fwd       箱 A の先方箱への参照を返す
    A'bwd       箱 A の前方箱への参照を返す

    A'queue!              箱 A を双方向の出し入れ箱として生成
    A'post( X, Y ,... )   箱 A 内に項目 X,Y,... を末尾から追加する
    A'push( X, Y, ... )   箱 A 内に項目 X,Y,... を先頭から追加する
    A'pop( msec )         箱 A 内の最初の箱を取り出す(空なら msec 時間待つ)

    A'move( X, "before", Y )    箱 A 内の箱 X を箱 Y の前に移動する
    A'move( X, "after", Y )     箱 A 内の箱 X を箱 Y の後に移動する
    A'swap( B )     箱 A と箱 B の順序を入れ換える(両箱の上位箱は同一のこと)
    A'sort( f )     箱 A 内の箱を関数 f の比較結果に応じて並べ換える
    A'sort( m )     箱 A 内の箱をモード m に応じて並べ換える
    A'sort( m, k )  箱 A 内の箱をモード m に応じてキー箱名 k の比較で並べ換える
    A'rotate        箱 A 内の箱の順番を回転する
    A'reverse       箱 A 内の箱の順番を逆にする

    A'each( f )     箱 A 内の直属の箱を順に関数 f へ列挙する(フラット走査)
    A'enum( f )     箱 A 内の直系の箱を順に関数 f へ列挙する(ツリー走査)

    A'AddScope( B, C, ... )     箱 A に箱 B, C, ... 内へのスコープを追加する
    A'DelScope( B, C, ... )     箱 A から箱 B, C, ... 内へのスコープを削除する
    A'inherit( B, C, ... )      箱 A に箱 B, C, ... のメンバーの継承を追加する
    A'disherit( B, C, ... )     箱 A に箱 B, C, ... のメンバーの継承を削除する

    A'from( B )     箱 A が箱 B を継承するレベル(段数)を取得
    A'base          箱 A が直接継承する最初の基底クラスへの参照を取得
    A'base( i )     箱 A が直接継承する第 i 番目の基底クラスへの参照を取得
 リレー型関数については、別章で詳述しますが、以下の例のように、関数の実行結果を
次の関数にリレーして使えるようになっています。
    A'up'name           箱 A の上位箱(箱 A を包含する箱)の名前
    A'first(i)'type     箱 A 内の最初から i 番目の箱のデータ型式
    A'last(i)'size      箱 A 内の最後から i 番目の箱のデータサイズ

●箱の破棄
 箱は、「delete 文」で削除(明示的に破棄)できます。この文の書式は、以下のよう
になります。
    delete 箱名の並び;
ここで、「箱名の並び」は、削除対象の1つの「箱名」か、または、コンマで区切られた
複数の「箱名」になります。「箱名」は、単一の識別名だけでなく、一般には「箱の経路」
になります。「箱名」が「連想名」の場合、そのインデックスには変数が使えます。連想
名については、「連想配列」の章で詳述します。「箱名」には、削除対象の箱への「参照」
も使えます。これに関しては「参照」の章で詳述します。
 以下に、「delete 文」の例を示します。
    delete A;       // デフォールトスコープ内の箱 A を削除
    delete B, C;    // デフォールトスコープ内の箱 B と C をまとめて削除
    delete ::G;     // グローバルスコープ内の箱 G を削除
    delete ^X.Y;    // モジュールスコープ内の箱 X の中の箱 Y を削除
    delete P[i];    // 連想配列 P のインデックス i の要素を削除
 delete の対象の箱が存在しなかった場合、既に削除済みとして解釈されます。つまり、
この場合、単に無視されるだけで、例外は発生しません。

 複合箱を削除(破棄)すると、その中にある全ての箱が削除されます。例えば、連想配
列を削除すると、その中の全要素が削除されます。また、クラスインスタンスを削除する
とその全メンバーが削除されます。なお、クラスインスタンスの破棄の際には、デストラ
クタが呼ばれます。これに関しては、「クラスとインスタンス」の章で詳述します。

 あるスコープ内にある箱は、そのスコープが消滅する時に、自動的に(暗黙に)破棄さ
れます。例えば、関数ローカルスコープ内にある全ての箱は、その関数からリターンする
時に、自動的に破棄されます。また、モジュールローカルスコープ内にある全ての箱は、
そのモジュールが除去される時に、自動的に破棄されます。

 箱が削除(破棄)されると、それに割り当てられていたメモリーは全て解放されます。
解放されたメモリーは、即時、再利用可能になります。そのため、本言語システムでは、
いわゆるガーベージコレクションが、ある時、急に発生して、本来の処理が止まるという
ようなことはありません。