Skip to content

hawk-libs desugar: 複数ファイル・複数アプリにまたがる設計上の制約(型宣言共有 / dist出力パス衝突) #119

Description

@redpeacock78

背景

PR #118 の codex レビューで指摘された、hawk-libs desugar の「ファイルごとに個別 gawk プロセスで desugar する」アーキテクチャに起因する2つの制約。

課題1: 複数ファイルにまたがる型宣言(record/type alias)を共有できない

コメント

型宣言(record / type alias)は dsl/check.awk 内のグローバル配列(V2_RECORD_TYPE / V2_RECORD_FIELDS 等)にそのプロセス内でのみ蓄積されるため、ある include ファイルで宣言した型を entry や他の include から参照すると、desugar 時に checker がその型を認識できずエラーになる。

例:

# types.awk
record User { name: Str, age: Int }
# main.awk
@include "types.awk"
let u: User = { name: "a", age: 1 }  # types.awk の User が見えず desugar エラー

課題2: 同一 cwd から複数アプリを desugar すると dist 出力パスが衝突する

コメント

entry の出力先は dist/<basename> のみ(src_root の情報を含まない)。そのため、同じ cwd から sites/a/app.awk と sites/b/app.awk のように異なるアプリを desugar すると、どちらも dist/app.awk を取り合い、片方の出力をもう片方が上書きする。旧 mktemp 方式(プロセスごとに一意な一時ファイル)ではこの衝突はなかった。

対応方針の候補

両課題とも、現行の「ファイルごとに desugar → dist/ へ書き出し → @include を dist 接頭に書き換え」という Task 2 の設計(1 entry = 1 cwd 相対 dist ツリーという前提)を見直す規模の変更が必要。

  • 課題1: include closure を1回の compile にまとめる(型宣言を共有できる)か、型宣言だけを事前抽出して各ファイルの desugar に注入する仕組みを新設する。
  • 課題2: dist 出力パスに src_root 由来の一意な名前空間を持たせる(entry の rel path が basename だけでなく、区別可能な prefix を持つようにする)。課題1で「include closure を1つの compile unit にする」方式を採る場合、その unit 単位が自然な名前空間になり、課題2も合わせて解決できる可能性がある。

どちらも brainstorming → spec → plan の通常フローが要る規模。

スコープ

wiki 段2(template ブランチ、ファイルベースルーティング)で app/ 配下に複数ページファイルを置き、共通の型を @include で共有する構成が想定される。また将来的に複数アプリを同一ホスト・同一 cwd から動かす運用(例: monorepo 型の複数サイト運用)もあり得る。段2着手前に対応方針を決めておきたい。

課題3: publish の世代混在窓(PR #118 追記)

コメント

PR #118 で publish は「closure 全体成功後の一括 mv」になったが、mv はファイル単位なので、稼働中の hawk-serve の worker が「子は新世代・親は旧世代」の混在状態を読む数 ms の窓が残る。完全解決には generation ディレクトリ(dist/gen-N/ に全ファイルを置き、dist/current symlink の付け替え一発で切り替える等)のような単一スイッチポイントが必要で、dist レイアウト規約(課題2と同じ領域)の再設計に含めて対応する。

課題1への補足: 関数シグネチャも同様にファイル跨ぎで共有できない(PR #118 追記)

コメント

型宣言(record / type alias)だけでなく、関数シグネチャも同じ制約を受ける。include された DSL ファイルが sibling や entry で宣言された関数を呼ぶと、ファイル単位の checker が unknown function で失敗する(gawk 自体は include 跨ぎの関数分割を許容する)。例: a.awk の function a() -> Int { return b() } が b.awk の b() を参照するケース。課題1の解決方式(include closure の一括 compile または宣言の事前抽出+注入)でシグネチャ収集も同時に扱う。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions