# Execution Pipeline 処理系は、source を AST に変換し、必要な値だけを AST interpreter で評価する。 ```text source ↓ lexer / parser ↓ desugar ↓ register root module ↓ demand-driven evaluation ├─ force thunk ├─ load imported module on demand ├─ evaluate expression ├─ compose `&` └─ patch `//` ↓ materialize ↓ data / diagnostics ``` ## lexer / parser lexer / parser は source を AST に変換する。 構文エラーはこの段階で diagnostic として報告する。 AST は arena に格納し、式や pattern は `ExprId`、`PatternId` のような ID で参照する。 ## desugar desugar は、意味論を単純にするための表層構文変換を行う。 例として、dot-path field は nested object に変換できる。 ```dcdl { feature_hoge.enable = false; } ``` ```dcdl { feature_hoge = { enable = false; }; } ``` この変換により、評価器は object field の再帰構造だけを扱えばよい。 ## module registry module registry は、読み込んだ module を canonical path で管理する。 ```text ModuleRegistry: CanonicalPath -> ModuleId ``` 処理系は、まず root module を parse / desugar して registry に登録する。 import 先 module は、この段階で全て読み込む必要はない。 import expression が評価されたとき、module registry は path を解決し、未登録なら対象 module を parse / desugar して登録する。 登録された module は module root thunk を持つ。 同じ module が複数回 import された場合は、同じ `ModuleId` を返す。 つまり import は module を即時評価しない。 module を読み込み、module root を thunk として登録するだけにする。 ## demand-driven evaluation 評価器は、必要になった thunk だけを force する。 未参照の field、let binding、import 先の field は評価しない。 この方式により、module 間に循環 import があっても、実際に force された thunk の依存が循環しない限り評価できる。 ## composition composition は、module 全体に後からかける global pass ではない。 `&` や `//` の式を評価するときに、demand-driven evaluation の中で呼ばれる演算である。 ```text eval(A & B): a = eval(A) b = eval(B) compose_and(a, b) eval(A // B): a = eval(A) b = eval(B) patch(a, b) ``` `&` は制約を保った合成を行い、`//` は右辺優先の deep patch を行う。 詳細は [Composition and Materialization](./composition-and-materialization.md) に置く。 ## resolver / binder resolver / binder は初期実装では必須ではない。 評価時に environment lookup を行えば、識別子参照は実装できる。 ただし、将来的には optional phase として追加できる余地を残す。 ```text source ↓ lexer / parser ↓ desugar ↓ resolver / binder ↓ register root module ↓ demand-driven evaluation ``` resolver / binder を追加すると、以下を早期に診断しやすくなる。 - 未定義識別子 - shadowing の扱い - reserved word の扱い - symbol interning - import path の一部静的解決 - span 付き diagnostic の精度向上 ただし、Decodal の制約検証は独立した type checking pass ではなく、`&` の合成時や materialize 時に行う。 ## materialize 通常の評価結果は runtime value であり、抽象値や default を含みうる。 外部へ出力するときだけ materialize を行い、出力可能な data に変換する。 materialize は以下を行う。 - 必要な thunk を force する。 - abstract value の default を必要に応じて force する。 - concrete value が constraint を満たすか検証する。 - 未解決の abstract value、function value などを diagnostic にする。