fix(joinir): Phase 241-EX - Remove hardcoded 'sum' check from Pattern3

Remove legacy hardcoded 'sum' carrier validation that was blocking
array_filter patterns with different accumulator names (e.g., 'out').

Before: Pattern3 required carrier named 'sum' to exist
After: Pattern3 uses carrier_info generically (any carrier name works)

Test results:
- phase49_joinir_array_filter_smoke: PASS 
- phase49_joinir_array_filter_fallback: PASS 
- phase49_joinir_array_filter_ab_comparison: PASS 
- Full suite: 909/909 PASS, 0 FAIL

Also: Archive old roadmap documentation (67k lines moved to docs/archive/)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-11 00:48:42 +09:00
parent a7dbc15878
commit 811dfebf98
387 changed files with 106 additions and 5551 deletions

View File

@ -0,0 +1,117 @@
# ABI移行タイミング詳細検討
## 🎯 現状分析
### 現在のTypeBox実装
- **TLVベース統一** - `invoke_id`ですべてのメソッド呼び出し処理
- **7つのプラグイン** - String/Integer/Array/Map/Console/File/Egui
- **問題なく動作** - 機能的には十分、パフォーマンスも実用レベル
### LLVM層の進捗
- ChatGPT5がLLVM実装改善中
- PHI/ターミネーター問題を解決中
- BuilderCursor導入で構造化
- EXE生成までもう少し
## 🔄 移行オプション検討
### Option 1: 今すぐ移行開始
**メリット**
- プラグイン数が少ない7個今がチャンス
- 早期のパフォーマンス改善
- 技術的負債を早めに解消
- Phase 16に向けた準備
**デメリット**
- LLVM作業と並行→リソース分散
- 優先度の問題LLVM > ABI
- 現行で問題ないのに変更リスク
### Option 2: LLVM完成後に移行推奨
**メリット**
- **集中できる** - まずLLVM完成に全力
- **最適化考慮** - LLVM/JITの特性を踏まえた設計
- **一度の変更** - まとめて最適な形に
- **実証データ** - LLVM性能を見てから判断
**デメリット**
- 移行が遅れる(でも急ぐ必要ない)
- TLVオーバーヘッド継続でも実用上問題なし
### Option 3: 段階的準備
**今できること**
1. struct_size活用コードの準備
2. ドキュメント整理(完了✅)
3. 拡張計画の詳細化
4. テストコード準備
**LLVM後にやること**
1. create/destroy追加
2. プラグイン順次対応
3. パフォーマンス測定
4. 最適化
## 📊 判断基準
### なぜLLVM完成後が最適か
1. **優先度の明確化**
- 現在の最重要課題:セルフホスティング
- LLVM完成 → EXE生成 → セルフホスト実現
- ABIは「改善」であって「必須」ではない
2. **設計の最適化**
- LLVMの最適化特性を理解してから
- インライン化可能性の考慮
- JIT/AOTでの扱いの違い
3. **リスク管理**
- 動いているものを変えるリスク
- LLVM作業への影響を避ける
- 一度に大きく変える方が安全
4. **実装効率**
- ChatGPT5がLLVM集中できる
- 混乱を避ける
- 明確なマイルストーン
## 🚀 推奨ロードマップ
### Phase 15現在
1. **LLVM完成に集中**
2. EXE生成実現
3. セルフホスト基盤確立
4. ABI拡張の詳細設計並行
### Phase 15.5LLVM完成直後
1. **ABI拡張実装**
- create/destroy追加
- struct_size活用
- 互換性維持
2. **プラグイン移行**
- 性能重要なものから
- 段階的に対応
3. **パフォーマンス検証**
### Phase 16次フェーズ
1. **ABI安定化宣言**
2. 外部開発者向けドキュメント
3. 他言語バインディング
## 🎯 結論
**LLVM完成後の移行が最適**
理由:
1. 現在のTLVベースで機能的問題なし
2. LLVM完成が最優先セルフホストへの道
3. 最適化知見を活かした設計可能
4. リスク最小化・効率最大化
**ただし準備は今から**
- ドキュメント整理(完了✅)
- 設計詳細化
- テスト準備
- 移行計画策定
これにより、LLVM完成後にスムーズに移行開始できる。

View File

@ -0,0 +1,469 @@
# Phase 15: セルフホスティング技術詳細
## 1. アーキテクチャ設計
### 1.1 全体構成
```
NyashCompiler (Nyashで実装)
├── Frontend
│ ├── Lexer (トークナイザー)
│ ├── Parser (構文解析)
│ └── AST Builder
├── Middle-end
│ ├── Type Checker
│ ├── Name Resolver
│ ├── MIR Lowerer (→13命令)
│ └── Optimizer
└── Backend複数選択可能
├── CraneliftBox (JITラッパー)
├── X86EmitterBox (直接エミッタ)
├── TemplateStitcherBox (超小型)
└── Runtime Linker
```
### 1.2 CompilerBox設計
```nyash
box CompilerBox {
init {
lexer, // トークン解析器
parser, // 構文解析器
lowerer, // MIR生成器
optimizer, // 最適化器
backend // コード生成器
}
// ソースコードからASTを生成
parse(source) {
local tokens = me.lexer.tokenize(source)
local ast = me.parser.parse(tokens)
return ast
}
// ASTからMIRを生成
lower(ast) {
local mir = me.lowerer.lower(ast)
return me.optimizer.optimize(mir)
}
// MIRから実行可能コードを生成
codegen(mir) {
return me.backend.generate(mir)
}
// 完全なコンパイルパイプライン
compile(source) {
local ast = me.parse(source)
local mir = me.lower(ast)
return me.codegen(mir)
}
}
```
## 2. パーサー実装Nyash版
### 2.1 Lexer実装例
```nyash
box Lexer {
init { keywords, operators }
constructor() {
me.keywords = new MapBox()
me.keywords.set("box", TokenType.BOX)
me.keywords.set("if", TokenType.IF)
me.keywords.set("loop", TokenType.LOOP)
// ... 他のキーワード
me.operators = new MapBox()
me.operators.set("+", TokenType.PLUS)
me.operators.set("-", TokenType.MINUS)
// ... 他の演算子
}
tokenize(source) {
local tokens = new ArrayBox()
local position = 0
loop(position < source.length()) {
local char = source.charAt(position)
if me.isWhitespace(char) {
position = position + 1
continue
}
if me.isDigit(char) {
local token = me.readNumber(source, position)
tokens.push(token)
position = token.end
continue
}
if me.isLetter(char) {
local token = me.readIdentifier(source, position)
tokens.push(token)
position = token.end
continue
}
// ... 他のトークン種別
}
return tokens
}
}
```
### 2.2 Parser実装例
```nyash
box Parser {
init { tokens, current }
parse(tokens) {
me.tokens = tokens
me.current = 0
return me.parseProgram()
}
parseProgram() {
local statements = new ArrayBox()
loop(not me.isAtEnd()) {
local stmt = me.parseStatement()
statements.push(stmt)
}
return new ASTNode("Program", statements)
}
parseStatement() {
if me.match(TokenType.BOX) {
return me.parseBoxDeclaration()
}
if me.match(TokenType.IF) {
return me.parseIfStatement()
}
// ... 他の文種別
return me.parseExpression()
}
}
```
## 3. MIR生成器実装
### 3.1 Lowerer実装例
```nyash
box MIRLowerer {
init {
current_block,
value_counter,
block_counter,
locals
}
lower(ast) {
me.value_counter = 0
me.block_counter = 0
me.locals = new MapBox()
local mir = new MIRModule()
me.lowerNode(ast, mir)
return mir
}
lowerExpression(node, mir) {
if node.type == "BinaryOp" {
local left = me.lowerExpression(node.left, mir)
local right = me.lowerExpression(node.right, mir)
local result = me.newValue()
mir.addInstruction(new BinOp(
node.operator,
left,
right,
result
))
return result
}
if node.type == "Literal" {
local result = me.newValue()
mir.addInstruction(new Const(node.value, result))
return result
}
// ... 他の式種別
}
}
```
## 4. バックエンド実装
### 4.1 CraneliftBox実装
```nyash
box CraneliftBox {
init { jit_module, func_ctx }
constructor() {
// CraneliftをFFI経由で初期化
me.jit_module = ExternCall("cranelift_new_module")
me.func_ctx = ExternCall("cranelift_new_context")
}
compile(mir) {
local compiled_funcs = new MapBox()
// 各関数をコンパイル
for func in mir.functions {
local code = me.compileFunction(func)
compiled_funcs.set(func.name, code)
}
return compiled_funcs
}
compileFunction(mir_func) {
// MIR → Cranelift IR変換
ExternCall("cranelift_begin_function", me.func_ctx)
for inst in mir_func.instructions {
me.emitInstruction(inst)
}
// JITコンパイル
return ExternCall("cranelift_finalize_function", me.func_ctx)
}
}
```
### 4.2 X86EmitterBox実装直接x86生成
```nyash
box X86EmitterBox {
init { code_buffer, label_map }
constructor() {
me.code_buffer = new ArrayBox()
me.label_map = new MapBox()
}
compile(mir) {
// MIR 13命令を直接x86-64に変換
for func in mir.functions {
me.emitFunction(func)
}
return me.code_buffer
}
emitInstruction(inst) {
// MIR命令をx86テンプレートに変換
if inst.type == "Const" {
// mov rax, imm64
me.emit_mov_imm(inst.dst, inst.value)
}
if inst.type == "BinOp" {
if inst.op == "Add" {
// add rax, rbx
me.emit_add(inst.dst, inst.left, inst.right)
}
}
if inst.type == "BoxCall" {
// mov rdi, receiver
// mov rax, [rdi] ; vtable
// call [rax+slot*8] ; method call
me.emit_boxcall(inst.recv, inst.slot)
}
// ... 残り10命令のテンプレート
}
emit_mov_imm(reg, value) {
// REX.W + mov r64, imm64
me.code_buffer.push(0x48) // REX.W
me.code_buffer.push(0xB8 + reg) // mov opcode
// 64ビット即値をリトルエンディアンで
for i in range(0, 8) {
me.code_buffer.push((value >> (i * 8)) & 0xFF)
}
}
}
```
### 4.3 テンプレート・スティッチャ実装(超小型バイナリ)
```nyash
box TemplateStitcherBox {
init { stub_addresses, jump_table }
constructor() {
// 各MIR命令の共通スタブアドレス
me.stub_addresses = new MapBox()
me.stub_addresses.set("Const", 0x1000)
me.stub_addresses.set("UnaryOp", 0x1100)
me.stub_addresses.set("BinOp", 0x1200)
me.stub_addresses.set("Compare", 0x1300)
me.stub_addresses.set("TypeOp", 0x1400)
me.stub_addresses.set("Load", 0x1500)
me.stub_addresses.set("Store", 0x1600)
me.stub_addresses.set("Branch", 0x1700)
me.stub_addresses.set("Jump", 0x1800)
me.stub_addresses.set("Return", 0x1900)
me.stub_addresses.set("Phi", 0x1A00)
me.stub_addresses.set("BoxCall", 0x1B00)
me.stub_addresses.set("ExternCall", 0x1C00)
}
compile(mir) {
me.jump_table = new ArrayBox()
// プログラムはスタブへのジャンプ列として表現
for inst in mir.instructions {
local stub_addr = me.stub_addresses.get(inst.type)
// jmp rel32
me.jump_table.push(0xE9) // jmp opcode
me.jump_table.push_rel32(stub_addr)
// 命令固有のパラメータをデータセクションに配置
me.encodeParameters(inst)
}
return me.jump_table
}
}
```
## 5. ブートストラップ手順
### 5.1 段階的移行
1. **Stage 0**: Rustコンパイラで初期Nyashコンパイラをビルド
2. **Stage 1**: Stage 0コンパイラでNyashコンパイラNyash版をコンパイル
3. **Stage 2**: Stage 1コンパイラで自分自身をコンパイル
4. **検証**: Stage 1とStage 2の出力が同一であることを確認
### 5.2 検証スクリプト
```nyash
box BootstrapVerifier {
verify() {
// Stage 0でStage 1をビルド
local stage0 = new CompilerBox() // Rust版
local stage1_code = stage0.compile(readFile("compiler.hako"))
// Stage 1でStage 2をビルド
local stage1 = stage1_code.instantiate()
local stage2_code = stage1.compile(readFile("compiler.hako"))
// バイナリ比較
if stage1_code.equals(stage2_code) {
print("🎉 Bootstrap successful!")
return true
} else {
print("❌ Bootstrap failed - outputs differ")
return false
}
}
}
```
## 6. 性能最適化
### 6.1 ホットパス最適化
```nyash
box OptimizingCompiler from CompilerBox {
init { profiler }
constructor() {
from CompilerBox.constructor()
me.profiler = new ProfilerBox()
}
compile(source) {
// プロファイル収集モード
if me.profiler.isEnabled() {
me.profiler.start()
}
local result = from CompilerBox.compile(source)
// ホット関数をJIT再コンパイル
if me.profiler.hasHotFunctions() {
for func in me.profiler.getHotFunctions() {
me.recompileWithOptimization(func)
}
}
return result
}
}
```
## 7. エラー処理とデバッグ
### 7.1 エラーレポート
```nyash
box CompilerError {
init { message, location, suggestions }
format() {
local output = "Error at " + me.location + ": " + me.message
if me.suggestions.length() > 0 {
output = output + "\nSuggestions:"
for suggestion in me.suggestions {
output = output + "\n - " + suggestion
}
}
return output
}
}
```
## 8. テストフレームワーク
```nyash
box CompilerTest {
testParser() {
local parser = new Parser()
local ast = parser.parse("box Test { }")
assert(ast.type == "Program")
assert(ast.children.length() == 1)
assert(ast.children[0].type == "BoxDeclaration")
}
testMIRGeneration() {
local compiler = new CompilerBox()
local mir = compiler.lower(compiler.parse("1 + 2"))
assert(mir.instructions.length() == 3) // 2 Const + 1 BinOp
}
testEndToEnd() {
local compiler = new CompilerBox()
local code = compiler.compile("print('Hello')")
local output = code.run()
assert(output == "Hello")
}
}
```
このようにして、NyashでNyashコンパイラを実装することで、真のセルフホスティングを実現します。

View File

@ -0,0 +1,139 @@
# Phase 15 自己ホスティング準備メモ - 箱積み上げ戦略
Date: 2025-09-03
Author: Claude + にゃ
## 基本理念:箱を下にして積み重ねる
- フォールバック不要、Rust依存なしEXEライブラリのみ
- 一度置いた箱は動かさない
- 下の箱が安定なら、上も安定
- 複雑さは敵、シンプルさは友
## 基礎Box群の階層構造
### 第1層最下層これがないと何も始まらない
- **MemoryBox**: メモリ管理
- **StringBox**: 文字列処理
- **ArrayBox**: 配列操作
- **MapBox**: 連想配列
- **ErrorBox**: エラー処理
### 第2層言語処理の基礎
- **TokenBox**: 字句解析
- **ASTBox**: 構文木
- **SymbolBox**: シンボルテーブル
- **ScopeBox**: スコープ管理
### 第3層コンパイラコア
- **ParserBox**: パーサー
- **MIRBox**: 中間表現13命令
- **OptimizerBox**: 最適化
- **GeneratorBox**: コード生成
### 第4層実行系
- **InterpreterBox**: インタープリター
- **VMBox**: 仮想マシン
- **JITBox**: JITコンパイラCranelift
- **LinkerBox**: リンカーlld
## 準備期間の研究項目
### 1. 依存関係マップ作成
- 何が何に依存?
- 最小限の依存で最大の効果
- 循環依存の排除
### 2. インターフェース設計
- 全Boxの共通プロトコル
- 入力/出力の標準化
- エラー処理の統一
### 3. ビルド順序の科学
- Day 1: 基礎Box群
- Day 2: 言語処理層
- Day 3: コンパイラ層
- 完成まで一直線
### 4. 最小ブートストラップセット
- 自分自身をコンパイルできる最小構成
- 必須機能の特定
- 段階的な機能追加
## 箱の品質保証原則
1. **単体で完結** - 他に依存しすぎない
2. **明確な責務** - 1つの箱は1つの仕事
3. **テスト可能** - 単独で動作確認
4. **不変インターフェース** - 一度決めたら変更なし
## 実装戦略
1. Rust実装の機能分解Box単位
2. 各Boxの仕様書作成
3. テストケースの移植計画
4. Box間プロトコル設計
5. 最小実装から始める
6. 増分的に機能追加
## 成功の鍵
- 準備こそすべて
- 急いで実装より、じっくり設計
- 箱を積み重ねれば必ず頂上に到達
- フォールバックなし、後戻りなし、前進あるのみ
## 革新的アイデア
### 1. BoxDNA設計書
- 各Boxの入力/出力/依存を明文化
- 遺伝子のように継承・組み合わせ
### 2. 増分コンパイル対応
- 変更部分だけ再コンパイル
- 開発効率の向上
### 3. 可視化ツール
- 進捗の見える化
- 依存関係の図示
## 数値目標
- **80,000行 → 20,000行**75%削減)
- **MIR13命令**で全機能実現
- **ビルド時間**1分以内
- **テストカバレッジ**90%以上
## コンテキスト圧縮対策
### 1. ANCP活用Phase 12.7
- 90%圧縮でAIコンテキスト節約
- [ANCP仕様書](../../../phase-12.7/ancp-specs/ANCP-Token-Specification-v1.md)
### 2. モジュール分割開発
- 各Boxを独立して開発
- 統合は最後に実施
### 3. AI協調開発
- Claude実装担当
- ChatGPT5リファクタリング
- Geminiレビュー
- Codexデバッグ支援
## 関連ドキュメント
- [自己ホスティングlld戦略](./lld-strategy.md)
- [Phase 15 README](../README.md)
- [Phase 12.7 ANCP](../../../phase-12.7/)
- [MIR13命令セット](../../../../../reference/mir/INSTRUCTION_SET.md)
## 次のアクション
1. このメモをベースに詳細設計
2. Box依存関係グラフの作成
3. 最小実装セットの確定
4. 各Boxの仕様書ドラフト
---
「箱を積み上げて、世界一美しいコンパイラを作るにゃ!」

View File

@ -0,0 +1,196 @@
# Phase 15 自己ホスティング実装戦略 - MIR→Cranelift→lld
Author: ChatGPT5 + Claude協議
Date: 2025-09-03
Version: 1.0
## 📋 概要
Nyash完全自己ホスティングを実現するための具体的実装戦略。
**「MIR→Craneliftで.o/.objを作る→lldでEXEを組む」**をNyashツールチェーンに内蔵する。
## 🎯 最終形(自己ホスト時の一発ボタン)
```bash
nyash build main.ny \
--backend=cranelift \
--target=x86_64-pc-windows-msvc # or x86_64-unknown-linux-gnu
```
内部処理フロー:
1. **frontend**: AST→MIR13
2. **codegen**: MIR→Cranelift→`.obj/.o`
3. **link**: `lld-link`(Win) / `ld.lld`(Linux)でEXE生成
4. 依存ランタイム`nyashrt`を自動リンク(静的/動的選択)
## 🏗️ 実装の芯(最小で美しいやつ)
### 1. コード生成ライブラリC ABIファサード
```c
// 最小限の美しいインターフェース
ny_mir_to_obj(mir_bin, target_triple) -> obj_bytes
ny_mir_jit_entry(mir_bin) -> exit_code // 開発用
ny_free_buf(buffer) // メモリ解放
// エラーハンドリング
// 例外は戻り値NyErrunwind禁止
```
実装のポイント:
- 返却メモリは`ny_free_buf`で解放
- 例外は戻り値NyErrで統一unwind禁止
- C ABIで安定した境界を作る
### 2. リンカー・ラッパ(プラットフォーム別)
#### Windows
- 既定: `lld-link`
- 主要フラグ:
```bash
lld-link <objs...> nyashrt.lib /SUBSYSTEM:CONSOLE \
/OUT:a.exe /ENTRY:nyash_entry \
/LIBPATH:<sdk/lib> /MACHINE:X64
```
- MSVC互換が要る配布向けに`/fallback:link.exe`オプションも用意可
#### Linux
- 既定: `ld.lld`(開発で`mold`併用可)
```bash
ld.lld -o a.out main.o -L. -lnyashrt -lc -lm -pthread \
--gc-sections --icf=all
```
#### macOS将来
- 日常は`ld64.lld`、配布はXcodeの`ld64` + コード署名要Entitlements
### 3. 同梱/検出戦略
**優先順**: 埋め込み`lld` → システム`lld` → 代替mold/link.exe/ld64
```bash
nyash toolchain doctor # 検出&パス設定
--linker=lld|mold|link.exe|ld64 # 明示上書き
```
### 4. ランタイム同梱
- `nyashrt`を**static.a/.lib**と**shared.so/.dll**両用意
- 既定は**static**(配布が楽)、`--shared-rt`で動的リンクに切替
- Windowsは**PDB生成**、Linuxは`-g`/`-Wl,--build-id`でデバッグ容易に
## 🔧 エラー整合(ビルド失敗をわかりやすく)
| エラー種別 | 戻り値 | 説明・対処 |
|----------|-------|-----------|
| `ny_mir_to_obj`失敗 | `NYCG_ERR_*` | ターゲット不一致/CLIF生成失敗など |
| リンク失敗 | リンカ標準出力 | ファイル名/未解決シンボルを整形表示 |
診断オプション:
```bash
--emit=clif,asm,obj,link-cmd # 診断をファイル出力(再現しやすい)
```
## 💾 キャッシュ&クロスコンパイル
### オブジェクトキャッシュ
`hash(MIR, target, codegen_ver)``.obj/.o`を再利用
### クロスコンパイル
```bash
--target=<triple> # .obj/.oとリンク器/SDKを切替
```
- Win用: `x86_64-pc-windows-msvc``lld-link` + MSVCライブラリ
- Linux: `x86_64-unknown-linux-gnu``ld.lld` + glibc
**Zig toolchain**を併用するとクロス用のCRT/SDKが楽内部はlld
## 🎨 使いやすいCLI例
```bash
nyash build main.ny --backend=cranelift --release
nyash build main.ny --emit=obj,asm,clif # 解析用
nyash run main.ny --backend=cranelift # JITで即実行
nyash toolchain doctor # lld/SDK検出
```
## ⚡ 地味に効く最適化スイッチ
### リンカ最適化
- `ld.lld`: `--gc-sections --icf=all`(不要コード除去&同一関数折りたたみ)
### Cranelift最適化
- `opt_level=speed`
- TypedArrayの**bounds-check併合**をLowerで実装
### 実行時最適化
- 起動時CPUIDで**関数ポインタ切替**AVX2/512の専用小関数
## ✅ 最初の"動くまで"チェックリスト
- [ ] `ny_mir_to_obj`C ABI`.o/.obj`を返せる
- [ ] `nyash link <obj> --target=<triple>``lld`でEXEを作れる
- [ ] Windows/Linuxそれぞれ"Hello, Box!"実行成功
- [ ] `--emit=clif,asm`でダンプが落ちる
- [ ] 失敗時のエラーメッセージが**ファイル名+未解決シンボル**まで出る
- [ ] `nyash toolchain doctor`でlld/SDK検出
## 📐 実装設計詳細
### LinkerBox設計
```nyash
box LinkerBox {
init { platform, linker_path, libraries, flags }
link(objects, output_path) {
local cmd = me.build_link_command(objects, output_path)
local result = me.execute_linker(cmd)
if result.exit_code != 0 {
me.format_link_error(result.stderr)
}
return result
}
detect_linker() {
// 優先順: 内蔵lld → システムlld → 代替
if me.has_embedded_lld() {
return me.extract_embedded_lld()
}
return me.find_system_linker()
}
}
```
### CraneliftBox統合
```nyash
box CraneliftBox {
init { target_triple, opt_level }
compile(mir) {
// MIR13 → Cranelift IR → Object
local module = me.create_module()
for inst in mir.instructions {
me.lower_instruction(module, inst)
}
return module.compile()
}
}
```
## 🌟 まとめ
- **Yes**: CraneliftでEXEにするには**内部でlldを叩く機能を埋め込む**のが正攻法
- 仕組みは**MIR→Cranelift .o/.obj → lld**
- C ABIファサード経由でcodegenを呼び、リンカは**内蔵ドライバ**で統一
- これで**自己ホスト→即EXE生成**の"気持ちいい体験"が完成!
## 🔗 関連ドキュメント
- [Phase 15メインドキュメント](README.md)
- [C ABI境界設計](../phase-12/c-abi-spec.md)
- [MIR 13命令セット](../../reference/mir/INSTRUCTION_SET.md)
- [Cranelift統合](../phase-10/)

View File

@ -0,0 +1,213 @@
# LLVM Native EXE Generation Strategy
## 📋 概要
LLVM バックエンドを使用した完全なネイティブ実行ファイル生成パイプラインの実装戦略。
Rustのビルド時間を削減するため、LLVM コンパイラ部分を独立した crate として分離する。
## 🎯 目標
### 短期目標Phase 15.5
1. **LLVM オブジェクト生成の安定化**ChatGPT5実装中
2. **リンカー統合**によるEXE生成
3. **基本的なビルド・実行パイプライン**の確立
### 中期目標Phase 15.6
1. **`nyash-llvm-compiler` crate の分離**
2. **ビルド時間の大幅短縮**5分→2分
3. **CI/CD での並列ビルド**対応
## 🏗️ アーキテクチャ
### 現在の構成(モノリシック)
```
nyash-rust/
├── Cargo.toml (features = ["llvm"]) # 重い!
├── src/
│ ├── backend/
│ │ └── llvm/ # LLVM実装
│ └── main.rs
```
### 目標構成(分離型)
```
nyash-rust/ # メインクレート(軽量)
├── Cargo.toml # LLVM機能なし
├── src/
nyash-llvm-compiler/ # 独立コンパイラ
├── Cargo.toml # LLVM依存のみ
├── src/
│ ├── main.rs # CLI エントリポイント
│ ├── mir_reader.rs # MIR入力処理
│ ├── codegen/ # LLVM コード生成
│ └── linker.rs # リンカー統合
```
## 🔧 実装計画
### Phase 1: 現在のLLVMバックエンド完成
```rust
// src/backend/llvm/compiler.rs
impl LLVMCompiler {
pub fn compile_to_executable(
&self,
mir: &MirModule,
output: &Path,
link_options: &LinkOptions,
) -> Result<(), Error> {
// 1. MIR → LLVM IR
let llvm_module = self.compile_module(mir)?;
// 2. LLVM IR → Object file
let obj_path = self.emit_object(llvm_module)?;
// 3. Link with runtime
self.link_executable(obj_path, output, link_options)?;
Ok(())
}
}
```
### Phase 2: インターフェース定義
```rust
// MIR交換フォーマットJSON or MessagePack
#[derive(Serialize, Deserialize)]
pub struct MirPackage {
pub version: u32,
pub module: MirModule,
pub metadata: CompileMetadata,
}
// コンパイラAPI
pub trait MirCompiler {
fn compile(&self, package: MirPackage, options: CompileOptions) -> Result<Output>;
}
```
### Phase 3: 独立crateの作成
```toml
# nyash-llvm-compiler/Cargo.toml
[package]
name = "nyash-llvm-compiler"
version = "0.1.0"
[dependencies]
inkwell = { version = "0.5", features = ["llvm18-0"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
clap = { version = "4.0", features = ["derive"] }
# Nyash共通定義MIR構造体など
nyash-mir = { path = "../nyash-mir" }
```
### Phase 4: CLI実装
```rust
// nyash-llvm-compiler/src/main.rs
#[derive(Parser)]
struct Args {
/// Input MIR file (JSON format)
input: PathBuf,
/// Output executable path
#[arg(short, long)]
output: PathBuf,
/// Target triple
#[arg(long, default_value = "native")]
target: String,
/// Link with nyrt runtime
#[arg(long)]
nyrt_path: Option<PathBuf>,
/// Static linking
#[arg(long)]
static_link: bool,
}
fn main() -> Result<()> {
let args = Args::parse();
// 1. Read MIR
let mir_package = read_mir_package(&args.input)?;
// 2. Compile to object
let compiler = LLVMCompiler::new(&args.target)?;
let obj_file = compiler.compile_to_object(&mir_package)?;
// 3. Link
let linker = Linker::new()?;
linker.link_executable(
&obj_file,
&args.output,
LinkOptions {
runtime: args.nyrt_path,
static_link: args.static_link,
},
)?;
Ok(())
}
```
## 🚀 使用方法
### 統合実行(将来)
```bash
# ワンステップビルド
nyash build --backend llvm --emit exe program.hako -o program.exe
# デバッグ用分離実行
nyash --dump-mir program.hako > program.mir.json
nyash-llvm-compiler program.mir.json -o program.exe
```
### パイプライン実行
```bash
# Unix pipe
nyash --dump-mir program.hako | nyash-llvm-compiler - -o program.exe
# Windows
nyash --dump-mir program.hako > temp.mir
nyash-llvm-compiler temp.mir -o program.exe
```
## 📊 期待される効果
### ビルド時間の改善
```
現在:
cargo build --release --features llvm # 5-7分
分離後:
cargo build --release # 1-2分メイン
cd nyash-llvm-compiler && cargo build # 2-3分LLVM部分
並列ビルド可能 → トータル3分程度
```
### CI/CD の改善
- メインビルドとLLVMビルドを並列実行
- LLVM部分の変更がない場合はキャッシュ利用
- プラットフォーム別ビルドの高速化
## 🔗 関連ファイル
- [lld-strategy.md](lld-strategy.md) - Cranelift版のリンカー戦略
- [../README.md](../README.md) - Phase 15全体計画
- [CURRENT_TASK.md](/mnt/c/git/nyash-project/nyash_self_main/CURRENT_TASK.md) - 現在の実装状況
## 📅 マイルストーン
- [ ] ChatGPT5によるLLVMバックエンド完成
- [ ] オブジェクトファイル生成の安定化
- [ ] build_llvm.shからの移行
- [ ] MIR交換フォーマットの確定
- [ ] nyash-llvm-compiler crate作成
- [ ] CI統合とドキュメント整備
---
> 「重いビルドは開発の敵。必要な部分だけを切り出して、高速な開発サイクルを実現するにゃ!」

View File

@ -0,0 +1,100 @@
# MIR Builder EXE Design (Phase 15 — EXEFirst)
Purpose: define a standalone MIR Builder executable that takes Nyash JSON IR (v0/v1) and produces native outputs (object/executable), independent of the Rust Runner/VM. This aligns Phase15 with an EXEfirst delivery pipeline.
Goals
- Accept JSON IR from stdin or file and validate semantics (minimal passes).
- Emit: object (.o/.obj), LLVM IR (.ll), or final executable by linking with NyRT.
- Operate without the Rust VM path; suitable for CLI and scripted pipelines.
- Keep the boundary simple and observable (stdout diagnostics, exit codes).
CLI Interface (proposed)
- Basic form
- `ny_mir_builder [--in <file>|--stdin] [--emit {obj|exe|ll|json}] -o <out> [options]`
- Defaults: `--stdin`, `--emit obj`, `-o target/aot_objects/a.o`
- Options
- `--in <file>`: Input JSON IR file (v0/v1). If omitted, read stdin.
- `--emit {obj|exe|ll|json}`: Output kind. `json` emits validated/normalized IR for roundtrip.
- `-o <path>`: Output path (object/exe/IR). Default under `target/aot_objects`.
- `--target <triple>`: Target triple override (default: host).
- `--nyrt <path>`: NyRT static runtime directory (for `--emit exe`).
- `--plugin-config <path>`: `nyash.toml` path resolution for boxes/plugins.
- `--quiet`: Minimize logs; only errors to stderr.
- `--validate-only`: Parse+validate IR; no codegen.
- `--verify-llvm`: Run LLVM verifier on generated IR (when `--emit {obj|exe}`).
Exit Codes
- `0` on success; >0 on error. Validation errors produce humanreadable messages on stderr.
Input IR
- JSON v0 (current Bridge spec). Unknown fields are ignored; `meta.usings` is accepted.
- Future JSON v1 (additive) must remain backward compatible; builder performs normalization.
Outputs
- `--emit obj`: Native object file. Uses LLVM harness internally.
- `--emit ll`: Dumps LLVM IR for diagnostics.
- `--emit exe`: Produces a selfcontained executable by linking the object with NyRT.
- `--emit json`: Emits normalized MIR JSON (postvalidation) for roundtrip tests.
Packaging Forms
- CLI executable: `ny_mir_builder` (primary).
- Optional shared lib: `libny_mir_builder` exposing a minimal C ABI for embedding.
C ABI Sketch (optional library form)
```c
// Input: JSON IR bytes. Output: newly allocated buffer with object bytes.
// Caller frees via ny_free_buf.
int ny_mir_to_obj(const uint8_t* json, size_t len,
const char* target_triple,
uint8_t** out_buf, size_t* out_len);
// Convenience linker: object → exe (returns 0=ok).
int ny_obj_to_exe(const uint8_t* obj, size_t len,
const char* nyrt_dir, const char* out_path);
void ny_free_buf(void* p);
```
Internal Architecture
- Frontend
- JSON IR parser → AST/CFG structures compatible with existing MIR builder expectations.
- Validation passes: controlflow wellformedness, PHI consistency (incoming edges), type sanity for BoxCall/ExternCall minimal set.
- Codegen
- LLVM harness path (current primary). Environment fallback via `LLVM_SYS_180/181_PREFIX`.
- Option flag `NYASH_LLVM_FEATURE=llvm|llvm-inkwell-legacy` maintained for transitional builds.
- Linking (`--emit exe`)
- Use `cc` with `-L <nyrt>/target/release -lnyrt` (static preferred) + platform libs `-lpthread -ldl -lm` (Unix) or Win equivalents.
- Search `nyash.toml` near the output exe and current CWD (same heuristic as NyRT runtime) to initialize plugins at runtime.
Integration Points
- Parser EXE → MIR Builder EXE
- `./nyash_compiler <in.hako> | ny_mir_builder --stdin --emit obj -o a.o`
- Compose with link step for quick endtoend: `... --emit exe -o a.out`
- Runner (future option)
- `NYASH_USE_NY_COMPILER_EXE=1`: Runner spawns parser EXE; optionally chain into MIR Builder EXE for AOT.
- Fallback to inproc Bridge when EXE pipeline fails.
Logging & Observability
- Default: singleline summaries on success, detailed errors on failure.
- `--quiet` to suppress nonessential logs; `--verify-llvm` to force verification.
- Print `OK obj:<path>` / `OK exe:<path>` on success (stable for scripts).
Security & Sandboxing
- No arbitrary file writes beyond `-o` and temp dirs.
- Deny network; fail fast on malformed JSON.
Platform Notes
- Windows: `.obj` + link with MSVC or lldlink; prefer bundling `nyrt` artifacts.
- macOS/Linux: `.o` + `cc` link; RPATH/loader path considerations documented.
Incremental Plan
1) CLI skeleton: stdin/file → validate → `--emit json/ll` (dry path) + golden tests。
2) Hook LLVM harness: `--emit obj` for const/arith/branch/ret subset。
3) Linker integration: `--emit exe` with NyRT static lib; add platform matrices。
4) Parity suite: run produced EXE against known cases (strings/collections minimal)。
5) Packaging: `tools/build_mir_builder_exe.sh` + smoke `tools/mir_builder_exe_smoke.sh`
Reference Artifacts
- `tools/build_llvm.sh`: current harness flow used as a baseline for emission and link steps。
- `crates/nyrt`: runtime interface and plugin host initialization heuristics。

View File

@ -0,0 +1,132 @@
# Phase 15 セルフホスティング戦略 2025年9月版
## 🎯 セルフホスティングの段階的実現戦略
### 現在地
- ✅ v0 NyパーサーNy→JSON IR完成
- ✅ MIR生成基盤ありRust実装
- 🚧 LLVM層改善中ChatGPT5協力
- 📅 NyコンパイラMVP計画中
### 君の提案の妥当性検証
## 📊 セルフホスティングの段階
### Stage 1: LLVM層の独立最優先
```
現在: Rustモリス → MIR → LLVM → オブジェクト
提案: Rustモリス → MIR(JSON) → [LLVM EXE] → ネイティブEXE
```
**実装詳細**
1. `nyash-llvm-compiler` crateを分離
2. 入力MIRJSON/バイナリ)
3. 出力:ネイティブ実行ファイル
4. nyrtランタイムとのリンク
**メリット**
- ビルド時間短縮Rust側は軽量化
- 独立したツールとして配布可能
- パイプライン明確化
### Stage 2: Nyashコンパイラ実装現在計画中
```
現在: Rustパーサー → MIR
提案: Nyashコンパイラ → AST/JSON → MIR生成層
```
**実装詳細**
1. Nyashで再帰下降パーサー実装
2. AST構造をJSONで出力
3. 既存のMIR生成層に接続
4. `NYASH_USE_NY_COMPILER=1`で切替
**これでセルフホスティング達成!**
- Nyashで書いたコンパイラがNyashをコンパイル
- Rustコンパイラは不要に
### Stage 3: VM層のNyash実装革新的
```
現在: Rust VM → MIR解釈
提案: Nyash VM → MIR解釈 → (必要時LLVM呼び出し)
```
**実装詳細**
```nyash
box NyashVMBox {
mir_module: MIRModuleBox
pc_stack: ArrayBox
value_stack: ArrayBox
frame_stack: ArrayBox
execute(mir_json) {
me.mir_module = MIRModuleBox.parse(mir_json)
me.runFunction("main")
}
runFunction(name) {
local func = me.mir_module.getFunction(name)
local frame = new FrameBox(func)
me.frame_stack.push(frame)
loop(frame.pc < func.instructions.length()) {
local inst = func.instructions[frame.pc]
me.executeInstruction(inst, frame)
frame.pc = frame.pc + 1
}
}
}
```
**メリット**
- **コンパイル不要**で即実行
- VMロジックを動的に変更可能
- デバッグ・実験が容易
## 🚀 実現順序の提案
### Phase 15.2: LLVM独立化
1. LLVM層をcrateに分離
2. MIR JSONインターフェース確立
3. スタンドアロンEXE生成
### Phase 15.3: Nyashコンパイラ
1. パーサー実装Nyashで
2. AST→MIRブリッジ
3. ブートストラップテスト
### Phase 15.4: VM層Nyash化
1. MIR解釈エンジン基本13命令
2. BoxCall/ExternCallブリッジ
3. パフォーマンス最適化JIT連携
## 💡 ABI移行タイミング
**LLVM独立化完了後が最適**理由:
1. インターフェース確定後に最適化
2. 独立EXEならABI変更の影響限定的
3. パフォーマンス測定してから判断
## 📋 検証結果
**君の提案は正しい!**
1. **LLVM EXE独立** → MIR JSONで疎結合
2. **Nyashコンパイラ** → AST/JSONでMIR生成
3. **セルフホスト完了** → Rustコンパイラ不要
4. **VM層Nyash化** → 究極の柔軟性
この順序なら:
- 段階的に実現可能
- 各段階で動作確認
- リスク最小化
- 最終的に完全セルフホスト
## 🎯 次のアクション
1. **LLVM crateの設計開始**
2. **MIR JSONスキーマ確定**
3. **Nyパーサー拡張計画**
4. **VMプロトタイプ設計**
これが現実的で革新的なロードマップにゃ!