3bf0dee2b0
feat(mir): Phase 285 P2.1 - KeepAlive instruction for weak ref semantics
...
Add KeepAlive instruction to fix hidden root problem where x = null
doesn't properly drop the strong reference.
Key changes:
- Add KeepAlive { values, drop_after } instruction to MIR
- Emit KeepAlive[drop=true] in build_assignment() before variable overwrite
- Emit KeepAlive[drop=false] in pop_lexical_scope() at scope end
- VM handler: when drop_after=true, remove ALL ValueIds pointing to
the same Arc (handles SSA Copy chains)
Test results:
- weak_upgrade_fail: exit 1 ✅ (weak_to_strong returns null after x=null)
- weak_basic: exit 2 ✅ (weak_to_strong succeeds while x alive)
- quick smoke: 154/154 PASS ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 13:08:32 +09:00
7a575e30cc
refactor(joinir): Phase 286 P3.2 cleanup + normalizer modularization
...
## Legacy Pattern5 削除 (488行)
- pattern5_infinite_early_exit.rs 完全削除
- LOOP_PATTERNS テーブルからエントリ削除
- Plan extractor が SSOT
## Normalizer 分割 (3294行 → 12ファイル)
- helpers.rs: 共通ヘルパー関数
- pattern*.rs: 各パターン専用ファイル
- mod.rs: ディスパッチャ
## ドキュメント更新
- Phase 286 README: クリーンアップ完了・Fail-Fast方針記載
- Phase 287 README: 将来計画
quick smoke 154/154 PASS
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 10:30:08 +09:00
22945c190c
feat(joinir): Phase 286 P3.2 - Pattern5 Plan line (loop(true) + early exit)
...
- Pattern5InfiniteEarlyExitPlan (Return/Break variants)
- extract_pattern5_plan() for loop(true) literal only
- normalize_pattern5_return(): 5 blocks CFG (header→body→found/step)
- normalize_pattern5_break(): 6 blocks CFG with carrier PHI
- NormalizationPlanBox exclusion for Pattern5-style loops
- Fixtures: phase286_pattern5_{return,break}_min.hako
- quick smoke 154/154 PASS
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 09:56:34 +09:00
b235a5b6db
feat(joinir): Phase 286 P3.1 - Pattern2 Plan line 完走(after_bb PHI)
...
Pattern2(Loop with Break)を Plan/Frag SSOT へ移行。
主な変更:
- Pattern2BreakPlan 追加(DomainPlan variant)
- extract_pattern2_plan() 実装(PoC サブセット厳守)
- normalize_pattern2_break() 実装(6-block CFG, 3 PHI)
- after_bb PHI が本質: carrier_out = PHI(header: carrier_current, break_then: carrier_break)
- router に Pattern2 追加(Pattern1 より前、より具体的)
テスト:
- Fixture B (break without update): PASS (出力 11)
- quick smoke: 154/154 PASS
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 05:56:30 +09:00
f76fb6cd3e
refactor(joinir): Phase 286 P2.8 - Normalizer Hygiene(小箱化・重複削減)
...
- LoopBlocksStandard5: 5-block レイアウト(Pattern1/9 で使用)
- LoopBlocksWithIfPhi: 8-block レイアウト(Pattern3 で使用)
- create_phi_bindings(): phi_bindings 作成ヘルパー(全5パターンで使用)
リファクタ適用:
- Pattern1: LoopBlocksStandard5 + create_phi_bindings
- Pattern3: LoopBlocksWithIfPhi + create_phi_bindings
- Pattern4: create_phi_bindings(8-block は別構造のため据え置き)
- Pattern8: create_phi_bindings(6-block は別構造のため据え置き)
- Pattern9: LoopBlocksStandard5 + create_phi_bindings
意味論は完全不変。quick 154/154 PASS。
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 05:08:09 +09:00
630ed02c48
feat(joinir): Phase 286 P2.7 - V10不変条件追加(body_bb effects契約)
...
- verifier.rs: V10検証追加 - body_bbのblock_effectsは空でなければならない
- 違反時: "[V10] Loop at depth N has non-empty block_effects for body_bb"
- テスト: test_v10_body_bb_effects_in_block_effects_fails
- joinir-plan-frag-ssot.md: V10をPlan段階の不変条件に追加
- README.md: P2.7セクション追加
Phase 286 P2.6.1で発見した「lowererはloop_plan.bodyをemitし、
block_effectsのbody_bbは無視する」問題を契約化し再発防止。
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 04:55:14 +09:00
0fca2df5be
feat(joinir): Phase 286 P2.6.1 - Pattern3 Plan 完走(normalizer 実装 + Fail-Fast 統一)
...
## 変更内容
### Router Fail-Fast 統一
- Pattern3 stub fallback 特例を撤去
- extract 成功 → normalize/lower 失敗は即 Err(他パターンと統一)
### normalize_pattern3_if_phi() 実装
- CFG 構造: 8 blocks (preheader, header, body, then, else, merge, step, after)
- PHI 構成: 3本(header×2 + merge×1)
- Header: loop_var_current, carrier_current
- Merge: carrier_next (if-else 合流)
- Frag: BranchStub×2 + EdgeStub×4(Pattern1 流儀の直接構築)
### 発見・修正
- lowerer は body_bb の block_effects を無視して loop_plan.body を emit
- body_bb effects は CorePlan::Effect(...) として loop_plan.body に配置
## テスト結果
- Phase 118 smoke: PASS (出力 12)
- quick: 154/154 PASS
- Plan line 完走確認: route=plan ... Pattern3_IfPhi MATCHED
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 04:39:36 +09:00
3abca63ebe
refactor(joinir): Phase 286 P2.6 コード品質 - pattern3.rs 重複削除 + 共通化
...
## 変更内容
- pattern3.rs: has_return_statement() 削除 → common_helpers 使用
- pattern3.rs: has_control_flow_statement() → has_forbidden_control_flow_for_pattern3() にリネーム
- Pattern3 固有のセマンティクス(ネスト if 禁止)を明確化
- common_helpers.rs: find_if_else_statement() 追加
- PoC subset コメント付き(最初の if-else だけ取る)
## 効果
- 重複コード削除: -34 lines net
- 関数名で意図を明確化(Pattern3 固有の制約)
- common_helpers の再利用性向上
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 04:13:13 +09:00
4d17e3d812
feat(joinir): Phase 286 P2.6 - Pattern3 Plan 基盤 + Pattern1 退行修正
...
## Pattern1 退行修正(構造的 Fail-Fast)
- Router に pattern_kind ガード追加(ctx.pattern_kind != Pattern1SimpleWhile → skip)
- has_if_else_statement() ヘルパー追加(再帰版、ScopeBox/Loop 内もチェック)
- Pattern1 extractor に if-else 拒否追加
## Pattern3 Plan 基盤
- DomainPlan: Pattern3IfPhiPlan 構造体追加
- Extractor: extract_pattern3_plan() 追加
- Normalizer: normalize_pattern3_if_phi() スタブ追加(レガシー JoinIR へフォールバック)
- Router: PLAN_EXTRACTORS に Pattern3 追加
## テスト結果
- quick 154 PASS
- Phase 118 smoke PASS(出力 12、退行解消)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 04:01:11 +09:00
21daf1b7dd
refactor(joinir): Phase 286 コード品質改善 - ヘルパー共通化 + static box フィルタ
...
## 1. lower_*_ast ヘルパー共通化
- `lower_value_ast()` に MethodCall 対応追加
- Pattern8 normalizer も共有ヘルパーを使用
- Pattern1/8/9 で一貫した lowering ロジック
## 2. PLAN_EXTRACTORS ドキュメント追加
- `WithPostLoop` variant: 将来拡張用として残存理由を明記
- 現在は常に `&[]` を渡すが、post-loop segment analysis 用に保持
## 3. Legacy Pattern8 残存 + static box フィルタ
- Plan extractor は pure 関数(builder にアクセス不可)
- router 側で static box フィルタリングを実装
- static box コンテキストは legacy Pattern8 へ fallback
- legacy 残存理由をドキュメント化
## 検証
- Quick: 154 PASS, 0 FAILED
- Pattern8 integration: exit 7
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 03:35:02 +09:00
832d018046
feat(joinir): Phase 286 P2.4.1 - Pattern8 normalizer 実装 + Fail-Fast 化
...
## 概要
Pattern8 (BoolPredicateScan) を Plan line で完走させる。
stub normalizer を完全実装に置き換え、legacy fallback を禁止。
## Step 0: Fixture 簡約
- `?:` ternary → `if/else` に変更(PoC 安定化)
## Step 1: Router Fail-Fast 化
- 文字列判定 `e.contains("[normalizer/pattern8]")` を削除
- extract が Some → normalize/lower 失敗は即 Err(fallback 禁止)
- extract が None → 次の extractor へ(legacy 含む)
## Step 2: Pattern8 normalizer 実装
- CFG: preheader → header(PHI) → body → found/step → after
- found: return false(早期脱出)
- after: return true(ループ完走)
- compose::cleanup() で 2 つの Return exit をマージ
## 検証結果
- Integration: exit 7 ✅
- Plan 完走: route=plan strategy=extract pattern=Pattern8 MATCHED
- Regression: quick 154 PASS, 0 FAILED
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 03:17:48 +09:00
064cae169e
feat(joinir): Phase 286 P2.4 - Pattern8 BoolPredicateScan Plan化 PoC
...
## 概要
Pattern8 (BoolPredicateScan) を Plan extraction routing に追加。
static box 除外(Phase 269 決定)を尊重し、非 static box fixture で PoC。
## 実装内容
- Pattern8BoolPredicateScanPlan struct + DomainPlan variant
- extract_pattern8_plan(): 条件・predicate check・increment 抽出
- normalize_pattern8_bool_predicate_scan(): PoC stub(CoreExitPlan::Return 未統合)
- PLAN_EXTRACTORS テーブルに Pattern8 追加(3rd priority)
- エラーフォールバック: Plan normalization 失敗時 → legacy Pattern8 へ
## 動作フロー
Plan extraction MATCHED → normalization failed (PoC stub) → legacy Pattern8 MATCHED
## 検証結果
- Integration: phase286_pattern8_plan_poc_vm PASS (exit 7)
- Regression: quick 154 PASS, 0 FAILED
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 03:01:11 +09:00
1d24e9a106
feat(joinir): Phase 286 P2.3 + Phase 287 - Pattern9 Plan化 + Router table-driven
...
## Phase 286 P2.3: Pattern9 AccumConstLoop Plan化 PoC
- DomainPlan::Pattern9AccumConstLoop 追加
- PlanNormalizer::normalize_pattern9_accum_const_loop() 実装
- PHI 2本(loop_var, acc_var)
- const/var 両方 OK(sum = sum + 1 または sum = sum + i)
- Pattern9 は Pattern1 より優先(より具体的なパターン)
- Integration test: phase286_pattern9_frag_poc PASS (return: 3)
- Regression: quick 154 PASS
## Phase 287: Router table-driven Plan extraction
- PLAN_EXTRACTORS static table で Pattern6/7/4/9/1 を統一管理
- PlanExtractorEntry/PlanExtractorVariant 構造体追加
- try_plan_extractors() で ~100行 → 3行に集約
- メンテナンス性向上(新 Pattern 追加はテーブル1行追加のみ)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-26 02:38:09 +09:00
a824346e30
feat(joinir): Phase 286 P2/P2.1/P2.2 - JoinIR Line Absorption (Pattern1/4 Plan化 PoC + hygiene)
...
Phase 286 P2: Pattern4 (Loop with Continue) を Plan/Frag SSOT に移行
- DomainPlan::Pattern4Continue 追加
- PlanNormalizer::normalize_pattern4_continue() 実装(phi_bindings による PHI dst 優先参照)
- Router integration(Plan line routing → legacy fallback)
- Integration test PASS (output: 6), quick smoke 154/154 PASS
Phase 286 P2.1: Pattern1 (SimpleWhile) を Plan/Frag SSOT に移行
- DomainPlan::Pattern1SimpleWhile 追加
- PlanNormalizer::normalize_pattern1_simple_while() 実装(4ブロック、1 PHI、phi_bindings 流用)
- Router integration(Plan line routing → legacy fallback)
- Integration test PASS (return: 3), quick smoke 154/154 PASS
Phase 286 P2.2: hygiene(extractor重複排除 + router小整理)
- extractor helper化: extract_loop_increment_plan を common_helpers.rs に統一
- Pattern1/Pattern4 が呼ぶだけに変更(重複排除 ~25行)
- router helper化: lower_via_plan() を追加し Pattern6/7/4/1 で共用
- 3行パターン(normalize→verify→lower)を1関数に集約(ボイラープレート削減 ~40行)
成果物:
- DomainPlan 2パターン新規追加(Pattern1SimpleWhile, Pattern4Continue)
- Normalizer 2つの normalize 関数追加
- Router に Plan line ブロック追加 + lower_via_plan() helper
- Extractor に extract_pattern1_plan() 追加
- Integration fixtures 2個 + smoke tests 2個
検証:
- quick smoke: 154/154 PASS
- integration: phase286_pattern1_frag_poc PASS, phase286_pattern4_frag_poc PASS
- Plan line routing: route=plan strategy=extract で Pattern1/4 検出確認
🤖 Generated with Claude Code
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2025-12-26 02:03:22 +09:00
46fbe12ce6
feat(repl): Phase 288.1 session persistence + auto-display
...
実装内容:
- AST Rewriter (~430行): 未宣言変数を __repl.get/set に変換
- ExternCall Bridge: VM で __repl.get/set ハンドラー実装
- Rc<RefCell<>> セッション共有: VM と REPL runner 間で永続化
- 式自動表示: pure expression の結果を自動出力
- _ 変数: 最後の表示値を保存(Void は除外)
- .reset 実装: セッション変数の完全クリア
- Fail-Fast: 未定義変数読み取りで明示的エラー + ヒント
変更ファイル (8ファイル, +592行):
- src/runner/repl/ast_rewriter.rs (NEW, +430行)
- src/runner/repl/repl_runner.rs (+84/-35行)
- src/backend/mir_interpreter/handlers/externals.rs (+54行)
- src/mir/builder/calls/build.rs (+41行)
- src/backend/mir_interpreter/mod.rs (+12行)
- src/runner/repl/repl_session.rs (+11/-9行)
- src/runner/repl/mod.rs (+2行)
- src/runner/mod.rs (+2/-1行)
REPL専用設計(src/mir/builder/calls/build.rs の特別扱い理由):
- __repl.get/set は REPL mode 専用の橋渡し機能
- try_build_repl_method_call() で早期検出・ExternCall 変換
- file mode では決して使用されない(VM で "outside REPL mode" エラー)
- 将来的にも file mode への影響ゼロを保証
検証済み:
- 変数永続化: x = 42; print(x) → 42 ✅
- 式自動表示: 1 + 1 → 2 ✅
- _ 変数: 10 * 2 → 20; _ → 20 ✅
- Fail-Fast: 未定義エラー + ヒント ✅
- 回帰テスト: 154/154 PASS ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 23:04:59 +09:00
e986e279b4
refactor(repl): Quiet Mode 方針整合 - REPL 専用フラグに統一
...
方針整合修正(commit 1cec724ce の改善):
- NYASH_QUIET_INTERNAL_LOGS 撤去(環境変数スパロー防止)
- src/runner/repl/repl_runner.rs: quiet_internal_logs フラグ追加、環境変数操作削除
- src/mir/mod.rs: set_quiet_internal_logs() 公開 API 追加
- src/mir/builder/compilation_context.rs: quiet_internal_logs フラグ追加
- src/mir/builder/decls.rs: 環境変数直読み → context フラグ参照
アーキテクチャ:
✅ REPL 専用フラグで制御(file mode 無影響保証)
✅ ReplRunnerBox → MirCompiler → CompilationContext の明確な伝播経路
✅ crate::config::env::cli_verbose() 既存 SSOT を活用
ルール遵守:
✅ 環境変数スパロー防止ポリシー(AGENTS.md 5.3)
✅ 隠しトグル禁止(新規環境変数なし)
✅ 既存の verbose 制御(NYASH_CLI_VERBOSE)に統一
機能保持:
✅ REPL 通常モード: 内部ログ抑制(clean output)
✅ REPL verbose モード: デバッグログ表示(--verbose)
✅ File mode 既定挙動: 不変(quiet_internal_logs 常に false)
Test results:
✅ REPL quiet/verbose 動作確認
✅ File mode regression: 154/154 pass(既定挙動不変)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 14:42:16 +09:00
1cec724ce0
feat(repl): REPL Quiet Mode - デバッグログ自動抑制
...
REPL mode では内部デバッグログを自動抑制:
- src/runner/repl/repl_runner.rs: NYASH_QUIET_INTERNAL_LOGS 設定/解除
- src/mir/builder/decls.rs: NYASH_QUIET_INTERNAL_LOGS チェック追加
- NYASH_CLI_VERBOSE=1 でデバッグログ有効化可能
UX improvement:
Before: >>> print("Hello")
[build_static_main_box] Storing fn_body_ast...
Hello
After: >>> print("Hello")
Hello
Test results:
✅ 通常モード: ログ抑制
✅ デバッグモード (NYASH_CLI_VERBOSE=1): ログ表示
✅ File mode regression: 154/154 pass
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 14:26:42 +09:00
3445ef7a7d
refactor(repl): Phase 288 Box化 - REPL Runner モジュール分離
...
箱理論モジュール化(Box-First):
- src/runner/repl/ 新規モジュール作成
- ReplRunnerBox: REPL実行器の完全隔離
- ReplSessionBox: mir/builder → runner/repl へ移動
File changes:
- src/runner/mod.rs: -118行(REPL コード削除)
- src/runner/repl/mod.rs: +22行(公開API)
- src/runner/repl/repl_runner.rs: +143行(ReplRunnerBox実装)
- src/runner/repl/repl_session.rs: moved from mir/builder/
Benefits:
- runner/mod.rs が綺麗(REPL 関連削除)
- REPL 機能が完全隔離(file mode への影響ゼロ保証)
- テスト容易性向上(Box 単体テスト可能)
Test results:
✅ REPL 動作確認(print/.reset/.exit)
✅ File mode regression: 154/154 pass
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 14:06:22 +09:00
79608bce64
feat(repl): Phase 288 P3 - Minimal UX (print() displays, .reset works)
...
UX improvements:
- print() output displays correctly (Main box entry point fix)
- .reset command clears session state
- _ variable stores last VMValue (ready for access)
- Statements execute silently (no auto-display)
Complete REPL workflow verified:
>>> .help
Commands:
.exit / .quit - Exit REPL
.reset - Clear session
.help - Show this help
>>> print("Hello REPL!")
Hello REPL!
>>> print(42 + 1)
43
>>> x = 42
>>> # Silent (implicit local creation)
>>> .reset
Session reset
Key fix:
- Changed wrapper from "__Repl" to "Main" for VM entry point
- VM execute_module() looks for Main.main/0, not __Repl.main/0
Files modified:
- src/runner/mod.rs: Main box wrapper (+3 lines), .reset impl (+7 lines)
Test results:
✅ print() displays output
✅ .reset clears session
✅ .help shows commands
✅ Statements silent (no auto-display)
✅ File mode regression: 154/154 tests pass
Deferred to Phase 288.1+:
- Expression auto-display (1+1 → 2)
- Variable persistence across lines
- _ variable access in user code
Phase 288 P0-P3 COMPLETE ✨
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 13:47:54 +09:00
934a774b50
feat(repl): Phase 288 P2 - Implicit local binding (VMValue persistence)
...
Box-First architecture:
- ReplSessionBox: VMValue-based session state (not ValueId)
- repl_mode flag: File/REPL mode isolation
- MirCompiler.set_repl_mode(): Public API for REPL
Files modified:
- src/mir/builder/repl_session.rs: NEW (+55 lines) - Session state
- src/mir/builder.rs: repl_mode field (+4 lines)
- src/mir/mod.rs: set_repl_mode() method (+4 lines)
- src/mir/builder/vars/assignment_resolver.rs: REPL skip (+3 lines)
- src/runner/mod.rs: repl_session + eval implementation (+45 lines)
REPL behavior:
- x = 1: Implicit local creation (暗黙 local)
- Compilation + execution pipeline complete
- Variable persistence: TODO for P3 (as planned)
Test results:
✅ x = 1 compiles and executes
✅ File mode regression: 154/154 tests pass
File mode unchanged (assignment_resolver.rs: minimal 3-line check).
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 13:38:04 +09:00
8941e3bb03
feat(repl): Phase 288 P1 - Add CLI entry point
...
Added --repl / -i flag:
- src/cli/args.rs: clap flag definition (+5 lines)
- src/cli/mod.rs: CliConfig.repl field (+3 lines)
- src/runner/mod.rs: run_repl() loop + stub eval (+71 lines)
Minimal REPL: .help / .exit work, eval stub for P2.
Test results:
✅ hakorune --repl starts REPL
✅ .help / .exit / .reset commands work
✅ File mode regression: 154/154 tests pass
File mode unchanged (0 regressions).
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 13:28:41 +09:00
4a5e2bd330
refactor(rewrite): Phase 287 P5 - Code cleanup after toString SSOT
...
Three targeted cleanups following Phase 287 P4 toString normalization:
1. known.rs: Extract primitive guard into helper function
- Unified 4 duplicate guard blocks (60 lines) into single function (15 lines)
- 75% code reduction with improved testability
- Function: should_block_primitive_str_rewrite()
2. special.rs: Extract trace helper
- Unified 3 duplicate NYASH_STATIC_CALL_TRACE checks
- Function: trace_tostring()
3. boxcall.py: Constant-ify magic numbers
- UNIVERSAL_SLOT_TOSTRING = 0 (self-documenting)
- TOSTRING_METHODS = ("toString", "stringify", "str")
Total impact: ~45 lines reduced, improved maintainability.
SSOT maintained: toString always uses universal slot #0 .
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 12:56:43 +09:00
93b4af9769
refactor(rewrite): Delete dead_code functions - Phase 287 P4 cleanup
...
Legacy deletion: Remove unused early rewrite functions that were replaced
by BoxCall(slot #0 ) normalization in Phase 287 P4.
Deleted functions (143 lines):
1. try_early_str_like() - 120 lines
- Complex class inference logic
- Global(Class.str/0) rewrite
- Unique suffix fallback with JsonNode priority
- Replaced by: try_early_str_like_to_dst() using BoxCall(slot #0 )
2. try_special_equals() - 22 lines
- Known rewrite + unique suffix for equals
- Replaced by: try_special_equals_to_dst()
These functions were marked #[allow(dead_code)] and had no callers.
Test Results:
✅ VM: local x = 1; print(x.toString()) → "1" (still works)
✅ Build: Success (0 errors)
SSOT: toString normalization via BoxCall(slot #0 ) is the only path now.
Files changed:
- src/mir/builder/rewrite/special.rs (-143 lines)
🎊 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 11:59:50 +09:00
b696f6c4c4
fix(llvm): Use nyash.any.toString_h for universal slot #0 - Phase 287 P4
...
SSOT unification: All toString calls now use nyash.any.toString_h(handle)
instead of plugin invoke system. This works for ALL types:
- IntegerBox, FloatBox, BoolBox, StringBox
- ArrayBox, MapBox, user-defined boxes
Changes:
- LLVM boxcall.py: Replace plugin invoke with direct nyash.any.toString_h call
- Deleted complex 6-argument plugin invoke for method_id=0
- Primitive i64 → box via nyash.box.from_i64 → toString via universal SSOT
Test Results (VM/LLVM parity achieved):
✅ VM: local x = 1; print(x.toString()) → "1"
✅ LLVM: local x = 1; print(x.toString()) → "1"
✅ VM: array_length (boxed Integer) → "0\n1\n2\n3"
✅ LLVM: array_length (boxed Integer) → "0\n1\n2\n3"
SSOT: nyash.any.toString_h = universal slot #0 handler (kernel)
Files changed:
- src/llvm_py/instructions/boxcall.py (universal slot #0 handler)
🎊 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 11:46:48 +09:00
c117a04035
fix(rewrite): toString normalization to BoxCall(slot #0 ) - Phase 287 P4
...
Root cause: toString/stringify/str were being rewritten to Global/Method calls
with class inference, causing Main.toString/0 to be called for primitives.
Fix (Box-First + Legacy Deletion):
1. ✅ MIR Builder - toString normalization (special.rs)
- ALWAYS emit BoxCall with method_id=0 for toString/stringify/str
- Do NOT rewrite to Global(Class.str/0) or Method calls
- DELETED 70+ lines of complex class inference logic
- Primitive guard with method name filter (known.rs)
2. ✅ JSON Serializer - method_id output (mir_json_emit.rs)
- Include method_id field in BoxCall JSON for LLVM
3. ✅ LLVM Backend - universal slot #0 support
- Extract method_id from JSON (instruction_lower.py)
- Box primitives via nyash.box.from_i64 (boxcall.py)
- Invoke toString via plugin system with method_id=0
- ⚠️ TODO: Add nyash.integer.tostring_h to kernel
Test Results:
✅ VM: local x = 1; print(x.toString()) → "1" (PASS)
✅ VM: array_length test (boxed Integer) → PASS
⚠️ LLVM: Compiles successfully, needs kernel function
SSOT: slot_registry - toString is ALWAYS universal slot #0
Legacy Deleted:
- special.rs: Complex class inference rewrite (~70 lines)
- special.rs: Unique suffix fallback for toString
- special.rs: Main box special handling
Files changed:
- src/mir/builder/rewrite/special.rs (try_early_str_like_to_dst)
- src/mir/builder/rewrite/known.rs (primitive guards x4)
- src/runner/mir_json_emit.rs (method_id serialization x2)
- src/llvm_py/builders/instruction_lower.py (method_id extraction)
- src/llvm_py/instructions/boxcall.py (slot #0 handler)
- docs/reference/language/quick-reference.md (toString SSOT)
🎊 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 11:38:05 +09:00
cab98e2fb4
fix(rewrite): Extend primitive guards to include boxed primitives (Phase 287 P4)
...
Critical fix: Guards only checked MirType::{Integer,Float,Bool,String}
but missed MirType::Box("IntegerBox") etc. This caused .length().toString()
to be rewritten to Global(Main.toString/0).
Root cause: .length() returns boxed Integer (MirType::Box("IntegerBox"))
not primitive Integer (MirType::Integer), so guards didn't catch it.
Fix: Extended is_primitive check to include boxed primitive types:
MirType::Box(name) if name in ["IntegerBox", "FloatBox", "BoolBox", "StringBox"]
Modified functions in known.rs (all 4):
1. try_known_rewrite (line 61-65)
2. try_known_rewrite_to_dst (line 156-160)
3. try_unique_suffix_rewrite (line 256-260)
4. try_unique_suffix_rewrite_to_dst (line 332-336)
MIR verification:
- All toString() calls now use Method(IntegerBox.toString) ✅
- No more Global("Main.toString/0") calls ✅
Remaining issue (separate bug):
- VM fails with "Unknown method 'toString' on Integer"
- MIR is correct, problem is in VM Method call resolution
- Needs separate investigation
🎉 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 10:55:41 +09:00
716f5735df
fix(rewrite): Limit primitive type guards to toString/stringify/str only (Phase 287 P4)
...
Critical fix: Previous guards blocked ALL primitive method calls, not just
toString/stringify/str. This would have broken length(), substring(), etc.
Root cause: Guards in known.rs checked primitive type but NOT method name,
so ANY method call on Integer/Float/Bool/String was blocked.
Fix: Added method name check to all 4 guard locations:
if method == "toString" || method == "stringify" || method == "str" {
// Only then check primitive type
}
Modified functions in known.rs:
1. try_known_rewrite (line 58-71)
2. try_known_rewrite_to_dst (line 151-164)
3. try_unique_suffix_rewrite (line 249-262)
4. try_unique_suffix_rewrite_to_dst (line 323-336)
Verification:
- toString() still works: "1" output ✅
- MIR still uses boxcall (no Global call) ✅
- Other primitive methods (length/substring) NOT affected ✅
Credit: User caught this critical issue before it caused problems!
🎉 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 10:50:14 +09:00
98a948344e
fix(rewrite): Add conservative primitive type guards to prevent toString() misrewrite (Phase 287 P4)
...
Root cause: x.toString() (x=Integer local var) was incorrectly rewritten to
Global(Main.toString/0) instead of using universal slot toString[#0 ].
The bug had two layers:
1. Early rewrite guards in special.rs correctly blocked it
2. BUT known.rs rewrite functions recursively called emit_unified_call with
Global("Main.toString/0"), bypassing the primitive type checks
Fix (Box-First Conservative Guards):
- Added primitive type guard (Integer/Float/Bool/String) to ALL 4 rewrite
functions in known.rs:
1. try_known_rewrite (line 56-69)
2. try_known_rewrite_to_dst (line 131-144)
3. try_unique_suffix_rewrite (line 243-256)
4. try_unique_suffix_rewrite_to_dst (line 283-296)
- Added debug trace in unified_emitter.rs to track CallTarget flow
Test case verification:
static box Main { main() { local x = 1; print(x.toString()) } }
Expected: "1" (via universal slot toString[#0 ])
Before: "Main()" (Global(Main.toString/0) misrewrite)
After: "1" (boxcall via Method slot #0 ) ✅
MIR verification:
Before: Global("Main.toString/0") in main function
After: boxcall instruction (universal slot) ✅
Files changed:
- src/mir/builder/rewrite/known.rs: 4 functions + primitive guard
- src/mir/builder/rewrite/special.rs: debug trace
- src/mir/builder/calls/unified_emitter.rs: debug trace
SSOT: docs/reference/language/types.md - toString() is universal slot #0
🎉 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 10:43:43 +09:00
fa00ed3018
refactor(joinir): Split contract_checks.rs into 2 files (Phase 286C-4.3)
...
Split 1,239-line contract_checks.rs into responsibility-based modules
for better maintainability and clarity.
## Changes
1. **New file: debug_assertions.rs** (440 lines)
- 6 debug-only verification functions (panic! on violation)
- All functions guarded with #[cfg(debug_assertions)]
- Excluded from release builds
- Functions:
* verify_loop_header_phis()
* verify_exit_line()
* verify_exit_phi_no_collision()
* verify_valueid_regions()
* verify_condition_bindings_consistent()
* verify_header_phi_dsts_not_redefined()
2. **Updated: contract_checks.rs** (1,239 → 848 lines, -391 lines)
- Kept 6 Fail-Fast functions (Result<(), String>)
- Kept all 13 unit tests
- Removed debug-only functions and imports
3. **Updated: mod.rs**
- Added `mod debug_assertions;` declaration
## Responsibility Split
- **contract_checks.rs**: Fail-Fast contracts (production)
- Return errors with diagnostic messages
- Run in both debug and release builds
- **debug_assertions.rs**: Debug-only assertions (development)
- Panic on contract violations
- Excluded from release builds (#[cfg(debug_assertions)])
## Benefits
- Single Responsibility Principle (each file <850 lines)
- Clear separation: Fail-Fast vs Debug-only
- Improved maintainability (localized changes)
- Better build performance (debug code stripped in release)
## Test Results
- ✅ Build: 0 errors
- ✅ Smoke tests: 45/46 PASS (no regression)
- ❌ core_direct_array_oob_set_rc_vm: FAIL (existing known issue)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 06:08:46 +09:00
ad1a8bd8ec
feat(joinir): Add carrier_inputs completeness contract (Phase 286C-4.2)
...
Adds Fail-Fast contract to verify carrier_inputs completeness at plan stage,
preventing silent bugs where carrier collection is skipped.
## Changes
1. **contract_checks.rs**:
- Added `verify_carrier_inputs_complete()` function
- Checks all non-ConditionOnly carriers are present in carrier_inputs
- Error tag: `[joinir/contract:C4]` for grep-friendly diagnostics
- Added test helper `make_boundary()` for JoinInlineBoundary construction
- Added 3 unit tests (missing carrier, ConditionOnly skip, valid case)
2. **instruction_rewriter.rs**:
- Call `verify_carrier_inputs_complete()` after plan_rewrites()
- Runs before apply_rewrites() for clean error state
## Contract
For each non-ConditionOnly exit_binding:
- `carrier_inputs[carrier_name]` must exist
Catches bugs where:
- CarrierInputsCollector fails to add a carrier
- plan_rewrites skips a carrier mistakenly
- exit_phi_builder receives incomplete carrier_inputs
## Test Results
- ✅ json_lint_vm: PASS (was FAIL in 286C-4.1 before fix)
- ✅ Full suite: 45/46 PASS (no regression)
- ❌ core_direct_array_oob_set_rc_vm: FAIL (existing known issue)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 05:43:34 +09:00
86dfa30abe
chore(joinir): Phase 286C-5 Step 3 - Remove unused imports
...
Ran `cargo fix --allow-dirty --lib` to automatically remove unused imports
across the codebase. This cleanup is standard maintenance and improves code
hygiene.
**Files Modified**:
- instruction_rewriter.rs: Removed 6 unused imports
- block_remapper::remap_block_id
- LoweringDecision
- ParameterBindingBox
- propagate_value_type_for_inst (2 occurrences)
- apply_remapped_terminator
- PhiAdjustment, ParameterBinding from scan_box
- Other files: Minor unused import cleanup (12 files total)
**No Functional Changes**: Pure cleanup, all tests expected to pass.
Phase 286C-5 progress: 3/4 steps complete
Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 05:18:06 +09:00
14ff126934
refactor(joinir): Phase 286C-5 Step 1 - CarrierInputsCollector Box extraction
...
Extract duplicated carrier_inputs collection logic into a dedicated Box:
**DRY Achievement**:
- Remove duplication between Return fallback (lines 740-763) and ExitJump
handling (lines 876-909)
- Single source of truth for carrier PHI fallback logic
- Reduced code size by ~30 lines (60 duplicated → 30 unified)
**Box Structure**:
- CarrierInputsCollector: Encapsulates carrier PHI collection from header
- Input: boundary + loop_header_phi_info
- Output: Vec<(carrier_name, block_id, value_id)>
- Filters ConditionOnly carriers automatically
- Handles DirectValue fallback to host_slot
**Files Modified**:
- instruction_rewriter.rs: Replace 2 inline blocks with Box calls
- carrier_inputs_collector.rs: New Box implementation (95 lines)
- rewriter/mod.rs: Export new module
**Contract Preserved**:
- Identical logic: ConditionOnly filter → header PHI → DirectValue fallback
- Same logging output format
- No behavior change, pure refactoring
Phase 286C-5 progress: 1/4 steps complete
Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 05:16:22 +09:00
bfc63b0e3c
fix(joinir): collect carrier_inputs for skippable ExitJump (Phase 286C-4.1)
...
After the Phase 286C-4 refactoring, carrier_inputs was not being
collected when a tail call's TailCallKind is ExitJump and the target
is a skippable continuation. This caused json_lint_vm to fail with:
[joinir/phase118/exit_phi/missing_carrier_phi]
exit_bindings carrier 'i' is missing from exit_carrier_phis
Root cause: The 3-stage pipeline refactoring separated Return→Jump
conversion (which collected carrier_inputs) from tail call handling.
When found_tail_call=true, the Return processing was skipped entirely,
but tail call handling didn't collect carrier_inputs.
Fix: Add carrier_inputs collection in the ExitJump (skippable) path
at lines 901-934. This mirrors the fallback logic from the Return
processing path.
Test results: 45/46 PASS (same as before refactoring)
- json_lint_vm: PASS (was FAIL)
- core_direct_array_oob_set_rc_vm: FAIL (unchanged, known issue)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 05:05:49 +09:00
e55665aa22
fix(joinir): verbose flag should not use env var (test pollution)
...
joinir_dev_enabled() was being used in verbose flags, causing debug
output to appear during smoke tests and polluting expected output.
Changed 3 locations from:
let verbose = debug || crate::config::env::joinir_dev_enabled()
To:
let verbose = debug
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 04:42:32 +09:00
5b74b3134a
refactor(orchestrator): Phase 286C-4 Step 4 - Complete 3-stage pipeline (~1150 lines removed)
...
Transformed merge_and_rewrite() from monolithic function to orchestrator:
**File Reduction**:
- Before: 2437 lines
- After: 1289 lines
- Removed: 1148 lines (47% reduction)
**New Architecture**:
- Stage 1: scan_blocks() - Read-only analysis (~200 lines)
- Stage 2: plan_rewrites() - Generate rewritten blocks (~550 lines)
- Stage 3: apply_rewrites() - Mutate builder (~160 lines)
**merge_and_rewrite() Now**:
- Metadata setup (~80 lines)
- Call 3-stage pipeline (~50 lines)
- DirectValue processing (~50 lines)
- Result building (~20 lines)
- Total: ~200 lines (down from ~1350)
**Benefits**:
- Clear separation of concerns (scan/plan/apply)
- No builder mutation until apply stage
- Easier to test and maintain
- Preserves all functionality
Build passes successfully. Phase 286C-4 complete.
2025-12-25 04:09:11 +09:00
8619ed07b9
feat(apply): Phase 286C-4 Step 3 - Implement apply_rewrites() (~160 lines)
...
Implemented apply_rewrites() stage to mutate MirBuilder:
**Block Addition**:
- Add all new blocks to current function
- Debug logging for blocks with 4+ instructions
**Boundary Injection** (~100 lines):
- Call BoundaryInjector::inject_boundary_copies()
- Build value_map for join_inputs and condition_bindings
- Collect PHI dst IDs from loop_header_phi_info
**Context Updates**:
- Add phi_inputs to ctx.exit_phi_inputs
- Add carrier_inputs to ctx.carrier_inputs
**Fix**:
- Use `ref args` in tail_call_target destructuring to avoid move error
Build passes successfully.
2025-12-25 04:04:50 +09:00
21e855d62a
feat(plan): Phase 286C-4 Step 2 - Complete plan_rewrites() (~370 lines)
...
Added parameter binding insertion and terminator conversion to plan_rewrites():
**Parameter Binding (~100 lines)**:
- Generate Copy instructions for tail call arguments
- Handle recursive/continuation/normal tail calls
- Skip bindings for loop header PHIs
- Record latch incoming for loop header PHI
**Terminator Conversion (~270 lines)**:
- Return → Jump conversion using ReturnConverterBox
- Exit value collection using ExitArgsCollectorBox
- Update result.phi_inputs and result.carrier_inputs
- Handle tail call Jump terminators with classification
Plan stage now generates complete RewrittenBlocks ready for apply stage.
Build passes with warnings only.
2025-12-25 04:01:44 +09:00
a78742b6d7
refactor(plan): Phase 286C-4 Step 2 - plan_rewrites() initial implementation
...
Extract block generation logic from merge_and_rewrite() into plan_rewrites():
- Function/block initialization (~70 lines)
- First pass: instruction filtering (~180 lines)
- Span synchronization (~20 lines)
Implemented:
- Instruction filtering using InstructionFilterBox
- Block ID remapping with local_block_map
- PHI dst protection for loop headers
- Deterministic function/block iteration
TODO (Step 2 continuation):
- Parameter binding insertion for tail calls (~100 lines)
- Terminator conversion logic (~270 lines)
- Exit PHI/carrier input collection
Current: ~290 lines extracted, target ~550 lines
Progress: Step 2/4 (plan_rewrites) partial
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 03:57:43 +09:00
a40ee8dda5
refactor(plan): Phase 286C-4 Step 1 - plan_helpers module
...
Create helper functions to support plan_rewrites() extraction:
- build_local_block_map(): Build block ID mapping for a function
- sync_spans(): Synchronize instruction spans after rewriting
These pure functions will be used by both the current monolithic
merge_and_rewrite() and the new plan_rewrites() function.
Progress: Step 1/4 (helpers) complete
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 03:53:42 +09:00
875c5e02fd
refactor(joinir): Phase 286C-2.1 Steps 3-5 - Extract scan logic, fix debug output
...
Step 3 Complete:
- Extract 94 lines of scan logic into scan_blocks()
- Populate RewritePlan with TailCallRewrite, ReturnConversion
- Read-only analysis phase (no mutations)
Steps 4-5 Partial:
- Document 3-stage pipeline architecture
- Infrastructure ready for future extraction
- Remaining extraction deferred to Phase 286C-2.2
Bug Fix:
- Remove joinir_dev_enabled() from verbose flag in scan_blocks()
- Prevents unintended debug output during tests
- Smoke tests now pass (45/46, 1 known fail unrelated)
Current State:
- scan_blocks(): 94 lines ✅ functional
- plan_rewrites(): stub (future extraction ~400 lines)
- apply_rewrites(): stub (future extraction ~200 lines)
- merge_and_rewrite(): ~1300 lines (target ~150 lines)
Build: cargo build --release ✅
Tests: 45/46 pass (1 known JoinIR pattern fail)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 03:45:16 +09:00
bfee1fd451
refactor(joinir): Phase 286C-2.1 Step 4-5 (Partial) - Document 3-stage pipeline structure
...
Steps 3-5 Summary:
- ✅ Step 3: scan_blocks() extraction complete (94 lines, functional)
- ⏳ Step 4-5: Documented plan/apply separation (requires future work)
What was achieved:
1. scan_blocks() now identifies tail calls and returns (read-only)
2. Clear orchestrator structure documented in merge_and_rewrite()
3. Strategic markers show what belongs to each stage
4. Foundation laid for future extraction of plan/apply logic
Current state:
- scan_blocks(): 94 lines (EXTRACTED ✅ )
- plan_rewrites(): Stub (main loop lines 380-1469 contains logic)
- apply_rewrites(): Stub (builder mutations intertwined with plan)
- merge_and_rewrite(): ~1300 lines (needs further refactoring)
Target state (future work):
- scan_blocks(): ~100 lines (identification only)
- plan_rewrites(): ~400 lines (block generation, no builder mutation)
- apply_rewrites(): ~200 lines (builder mutation only)
- merge_and_rewrite(): ~100-200 lines (orchestrator)
Why partial completion:
- Main loop (1400 lines) has highly intertwined plan + apply logic
- Safe extraction requires careful separation (multi-session work)
- Current commit achieves scan extraction + clear architecture docs
- Follows 80/20 rule: Working scan stage + clear path forward
Next steps (future):
- Extract parameter binding logic → plan_rewrites()
- Extract block generation logic → plan_rewrites()
- Extract builder.add_block() calls → apply_rewrites()
- Move PHI/carrier input collection → plan_rewrites()
Build: cargo build --release ✅
Tests: Existing tests pass (no behavior changes)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 03:31:43 +09:00
7e259ad334
refactor(joinir): Phase 286C-2.1 Step 3 - Extract scan logic into scan_blocks()
...
- Move instruction identification logic from main loop to scan_blocks()
- Populate RewritePlan with tail_calls, return_conversions
- Read-only analysis phase complete (no mutations, just detection)
- merge_and_rewrite() now calls scan_blocks() to identify rewrites
Scan logic extracted:
- Tail call detection: Check Call instructions for intra-module calls
- Return detection: Identify Return terminators for exit jump conversion
- Populate TailCallRewrite with target_func_name, target_block, args
- Populate ReturnConversion with return_value, has_exit_edge_args
Build: cargo build --release ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com >
2025-12-25 03:28:53 +09:00
f2458280c1
refactor(joinir): Phase 286C-2.1 Step 1 - Create 3-stage function stubs
...
- Create scan_blocks() stub (Stage 1: Read-only analysis)
- Create plan_rewrites() stub (Stage 2: Pure transformation)
- Create apply_rewrites() stub (Stage 3: Builder mutation)
- Add strategic markers for future extraction (STAGE 1/2/3)
- Document future orchestrator structure
Function Signatures:
- scan_blocks(&MirFunction, &JoinInlineBoundary, &RewriteContext) -> Result<RewritePlan, String>
- plan_rewrites(RewritePlan, &mut RewriteContext) -> Result<RewrittenBlocks, String>
- apply_rewrites(&mut MirBuilder, RewrittenBlocks) -> Result<(), String>
Benefits:
- Borrow checker safety: Sequential calling pattern (no overlapping borrows)
- Clear extraction targets: TODO markers identify logic to move
- Build stability: Stubs compile successfully, no functionality changes yet
- Foundation for incremental refactoring: Steps 2-5 can now proceed safely
Strategic Markers:
- Line 205: STAGE 1 marker (scan logic)
- Line 282: STAGE 2 marker (plan logic)
- Line 1355: STAGE 3 marker (apply logic)
- Line 1514: Future orchestrator structure
Status:
- Scaffolding: ✅ Complete (stubs in place)
- Extraction: ⏳ Next step (move logic from merge_and_rewrite to stubs)
Build: cargo build --release ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 03:19:06 +09:00
1a8a70cc99
refactor(joinir): Phase 286C-2.1 - 3-stage pipeline scaffolding (Scan/Plan/Apply)
...
- Create 3-stage pipeline architecture to solve borrow checker conflicts
- Stage 1 (ScanBox): Read-only scanning, identify rewrites (170 lines)
- Stage 2 (PlanBox): Pure transformation, generate new blocks (85 lines)
- Stage 3 (ApplyBox): Builder mutation only (75 lines)
New Files:
- scan_box.rs: Stage 1 - Read-only scan for RewritePlan
- plan_box.rs: Stage 2 - Transform RewritePlan → RewrittenBlocks
- apply_box.rs: Stage 3 - Apply RewrittenBlocks to MirBuilder
- C-2.1-pipeline-refactoring.md: Implementation guide
Data Structures:
- RewritePlan: Describes WHAT to rewrite (tail calls, returns, PHI, params)
- RewrittenBlocks: Contains HOW to rewrite (new blocks, replacements, inputs)
Benefits:
- Borrow checker safety: No overlapping mutable/immutable borrows
- Single responsibility: Each stage has one clear purpose
- Testability: Each stage can be unit tested independently
- Maintainability: Clear data flow, isolated changes
Status:
- Scaffolding: ✅ Complete (structure defined, stub implementations)
- Integration: ⏳ Next step (refactor merge_and_rewrite to use 3 stages)
Build: cargo build --release ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 03:05:44 +09:00
d81937e744
refactor(joinir): Phase 286C-2 - RewriteContext state consolidation
...
- Create RewriteContext struct to consolidate 11 scattered state variables
- Add 4 helper Boxes: InstructionFilterBox, ParameterBindingBox, ReturnConverterBox, TailCallDetectorBox
- Reduce instruction_rewriter.rs cognitive overhead via centralized state API
- All state mutations now go through consistent RewriteContext methods
Changes:
- New: rewrite_context.rs (94 lines) - State consolidation SSOT
- New: 4 helper Box modules (instruction_filter, parameter_binding, return_converter, tail_call_detector)
- Modified: instruction_rewriter.rs (1454 → 1421 lines)
- Modified: rewriter/mod.rs (export RewriteContext)
Benefits:
- State tracking simplified (11 variables → 1 context object)
- Clearer intent via API methods (add_exit_phi_input vs push)
- Foundation for future refactoring (Phase 286C-2.1: 3-stage pipeline)
- Zero functionality changes (pure refactoring)
Build: cargo build --release ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-25 02:58:36 +09:00
843d094598
refactor(joinir): Phase 286 P1-P3 - Boundary contract context enrichment
...
- P1: Add alloc_join_param()/alloc_join_local() API to JoinValueSpace
- Prevents future API misuse (thin wrappers with explicit "JoinIR" context)
- Updated docs with footnote-style number references
- P2: Enrich error context with host_fn for better diagnostics
- Added context: &str parameter to verify_boundary_contract_at_creation()
- Error format now shows: [merge_joinir_mir_blocks host=<fn> ...]
- P3: Add join-side info to error context (continuation count + boundary summary)
- Uses boundary.continuation_func_ids.len() for join=
- Adds [conts=X exits=Y conds=Z] suffix with fixed key names
- Enables faster debugging with log-searchable format
Error format: [merge_joinir_mir_blocks host=X join=Y [conts=A exits=B conds=C]]
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude <noreply@anthropic.com >
2025-12-25 02:15:40 +09:00
48048425e5
refactor(joinir): Phase 286C - Normalized module box modularization
...
Extract 3 boxes from normalized.rs (1,280 → 563 lines, 56% reduction):
- pattern1_normalizer.rs: Pattern 1 (simple while loops) normalization
- pattern2_normalizer.rs: Pattern 2/3/4 (loops with carriers) normalization
- env_layout_builder.rs: Environment layout construction utilities
Changes:
- Replace large function implementations with re-exports
- Add module declarations for new boxes
- Fix JoinInst import in shape_guard/mod.rs
- Maintain backward compatibility via legacy function wrappers
Acceptance:
- Build passes: cargo build --release
- Quick smoke tests: 17/18 PASS (1 pre-existing failure)
- No regressions in existing functionality
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude <noreply@anthropic.com >
2025-12-25 00:39:08 +09:00
f740e6542f
feat(phase285): Complete weak reference implementation (VM + LLVM harness)
...
Phase 285LLVM-1.1 to 1.4 + weak reference infrastructure:
**LLVM Harness** (Phase 285LLVM-1.x):
- 285LLVM-1.1: User Box registration & debug output
- 285LLVM-1.2: WeakRef basic operations (identity deferred)
- 285LLVM-1.3: InstanceBox field access (getField/setField)
- 285LLVM-1.4: print Handle resolution (type tag propagation)
**VM Runtime** (nyash_kernel):
- FFI functions: nyrt_weak_new, nyrt_weak_to_strong, nyrt_weak_drop
(crates/nyash_kernel/src/lib.rs: +209 lines)
- WeakRef plugin invoke support
(crates/nyash_kernel/src/plugin/invoke.rs: +250 lines)
- weak_handles.rs: WeakRef handle registry (NEW)
**LLVM Python Backend**:
- WeakRef instruction lowering (weak.py: NEW)
- Entry point integration (entry.py: +93 lines)
- Instruction lowering (instruction_lower.py: +13 lines)
- LLVM harness runner script (tools/run_llvm_harness.sh: NEW)
**MIR & Runtime**:
- WeakRef emission & validation
- MIR JSON export for weak instructions
- Environment variable support (NYASH_WEAK_*, HAKO_WEAK_*)
**Documentation**:
- CLAUDE.md: Phase 285 completion notes
- LANGUAGE_REFERENCE_2025.md: Weak reference syntax
- 10-Now.md & 30-Backlog.md: Phase 285 status updates
Total: +864 lines, 24 files changed
SSOT: docs/reference/language/lifecycle.md
Related: Phase 285W-Syntax-0, Phase 285W-Syntax-0.1
2025-12-25 00:11:34 +09:00
cc05c37ae3
feat(phase285w): Phase 285W-Syntax-0.1 - Reject weak(...) syntax (Parser-level Fail-Fast)
...
- Parser guard: Reject weak(...) with LPAREN check in parse_unary()
- Error: "Use 'weak expr', not 'weak(expr)'" (helpful message)
- Location: src/parser/expressions.rs:248-256
- MIR builder guard: Defense-in-depth for any bypassed cases
- Location: src/mir/builder/calls/build.rs:37-46
- Rejection test: apps/tests/phase285w_weak_call_rejected.hako
- Smoke test: phase285w_weak_call_rejected_vm.sh (PASS ✅ )
- Documentation:
- EBNF.md: Add ~ (BitNot) to unary operators
- lifecycle.md: Document weak(expr) as invalid syntax
- phase-285/README.md: Add Phase 285W-Syntax-0.1 entry
Test results: 5/6 phase285 tests PASS (1 unrelated failure)
SSOT: docs/reference/language/lifecycle.md
Closes: Phase 285W-Syntax-0.1
2025-12-25 00:04:55 +09:00
9227673ef7
feat(phase285w): Implement weak x unary operator syntax
...
Phase 285W-Syntax-0: Migrate weak reference syntax from function call
to unary operator for consistency and clarity.
**Changes**:
- Parser: Add UnaryOperator::Weak variant and parse_unary() handling
- MIR: Lower UnaryOp::Weak to emit_weak_new() (reuses existing path)
- AST: Add Weak to UnaryOperator enum + Display/JSON support
- Tests: Migrate 8 files from `weak(x)` to `weak x` syntax
- 7 .hako test files updated
- 1 smoke test shell script updated
- Cleanup: Remove obsolete weak(x) parser/MIR special cases
- Docs: Update Phase 285 README
**Syntax Change**:
- Old: `local w = weak(x)` (function call)
- New: `local w = weak x` (unary operator)
**Validation**: All migrated phase285* smoke tests pass (4/4 relevant)
**SSOT**: docs/reference/language/lifecycle.md
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2025-12-24 17:21:21 +09:00