96 lines
2.6 KiB
Markdown
96 lines
2.6 KiB
Markdown
# モジュールと import
|
|
|
|
`import` は外部ファイルを読み込み、そのファイルの評価結果を返す。
|
|
|
|
## 構文
|
|
|
|
```dcdl
|
|
import "./config.dcdl"
|
|
```
|
|
|
|
import specifier は文字列リテラルとする。
|
|
パスリテラル構文は採用しない。
|
|
|
|
## モジュール
|
|
|
|
import 先はモジュール単位で読み込まれる。
|
|
ただし、モジュール全体を即時評価する必要はない。
|
|
各フィールドは thunk として保持され、必要になったときだけ評価される。
|
|
|
|
top-level に field 定義列を書いた module は、recursive module scope を作る。
|
|
つまり、top-level field は同じ module の他の top-level field から識別子として参照できる。
|
|
|
|
```dcdl
|
|
schema = {
|
|
hoge = String;
|
|
};
|
|
|
|
result = schema;
|
|
```
|
|
|
|
この場合、`result` の右辺の `schema` は同じ module の top-level field `schema` を参照する。
|
|
通常の object literal 内の field を暗黙に recursive scope にするかは別仕様とする。
|
|
|
|
## SourceLoader
|
|
|
|
`import` specifier の解決は処理系 core ではなく host 側の `SourceLoader` が行う。
|
|
CLI では、specifier を現在の module path からの相対 path として解決する。
|
|
組み込み利用では、resource table や static source map など、filesystem 以外の loader を使える。
|
|
|
|
module cache の key は loader が返す安定 key を使う。
|
|
CLI では canonical path を key とする。
|
|
|
|
## 循環 import
|
|
|
|
モジュール間に循環参照があっても、必要なフィールドの依存関係が循環していなければ評価できる。
|
|
|
|
例:
|
|
|
|
```dcdl
|
|
# main.dcdl
|
|
{
|
|
schema = {
|
|
hoge = String;
|
|
};
|
|
|
|
result = (import "./func.dcdl")(schema);
|
|
}
|
|
```
|
|
|
|
```dcdl
|
|
# func.dcdl
|
|
(input: (import "./main.dcdl").schema) =>
|
|
{
|
|
# ...
|
|
}
|
|
```
|
|
|
|
`func.dcdl` は `main.dcdl` を import しているが、参照しているのは `main.schema` である。
|
|
`main.schema` が `main.result` に依存していなければ、この循環 import は成立する。
|
|
|
|
## import の評価単位
|
|
|
|
実装上は、以下の単位で管理するのが自然である。
|
|
|
|
```text
|
|
Module main
|
|
schema -> thunk
|
|
result -> thunk
|
|
|
|
Module func
|
|
root -> thunk
|
|
```
|
|
|
|
各 thunk は一度だけ評価して memoize する。
|
|
評価中に同じ thunk へ戻った場合は循環依存としてエラーにする。
|
|
|
|
## import 失敗
|
|
|
|
以下は import 失敗として扱う。
|
|
|
|
- ファイルが存在しない。
|
|
- ファイルが読めない。
|
|
- import 先の構文解析に失敗する。
|
|
- import 先の評価で必要な値がエラーになる。
|
|
- 実装が禁止する import 循環に該当する。
|