ワンクリックで
rebrgen-new-lang
新しい言語ジェネレーター (ebm2<lang>) の追加手順とフック実装の方法。新言語対応を始めるときに参照する。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
新しい言語ジェネレーター (ebm2<lang>) の追加手順とフック実装の方法。新言語対応を始めるときに参照する。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
rebrgen の設計判断を ADR として記録するか検討する。設計方針の議論、選択肢の比較、既存判断の変更、判断理由を残す場面で使用する。
rebrgen のビルド、初期セットアップ、EBM再生成、ebmcodegen復旧、新言語ジェネレーター追加を行うときに使用する。
rebrgen のコンパイルエラー、テスト失敗、想定外の挙動を調査するときに使用する。型や構造の定義から原因を追跡するデバッグ手順を提供する。
rebrgen 内部の機能、マクロ、Context型、実装場所や構造を調べるときに使用する。開発中に関連定義やAPIの所在を確認するための知識を提供する。
rebrgen の複数言語ジェネレーターにまたがるリファクタリング、共通部分の整理、EBM構造変更の影響調査を行うときに使用する。
rebrgen のコードジェネレーターへ新機能を追加するときに使用する。共通処理と言語固有処理の配置、EBM変更の判断、実装時の注意点を提供する。
| name | rebrgen-new-lang |
| description | 新しい言語ジェネレーター (ebm2<lang>) の追加手順とフック実装の方法。新言語対応を始めるときに参照する。 |
# 1. スケルトン生成
python script/ebmcodegen.py <lang_name>
# → src/ebmcg/ebm2<lang_name>/ が作られる
# 2. ビルド
python script/build.py
# 3. テストで未実装フック一覧を確認
mkdir -p save
python script/unictest.py --target-runner ebm2<lang_name> --print-stdout > save/unictest.txt 2>&1
grep "unimplemented" save/unictest.txt
必ず --debug-unimplemented を付ける。 これがないと未実装フックがサイレントに空文字を返すため、出力を見ても何が欠けているか分からない。
./tool/ebm2<lang>.exe -i save/some.ebm --debug-unimplemented 2>/dev/null
# → 未実装箇所に {{Unimplemented Statement_FOO N}} がインライン出力される
実装のゴールは2段階:
--debug-unimplemented 付きで {{Unimplemented ...}} が一切出なくなり、生成コードが構文的に正しいpython script/unictest.py --target-runner ebm2<lang>)フックを実装するごとにこのフラグ付きで確認し、段階的にゴール1→2を目指す。
ebmtemplate.py で生成する 🚨Editor/Write ツールで手書きしないこと。手書きするとビルドは通るがフックがサイレントに呼ばれない。
python script/ebmtemplate.py <hook>_class <lang>
# → src/ebmcg/ebm2<lang>/visitor/<hook>_class.hpp を生成
# → main.cpp の timestamp も touch される
理由: main.cpp は __has_include("visitor/<hook>_class.hpp") でフックを取り込むが、cmake は __has_include の依存を追跡しない。新規ファイル追加時に main.cpp を touch しないと再コンパイルされず、新規フックは include されず、何のエラーも出ずにスキップされる。ebmtemplate.py はこの touch まで自動でやる。
実用上のスケール感: hooklist は EBM kind × stage suffix × DSL 有無の cartesian で 4000+ 種類になるが、実際に各 backend が override してるのは 10-30 程度。default_codegen_visitor が 99 hook で大半を済ませているので、新言語追加時に書くのも一桁〜十数個になることが多い。
# 全 template 名カタログ (検索用、量に圧倒されない)
./tool/ebmcodegen --mode hooklist
# 既存言語が override してる hook を見る (← こちらが実用的)
python script/ebmtemplate.py list <lang> # 例: python, rust, go, c
python script/ebmtemplate.py list all # ebmcg 全言語
python script/ebmtemplate_ip.py list all # ebmip (interpreter 系)
python script/ebmtemplate.py list default # 共通の default 実装 (99 個、これが大半をカバー)
新言語の hook を考えるときは、近い既存言語 (例: 静的型なら rust / go、動的型なら python) の list <lang> を眺めて差分を埋める発想が早い。
ebmtemplate.py が動かない・テンプレートに無いフックを増設したい等で手書きが避けられない場合のみ:
# 1. 該当する visitor/<hook>_class.hpp を Write
# 2. main.cpp を必ず touch する (これを忘れるとサイレント失敗)
touch src/ebmcg/ebm2<lang>/main.cpp
python script/build.py
src/ebmcg/ebm2<lang>/visitor/entry_before_class.hpp の DEFINE_VISITOR(entry_before) 内で config.*_visitor に設定する。これは ebmcodegen.py のスケルトン生成時点で既に存在するファイルなので、追加 touch なしで編集 OK。量が少ない間はここに集約してよい。
DEFINE_VISITOR(entry_before) {
config.variable_define_keyword = "let mut";
config.endof_statement = ";";
// ...
config.read_data_visitor = [](Context_Statement_READ_DATA& ctx) -> expected<Result> {
using namespace CODEGEN_NAMESPACE;
if (auto lw = ctx.read_data.lowered_statement()) {
return ctx.visit(lw->io_statement.id);
}
// 言語固有の実装
return pass;
};
return pass;
}
ファイルが大きくなったら個別フックに切り出す:
python script/ebmtemplate.py Statement_FOO_class <lang>
DEFINE_VISITOR(Statement_FOO) { ... } に実装する。
ctx オブジェクトのメンバーは IDE のオートコンプリートで確認できるextended_binary_module.hpp で定義を確認する(推測しない)unit はフィールド、unit() は誤り)MAYBE(result, expr) は expected の伝搬マクロ(Rust の ? 相当)src/ebmcg/ebm2<lang>/
├── main.cpp # 自動生成(編集禁止)
├── codegen.hpp # 自動生成(編集禁止)
├── visitor/
│ ├── entry_before_class.hpp # 言語設定 + シンプルなフック
│ ├── Flags.hpp # フラグ定義
│ └── *_class.hpp # 専用ファイルに分割したフック
└── config.json # 言語設定(任意)
src/ebmcodegen/default_codegen_visitor/ にデフォルト実装がある。
まずデフォルト動作を確認してから、差分だけ上書きする方針が効率的。