Diksamのグローバル定数

Diksamには、複数ソースファイルにまたがるグローバル変数はありません。
これは私は問題ないと思っています。グローバル変数自体、そんなに使用が奨励されるものではなく、数も少ないだろうし、get_xxx()やset_xxx()関数を作ればよいだろうと。Cで言うstdinやstdoutやstderrは、実は今のDiksamではFileオブジェクトとして取得できないのですが、これについても「stdin()関数をネイティブ関数で用意しておけばよいだろう」ぐらいに思っていました。

しかしまあ、自分のドッグフードを食えとはよく言ったもので、ライブラリを作り始めてみたら、さすがにグローバル定数はないと困る、ということに気付きました……もっと早く気付けという話ですが。

というわけで、明日から実装に入ろうと思うのでメモ。

  1. 現状、関数外で宣言された変数(「トップレベル変数」と呼ぶことにします)のスコープは「ファイル内」だが、これはこのままとするつもり。
  2. トップレベル変数はfinal修飾子が付けられるけれども、これは「初期化子以外で代入できない変数」を意味する。つまり、トップレベルに置かれた宣言文が実行されないと初期化できない。しかし、Diksamでは、requireで読み込まれたソースのトップレベルは実行されない。
  3. そこで、新たなキーワードconstを導入する。「const DEFAULT_WINDOW_WIDTH = 600;」のように書くと、定数DEFAULT_WINDOW_WIDTHが定義できる。
  4. constの場合、型の指定は、右辺で完全に決まるので不要(…だと思う)
  5. constの右辺に指定できる値は定数式のみとする。定数式とは、boolean, int, double, null, string, 配列等のリテラル、およびそのソースファイルからrequireされているソースとそのソースファイルのconstの位置より前で定義されているconstにより構成される式である。…というチェックをかけたいが、当面ここは無保証で行くかも。
  6. 配列の定数や、配列のサイズを使う定数や、stdinみたいなのもあるから、コンパイル時に畳むのは無理ではないかと。
  7. そこで、DVM_Executableにはconstを保持するための配列をつけ、DVM_VirtualMachineには実行時の値を持つための配列をつけ、関数やクラスと同様の間接参照テーブルもつける。
  8. constの初期化は、ソースのロード時に一度だけ行われる。DVM_Executableは、constの初期化のためだけのバイトコードを別に持つ。dkc_generate()を2回実行しなきゃいけないかと思ったけれど、constのコード生成だけ別のOpcodeBufに吐けばいいのか……しかしそのOpcodeBufをどう持ち歩く? static? うげげ。
  9. 関係ないけどインスタンスフィールドのfinal修飾子、現在は初期化子が書けないから使えませんが、finalならオブジェクトごとに違う領域を持つ必要はないので、これってそもそも不要では? (私はソースファイルより狭い範囲のスコープに対しては冷淡なのだ)

……なんだかずいぶん大がかりになってしまいましたけど。