公開技術情報

[English] [Japanese]

Y.3 LuneScript の開発(スコープとシンボル)

LuneScript 開発の続き。

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

スコープ

LuneScript は一般的なレキカルスコープである。

また、スコープには次の種類がある。

  • 組込みスコープ
  • グローバルスコープ
  • モジュール内スコープ

組込みスコープは、 int や str などの組込みの型シンボルや、 print()string.format() などの組込みの関数シンボルなどを管理する。

グローバルスコープは、 lua のグローバルシンボル互換のシンボルを管理する。

基本的にはユーザが作成するモジュールのシンボルは、全てモジュール内スコープで管理する。

スコープの構造

スコープはツリー構造になっていて、各スコープには次の要素を保持する。

  • 親スコープ
  • スコープに属するシンボルのリスト

例えば、以下の Test.lns において、

// @lnsFront: skip
// Test.lns
fn func( val1:int ) {
  let val2 = val1 + 10;
}
func( 1 );

スコープは次の 2 つからなる。

  • @Test スコープ
  • func スコープ

@Test スコープは、 Test.lns のモジュールを管理するスコープである。 .lns ファイルは、 必ず独自のスコープを持つ。

なお、 LuneScript のモジュールは、 カレントディレクトリからの相対パスでモジュールを管理する。

相対パスが dir/Test.lns のモジュールは、 @dir スコープの中に @Test スコープを持つ。

LuneScript でのクラス

スコープは Ast.Scope クラスで管理する。

シンボル

スコープは、そのスコープに属するシンボルを管理する。

例えば以下のソースの場合、

// @lnsFront: skip
// Test.lns
fn func( val1:int ) {
  let val2 = val1 + 10;
}
func( 1 );

この @Test には、ユーザが定義している func 関数シンボルが登録される。

func スコープには、 val1 , val2 の変数シンボルが登録される。

この時のスコープとシンボルは、次のようなツリーになる。

digraph G {
rankdir=RL;

builtin[label="<builtin>"];
global[label="<global>"];
dir[label="@dir"];
dir_sym[shape="box"];
Test[label="@Test"];
Test_sym[shape="box"];
func_sym[shape="box"];
func;
val1_sym[shape="box"];
val2_sym[shape="box"];

global->builtin
dir_sym->global
dir->dir_sym
Test_sym->dir
Test->Test_sym
func->func_sym
func_sym->Test
val1_sym->func
val2_sym->func
}

../lunescript_scope.png

ここで、楕円がスコープで、四角がシンボルを示す。

シンボルの構成

シンボルは、次の属性から構成される。

  • アクセス制限
  • 名前
  • mutable/immutable

例えば以下のコードの場合、

// @lnsFront: skip
// Test.lns
fn func( val1:int ) {
  let val2 = val1 + 10;
}
func( 1 );

各シンボルは以下になる。

アクセス制限 名前 mut/imut
local func fn (int) imut
local val1 int imut
local val2 int imut

LuneScript でのクラス

スコープは Ast.SymbolInfo クラスで管理する。