公開技術情報

[English] [Japanese]

Y.2 LuneScript の開発(型情報管理)

LuneScript 開発の続き。

フローの各処理概要は既に説明したので、今回は少し内部の説明に入る。

型情報

プログラミングには、データの型が重要である。

特に LuneScript は静的型付け言語なので、 データの型の管理の重要性は理解できるだろう。

なお、 LuneScript のデータの型の管理は Ast.lns でやっている。

型の管理をするソースがなんで Ast.lns なんて名前なんだ、というツッコミはあるだろうが、 それは気にしないでほしい。

型の種類

早速だが、次のコードにおいて型は幾つあるか分かるだろうか?

// @lnsFront: skip
fn func() {
  print( "hello world" );
}

答は以下の3つ。

  • func の関数型
  • print の関数型
  • "hello world" の文字列型

上記の型情報には、関数を表す型と文字列を表す型があることが分かる。

もちろん、LuneScript は他にも整数型や実数型,クラスなど様々な型をサポートしている。

型の属性

さらに、型は以下の 2 つに分けることが出来る。

  • 予めシステムに組み込んである builtin の型
  • ユーザが定義する関数やクラスなどの型

ここで問題なのが、ユーザ定義の型である。

builtin 型だけであれば、 型の情報を全てハードコーディングしておけば済むが、 ユーザ定義の型をサポートするということは、 「ユーザがどのような型を定義しているのか」ということを 動的に管理しなければならないということである。

例えば、次のユーザ定義の関数 func は、

// @lnsFront: skip
pub fn func<T>( val:T ) : &List<T> {
  return [ val ];  
}

次の構成からなる。

  • 関数名

    • func
  • アクセス制限

    • pub
  • 型パラメータ

    • T
  • 引数

    • 名前 val
    • 型 T
  • 戻り値型

    • &List<T>

このように、一言で関数といっても多くの属性情報から構成される。

なお、上記の例では示していないが、 他にも属性には abstract や static, mutable など様々な属性で構成される。

これらの構成情報を管理するのが、型情報である。

この型情報は、LuneScript では Ast.TypeInfo クラスで管理している。

型情報のバリエーション

次のコードを見て欲しい。

// @lnsFront: skip
let list1:List<int>;
let list2:&List<int>;
let list3:List<int>!;
let list4:&List<int>!;

このコードは変数 list1 〜 list4 を宣言している。

それぞれの変数の型は、下記 4 つである。

  • List<int>
  • List<int> の immutable
  • List<int> の nilable
  • List<int> の immutable の nilable

これは List<int> に対するバリエーションである。

このバリエーションは、基本的に全ての型に対して存在する。

そして、それぞれは異なる型なので、 型情報としても異なる型情報として管理する必要がある。

TypeInfo のメソッド

上記の通り、全ての型に対して imuttable, nilable の型が存在する。

そして、その型に簡単にアクセスするために、 TypeInfo には次のメソッドを用意している。

// @lnsFront: skip
   /**この TypeInfo に対する immutable な型を取得  */
   pub fn get_imutType(): &TypeInfo;
   /**この TypeInfo に対する nilable な型を取得  */
   pub fn get_nilableTypeInfo(): &TypeInfo;
   /**この TypeInfo に対する nonnilable な型を取得  */
   pub fn get_nonnilableType(): &TypeInfo;
   /**この TypeInfo に対する mutable な型を取得  */
   pub fn get_srcTypeInfo(): &TypeInfo;

例えば List<int> を管理する TypeInfo の get_imutType() を実行すると &List<int> を管理する TypeInfo が取得できる。

代入可能判定

次の関数の引数において、

// @lnsFront: skip
fn func( mut list1:List<int>, mut list2:&List<int>, 
         mut list3:List<int>!, mut list4:&List<int>! )

引数 list1 から list4 は次の代入可否関係がある。

// @lnsFront: skip
list1 = list2; // error
list1 = list3; // error
list1 = list4; // error

list2 = list1;
list2 = list3; // error
list2 = list4; // error

list3 = list1;
list3 = list2; // error
list3 = list4; // error

list4 = list1;
list4 = list2;
list4 = list3;

簡単に言えば、以下の2つである。

  • immutable から mutable への代入禁止
  • nilable から 非 nilable への代入禁止

型情報は、このような禁則制御も行なっている。

当然、型の種別が異なるデータ間の代入制御も同様に行なう。 (例えば、関数型のデータを整数型に代入する場合など)

generics

あるクラス Hoge を要素にもつ List 型の変数 list1, list2 を宣言した場合、

// @lnsFront: skip
let mut list1:List<Hoge>;
let mut list2:List<&Hoge>;

list1, list2 には次の関係がある。

// @lnsFront: skip
list1 = list2; // error
list2 = list1;

そしてこれは、先程の型情報のバリエーションとの組み合わせで制御が必要である。

class

以下のクラスの継承関係がある時、

// @lnsFront: skip
class Super {
}
class Sub extend Super {
}

それぞれの型の変数には、次の関係がある。

// @lnsFront: skip
let super = new Super();
let sub = new Sub();

super = sub;
sub = super; // error

そしてこれも、型情報のバリエーションとの組み合わせで制御が必要である。

nilable, immutable を管理するクラス

LuneScript では、nilable, immutable の型情報を以下のクラスで管理する。 なお、以下のクラスは TypeInfo のサブクラスである。

  • Ast.ModifierTypeInfo

    • immutable を管理するクラス
  • Ast.NilableTypeInfo

    • nilable を管理するクラス

以上のように、型情報を管理するのが TypeInfo の主な役割りである。