一键导入
rebrgen-new-feature
rebrgen のコードジェネレーターに新機能を追加する時の方法と注意点。コードジェネレーターの構造の理解、共通部分と言語固有部分の整理、EBM構造の変化への対応などを扱う。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
rebrgen のコードジェネレーターに新機能を追加する時の方法と注意点。コードジェネレーターの構造の理解、共通部分と言語固有部分の整理、EBM構造の変化への対応などを扱う。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
rebrgen の設計判断を ADR として記録するか検討する。設計方針の議論、選択肢の比較、既存判断の変更、判断理由を残す場面で使用する。
rebrgen のビルド、初期セットアップ、EBM再生成、ebmcodegen復旧、新言語ジェネレーター追加を行うときに使用する。
rebrgen のコンパイルエラー、テスト失敗、想定外の挙動を調査するときに使用する。型や構造の定義から原因を追跡するデバッグ手順を提供する。
rebrgen 内部の機能、マクロ、Context型、実装場所や構造を調べるときに使用する。開発中に関連定義やAPIの所在を確認するための知識を提供する。
rebrgen の複数言語ジェネレーターにまたがるリファクタリング、共通部分の整理、EBM構造変更の影響調査を行うときに使用する。
rebrgen のコードジェネレーターへ新機能を追加するときに使用する。共通処理と言語固有処理の配置、EBM変更の判断、実装時の注意点を提供する。
| name | rebrgen-new-feature |
| description | rebrgen のコードジェネレーターに新機能を追加する時の方法と注意点。コードジェネレーターの構造の理解、共通部分と言語固有部分の整理、EBM構造の変化への対応などを扱う。 |
ebm2lang - ebm2c,ebm2go,ebm2zigなどのEBMから各言語へのコードジェネレーターの総称。ebm[cg|ip]/ディレクトリ内に実装されている。
extended_binary_module.bgn: EBMの構造を定義するファイル。EBM IRの構造を変更する場合はこのファイルを編集する必要がある。
ebmcodegen/stub/: コードジェネレーターの共通のユーティリティ関数等を置くディレクトリ。ここにはEBM IRの構造に依存しておりかつ言語固有の処理を必要としないロジックを実装することが望ましい。
ebmcodegen/default_codegen_visitor/visitor/: コードジェネレーターの共通のvisitorの実装を置くディレクトリ。ここにはEBM IRの各ノードに対応するデフォルトの処理が置かれている。
ebmgen: IRコンパイラのディレクトリである。EBM IRの物理レイアウトを編集するときはextended_binary_module.bgnを編集し、update_ebm.pyを使って更新する必要がありさらにそれに対応するロジックも追加していく必要がある。またEBM IRの論理構造を編集するときはebmgen/transform/内に処理を追加するかあるいはebmgen/convert/内のASTからEBM IRへの変換処理を編集する必要がある。
ebmcg/ebm2lang/visitor/: 各言語固有のコードジェネレーターの実装を置くディレクトリ。ebm2c, ebm2go, ebm2zigなどの各言語固有のコードジェネレーターの実装はここに置いてある。EBM IRの構造を変えない追加であっても、特定のノードを特定のパターンで変換するような追加の場合はここに処理を追加する必要がある。
ebmcg/ は ebm code generatorの略で、default codegen visitor を継承する generator を置く場所である。Result型にCodeWriterを含み、EBM IRから各言語のソースコードを組み立てる典型的なコード生成用途(C, Go, Rust, Python 等)に向いている。
ebmip/ は略称の由来こそ ebm interpreter (最初の住人 ebm2rmw が interpreter だった)だが、実体は「default codegen visitor (CodeWriter 中心) が不適な generator 全般の受け皿」 である。現在の住人は ebm2rmw(interpreter)と ebm2json(シリアライズ出力)であり、将来 ebm2ascii(可視化)等もここに入る予定。詳細は ADR 0005 を参照。
基本的にこれらの中のディレクトリ構造などはscript/ebmcodegen.pyを使って生成されているものである。手動で編集していいのは ebm[cg|ip]/ebm2lang/visitor/ディレクトリ内とebm[cg|ip]/ebm2lang/内のunictest.pyやunictest_runner.jsonなどの設定のみである。特にebm[cg|ip]/ebm2lang/visitor/ディレクトリ内はコードジェネレーターの実装が置いてある場所であるため、ここを編集することになる。
両者の具体的な差分は、ebmcg/ 側の ebm2lang::Result 型に CodeWriter が含まれている点(+ それを前提とした default hook 群の差)である。基本的には ebmcg/ のほうが使われることが多いが、インタープリタ、シリアライズ、可視化など CodeWriter 中心の default が合わないケースで ebmip/ として実装する。
機能の追加は基本的に影響範囲が不定形である。 EBM IR自体の構造を変えない追加であるとしてもそれが例えば全言語間でEBMの解釈を変える必要がある場合影響は全言語のコードジェネレーターに広がりうる。 逆にEBM IRの論理構造を変えてもそれがうまく追従して各言語に影響を及ぼさない可能性もある。だが言語数が増えるに従ってそれぞれの言語にエッジケースの処理のためのコードが存在しているため完全にそうすることはより不可能になってくるであろう。
そのため機能追加の際には必ずリグレッションしていないかを各言語ごとと確認していく必要がある。とくに影響範囲が大きい変更の場合は必ずブランチを切りmainブランチのテスト通過数からリグレッションしていないことを必ず担保する必要がある。
具体的な確認方法については/rebrgen-inter-lang-refactor スキルも参照のこと。
EBM IRの構造を変えない追加とはコード生成ロジックをいじるだけで対処できるような追加のことである。例えばコード生成の際に特定のノードの変換パターンを変えるだけで実現できる場合がこれにあたる。この場合はebmcg/ebm2lang/visitor/内の各言語固有のコードジェネレーターの実装に処理を追加することになる。この方法はEBM IRの構造を変えないため影響範囲を比較的小さく抑えることができる一方で、全言語に影響するような変更の場合は全言語のコードジェネレーターに同様の変更を加える必要があるため注意が必要である。
EBM IRの論理構造を変える追加とはEBM IRのノードの種類を増やす、あるいはノードの属性を増やすなどは行わずに参照の構造を変えるような追加のことである。例えばあるノードの子ノードの構造を変える、あるいはあるノードの属性を別のノードに移すなどがこれにあたる。この場合はebmgen/transform/内に処理を追加することで対応できる可能性がある。この方法はEBM IRの物理レイアウトを変えないため影響範囲を比較的小さく抑えることができる一方で、既存のIRの論理構造に依存しているコードが多い場合は影響範囲が広くなりすぎる可能性があるため注意が必要である。
EBM IRの物理レイアウトを変える追加とはEBM IRのノードの種類を増やす、あるいはノードの属性を増やすなどの追加のことである。例えば新しい種類のノードを追加する、あるいは既存のノードに新しい属性を追加するなどがこれにあたる。この場合はextended_binary_module.bgnを編集しupdate_ebm.pyを使って更新する必要がある。またebmgen/transform/内などに処理を追加する必要がある。この方法はEBM IRの構造を変えることができるため柔軟な対応が可能である一方で、EBM IRの構造が変わるため全体への影響が大きくなりがちであるため、変更の内容を十分に理解した上で行う必要がある。ただしこれは変更コストが大きいから躊躇しろというわけではなく必要ならばどんどん行うべきであるが、変更の内容を十分に理解した上で行う必要があるということである.
EBM IRのノードの粒度はコードジェネレーターの実装のしやすさに大きく影響する。 理想としては各言語が1ノード1言語単位で逐次変換できるような粒度が望ましい。これによりコードジェネレーターの実装が単純になり、また言語ごとのエッジケースの処理も特定のノードに集中させることができるためメンテナンス性も高まる。 が実際には途上でありEBM IRのノードの粒度は必ずしもそうなっているわけではない。特にEBM IRのノードの粒度が粗い場合はコードジェネレーターの実装が複雑になり、また言語ごとのエッジケースの処理も分散してしまうためメンテナンス性が低下する可能性がある。しかしこれは言語ごと固有の詳細をあまりにもEBM IRのノードの粒度に反映させすぎるとEBM IRの構造が複雑になりすぎるため、ある程度は仕方がない部分もある。EBM IRのノードの粒度をどこに設定するかはコードジェネレーターの実装のしやすさとEBM IRの構造の複雑さのバランスを見ながら決めていく必要がある。
ctx.config()は現時点ではctx.visitorの単純なaliasである。その中身については
default_codegen_visitor/visitor/Visitor.hppと各言語固有のvisitor/Visitor_before.hppで定義されている。
特にVisitor_before.hppの方は言語ごとに異なるため注意すること。ctx.config().*_visitorや ctx.config().*_custom, ctx.config().*_wrapperの実体はdefault_codegen_visitor/visitor/Visitor.hppに存在しておりdefault_codegen_visitor/visitor/内のデフォルトフック内で呼び出されている。命名規則の詳細は/rebrgen-inter-lang-refactorを参照。
言語数はCLAUDE.mdやSKILL.mdに書いてある時点から増えている可能性が高くまた、さらに増える可能性もあるため、そこに書いてある言語個数はあくまで参考程度にとどめて実際のディレクトリ構造とコードを確認すること。特にebmcg/ebm2lang/visitor/内のディレクトリ構造を確認すること。