diff --git a/docs/architecture.md b/docs/architecture.md index e4882d4..b9a18ca 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -101,6 +101,12 @@ risundle が引き受けるのは、単一翻訳単位への展開と tree-shaki - **再実行や退避のポリシー (watch モード・自動フォールバック) は持たない。** いつ再実行し、失敗時にどう逃げるかは利用者ごとに異なるポリシーであり、`watchexec` や `||` の一行で組める。 - **公開ライブラリ (lib.rs) としては提供しない。** 作業単位が「1 バンドル = テキスト入出力」と粗く、リンクしても実行時に C++ コンパイラが要る事実は消えないため、組み込みたいツールは子プロセス実行で足りる (ブラウザ連携の構想も、WASM 組み込みではなくローカル HTTP サーバーを受け口とする)。公開 API は、内部を自由にリファクタできる現状の強みを semver で縛る割に、見合う利益がない。子プロセスでは成立しない具体的な消費者が現れたら、その要求に合わせて再考する。 +## 識別子の列挙は登録時に行い、バンドルのホットパスから構造解析を追い出す + +ライブラリの定義識別子の列挙 (tree-sitter の構造解析) を `library add` の時点で行い tags.json に保存するのは、この解析がライブラリ規模に比例して重く、バンドルの支配項 (コンパイラのプリプロセス、約 0.1 秒) を超えてしまうから。バンドル時に展開後の全ライブラリコードを毎回解析する素朴な代替設計をプロトタイプで実測したところ、看板ユースケースの「全ライブラリを include したテンプレ」(Nyaan's Library 全 405 ヘッダー・展開後 1.8 MB) で 1 回あたり +1 秒超を要した。解析コストを「ライブラリを触ったときだけ」に償却することで、バンドル時のライブラリ規模依存の処理は字句解析・逆引き・ハッシュ検証といった軽いものだけになり、支配項に埋もれる。 + +この設計の代償が、ハッシュによる変更検知と `library update` の存在 (キャッシュの陳腐化をユーザーに管理させている) と、プリプロセス前の生ソースを解析することによる限界 (マクロが生成する名前が見えない、`#ifdef` は両分岐を安全側に拾う) である。展開後のファイル片を内容ハッシュキーでキャッシュしながらバンドル時に解析すれば、同じ償却構造のままこれらを解消できる見込みがある (実測と検討の記録は [#105](https://github.com/TwoSquirrels/risundle/issues/105))。 + ## tree-shaking は過剰検出側に倒す C++ の厳密な依存解析は難しいので、識別子名の照合で近似する。余分に拾う分には安全 (取りこぼしだけが依存漏れ = コンパイルエラーになる) なので、メンバ名やマクロ名まで拾っても気にしない。