diff --git a/CLAUDE.md b/CLAUDE.md index 199d7060..a42efc93 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -449,6 +449,40 @@ NYASH_VM_DEBUG=1 # VM のみ **判断基準:3ヶ月後の自分が理解できるか?** +## ⚠️ Claude実行環境の既知のバグ(重要!) + +### 🐛 Bash Glob展開バグ(Issue #5811) + +**問題:** Claude Code v1.0.61-1.0.81でglob展開がパイプと一緒に使うと動作しない + +```bash +# ❌ 失敗するパターン(asteriskが"glob"という文字列に置換される) +ls *.md | wc -l # エラー: "ls: 'glob' にアクセスできません" +find . -name "*.rs" # エラー: "glob"になる +ls src/backend/vm_*.rs # エラー: "glob: そのようなファイルやディレクトリはありません" + +# ✅ 回避策1: bash -c でラップ +bash -c 'ls *.md | wc -l' +bash -c 'ls src/backend/vm_*.rs | xargs wc -l' + +# ✅ 回避策2: findコマンドを使う(最も確実) +find src/backend -name "vm_*.rs" -exec wc -l {} \; + +# ✅ 回避策3: 明示的にファイル名を列挙 +wc -l src/backend/vm.rs src/backend/vm_values.rs + +# ✅ 回避策4: ls + grepパターン +ls src/backend/ | grep "^vm_" | xargs -I{} wc -l src/backend/{} +``` + +**影響を受けるパターン:** +- `*.md`, `*.rs` - 通常のglob +- `src/*.py` - パス付きglob +- `file[12].md` - 文字クラス +- `file{1,2}.md` - ブレース展開 + +**根本原因:** Claudeのコマンド再構築機能のバグ(`pattern`ではなく`op`フィールドを使用) + ## 🔧 開発サポート ### 🤖 AI相談 diff --git a/src/backend/vm.rs b/src/backend/vm.rs index ea077e0c..6fbe7dd5 100644 --- a/src/backend/vm.rs +++ b/src/backend/vm.rs @@ -17,6 +17,8 @@ use crate::scope_tracker::ScopeTracker; use crate::instance_v2::InstanceBox; use super::vm_phi::LoopExecutor; use std::time::Instant; +use super::frame::ExecutionFrame; +use super::control_flow; // Phase 9.78a: Import necessary components for unified Box handling // TODO: Re-enable when interpreter refactoring is complete @@ -184,15 +186,10 @@ pub struct VM { values: Vec>, /// Current function being executed current_function: Option, - /// Current basic block - current_block: Option, + /// Frame state (current block, pc, last result) + frame: ExecutionFrame, /// Previous basic block (for phi node resolution) previous_block: Option, - /// Program counter within current block - pc: usize, - /// Return value from last execution - #[allow(dead_code)] - last_result: Option, /// Simple field storage for objects (maps reference -> field -> value) pub(super) object_fields: HashMap>, /// Class name mapping for objects (for visibility checks) @@ -250,10 +247,8 @@ impl VM { Self { values: Vec::new(), current_function: None, - current_block: None, + frame: ExecutionFrame::new(), previous_block: None, - pc: 0, - last_result: None, object_fields: HashMap::new(), object_class: HashMap::new(), object_internal: std::collections::HashSet::new(), @@ -277,10 +272,8 @@ impl VM { Self { values: Vec::new(), current_function: None, - current_block: None, + frame: ExecutionFrame::new(), previous_block: None, - pc: 0, - last_result: None, object_fields: HashMap::new(), object_class: HashMap::new(), object_internal: std::collections::HashSet::new(), @@ -348,10 +341,10 @@ impl VM { // Save current frame let saved_values = std::mem::take(&mut self.values); let saved_current_function = self.current_function.clone(); - let saved_current_block = self.current_block; + let saved_current_block = self.frame.current_block; let saved_previous_block = self.previous_block; - let saved_pc = self.pc; - let saved_last_result = self.last_result.clone(); + let saved_pc = self.frame.pc; + let saved_last_result = self.frame.last_result; // Bind parameters for (i, param_id) in function.params.iter().enumerate() { @@ -376,10 +369,10 @@ impl VM { // Restore frame self.values = saved_values; self.current_function = saved_current_function; - self.current_block = saved_current_block; + self.frame.current_block = saved_current_block; self.previous_block = saved_previous_block; - self.pc = saved_pc; - self.last_result = saved_last_result; + self.frame.pc = saved_pc; + self.frame.last_result = saved_last_result; result } @@ -401,7 +394,7 @@ impl VM { let block = function.get_block(current_block) .ok_or_else(|| VMError::InvalidBasicBlock(format!("Block {} not found", current_block)))?; - self.current_block = Some(current_block); + self.frame.current_block = Some(current_block); self.pc = 0; let mut next_block = None; @@ -431,10 +424,8 @@ impl VM { self.scope_tracker.pop_scope(); return Ok(return_value); } else if let Some(target) = next_block { - // Update previous block before jumping - self.previous_block = Some(current_block); - // Record the transition in loop executor - self.loop_executor.record_transition(current_block, target); + // Update previous block before jumping and record transition via control_flow helper + control_flow::record_transition(&mut self.previous_block, &mut self.loop_executor, current_block, target).ok(); current_block = target; } else { // Block ended without terminator - this shouldn't happen in well-formed MIR