5. モジュールシステム¶
モジュールシステム は ランタイム のサブシステムで、 モジュール を管理する。
module は モジュールシステム によってロードされる値である。通常、モジュールはひとつの機能グループに属する関数の集合を、変数として持つ。「モジュール」は「mod」と略される。
5.1. モジュール名¶
モジュール名は次の正規表現パターンを満たさなければならない: ([a-z_][a-z0-9_]*/)*_*[A-Z][A-Z0-9_]*
有効なモジュール名の例:
MAIN
kink/STR
kink/test/TEST
org/example/_internal/INTERNAL_MOD
com/example/_PRIVATE_MOD
5.2. モジュール基底パス集合¶
モジュールのソースはファイルシステム上のディレクトリに配置できる。これらディレクトリの一覧を モジュール基底パス集合 と呼ぶ。
モジュール基底パス集合は -p / --path コマンドラインオプションか、 MOD.add_path によって指定される。
5.3. モジュールソースの種別¶
モジュールのソースには3つの種別がある。
5.3.1. 組み込み部品¶
ランタイムはモジュールのソースとなる組み込み部品を提供する。これらモジュールは組み込みモジュールと呼ばれる。公開の組み込みモジュールの仕様については、 組み込みライブラリAPI を参照。組み込みモジュールには公開APIに含まれない、非公開のモジュールも存在する。
5.3.2. Kinkプログラムファイル¶
モジュール基底パス上のKinkプログラムファイルはモジュールのソースになり得る。Kinkプログラムファイルのパスは次の形式でなければならない: {module base path}/{module name}.kn 。ファイルはUTF-8でエンコードされていなければならない。
例として、 org/example/TARAI をモジュール名としよう。また、モジュール基底パス集合は /home/you/kinkmod と /usr/share/kinkmod だとしよう。このとき、Kinkプログラムファイルは次のパスに配置できる。
/home/you/kinkmod/org/example/TARAI.kn/usr/share/kinkmod/org/example/TARAI.kn
プログラムのトップレベルの 束縛 がモジュールになる。詳細は compile_and_run 疑似手続きを見よ。
例
次に示す org/example/rat/RAT モジュールのソースのプログラムファイルが、 /home/me/mymods/org/example/rat/RAT.kn にあるとする。
:new <- {(:Numer :Denom)
new_val(
... Rat_trait
'Numer' Numer
'Denom' Denom
)
}
:Rat_trait <- [
'numer' {[:R]
R.Numer
}
'denom' {[:R]
R.Denom
}
'repr' {[:R]
'{}/{}'.format(R.numer R.denom)
}
]
プログラムファイルclient.knが、カレントディレクトリにあるとする。client.knはRATモジュールを使う。
:RAT.require_from('org/example/rat/')
:Rat <- RAT.new(1 3)
stdout.print_line('rat: {}'.format(Rat.repr))
client.knはつぎのように実行できる。
$ kink --path /home/me/mymods client.kn
rat: 1/3
RAT モジュールは単にトップレベルの束縛なので、 Rat_trait など非公開の変数も持っている。単体テストの際には、これら非公開の変数にアクセスするのが有用かもしれない。
5.3.3. データファイル¶
モジュール基底パス上にある、任意のバイト列のファイルがモジュールのソースになり得る。データファイルのパスは次の形式でなければならない: {module base path}/{module name}.data
バイト列は バイナリ として、モジュールの data 関数を通して提供される。詳細は make_data_mod 疑似手続きを見よ。
例
データファイルのソースを使うと、任意の形式のデータをモジュールとともに配布できる。たとえば、次のようなUTF-8のテキストファイルが /home/me/mymods/org/example/conversation/_PROMPT_TEMPLATE.data にあるとする。
Your name is {Name}.
You work in {Department}.
Always state your name at the beginning of a conversation.
次に示すプログラムファイル /home/me/mymods/org/example/conversation/TOOL.kn があるとする。
:_PROMPT_TEMPLATE.require_from('org/example/conversation/')
:CHARSET.require_from('kink/charset/')
:main <- {
:Bin = _PROMPT_TEMPLATE.data
:Template = CHARSET.utf8.bin_to_str(Bin)
:Prompt = Template.format{(:C)
C.named_arg('Name' 'John Doe')
C.named_arg('Department' 'Support Department')
}
stdout.print(Prompt)
}
TOOL モジュールは main 関数を持っているから、 起動可能モジュール だ。TOOLモジュールは次のように実行できる。
$ kink --path /home/me/mymods mod:com/example/conversation/TOOL
Your name is John Doe.
You work in Support Department.
Always state your name at the beginning of a conversation.
5.4. モジュールのロード¶
モジュールは、モジュール名を指定して、モジュールシステムからロードできる。モジュールのロードは Varref.require_from または MOD.require で実行できる。モジュールのロードは三つの状態で終了する: success, not_found, compile_error
モジュールのロードは、次の疑似コードに示すように行われる:
if not is_associated(Mod_name) {
Source = find_source(Mod_name) or return not_found
if Source is a builtin component {
Mod = make_builtin_mod(Source)
} elsif Source is a Kink program file {
Mod = compile_and_run(Source) or return compile_error(Compile_error)
} else {
assert Source is a data file
Mod = make_data_mod(Source)
}
associate(Mod_name Mod)
}
return success(get_associated(Mod_name))
5.4.1. is_associated¶
is_associated 疑似手続きは、指定されたモジュール名に既にモジュールが紐付いているときに真を、そうでないときに偽を戻す。
5.4.2. find_source¶
find_source 疑似手続きは、 指定されたモジュール名に対応するモジュールのソースを探索する。探索が失敗した場合、モジュールのロードの手順は not_found の状態で終了する。 find_source は次の疑似コードのように定義できる。
def find_source(Mod_name) {
if builtin component exists for Mod_name {
return the builtin component
}
for base_dir in module_base_paths {
kn_path = base_dir + '/' + Mod_name + '.kn'
if file kn_path exists {
return file kn_path as a Kink program file
}
data_path = base_dir + '/' + Mod_name + '.data'
if file data_path exists {
return file data_path as a data file
}
}
return not_found
}
5.4.3. make_builtin_mod¶
make_builtin_mod 疑似手続きは、ランタイムの組み込み部品からモジュールを作る。
5.4.4. compile_and_run¶
compile_and_run 疑似手続きは、 モジュールのソースをコンパイルし 、コンパイルされたプログラムからモジュールを作る。コンパイルが失敗した場合、モジュールのロードの手順は compile_error の状態で終了する。
compile_and_run は次の疑似Kinkコードのように定義できる。
:BINDING.require_from('kink/')
:CHARSET.require_from('kink/charset/')
:PROGRAM.require_from('kink/porgram/')
:compile_and_run <- {(:Source)
:Text = CHARSET.utf8.bin_to_str(Source.bin)
:Program = PROGRAM.new(Source.file_path Text)
:Mod = BINDING.new
Mod:repr <- _make_repr
:run_program = Program.compile{(:C)
C.binding(Mod)
C.on_error{(:Compile_error)
_end_compile_error(Compile_error)
}
}
run_program
Mod
}
5.4.5. make_data_mod¶
make_data_mod 疑似手続きは、次の疑似Kinkコードのようにして、バイト列からモジュールを作る。
:make_data_mod <- {(:Source)
:Mod = new_val
:Bin = Source.bin
Mod:data <- {() Bin }
Mod:repr <- _make_repr
Mod
}
5.4.6. associate¶
associate 疑似手続きは、モジュール名が既にモジュールに紐付いているかをテストし、紐付いていない場合、モジュール名を指定されたモジュールに紐付ける。テストと紐付けはアトミック操作として実行される。
5.4.7. get_associated¶
get_associated 疑似手続きは、モジュール名に紐付いたモジュールを戻す。
5.5. 起動可能モジュール¶
モジュールが main 関数を持っているとき、そのモジュールはコマンドラインから起動できる。詳細は kink and kinkw commands を見よ。