vm: introduce ExecutionFrame for current_block/pc/last_result; use control_flow::record_transition; keep behavior identical
This commit is contained in:
34
CLAUDE.md
34
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相談
|
||||
|
||||
@ -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<Option<VMValue>>,
|
||||
/// Current function being executed
|
||||
current_function: Option<String>,
|
||||
/// Current basic block
|
||||
current_block: Option<BasicBlockId>,
|
||||
/// Frame state (current block, pc, last result)
|
||||
frame: ExecutionFrame,
|
||||
/// Previous basic block (for phi node resolution)
|
||||
previous_block: Option<BasicBlockId>,
|
||||
/// Program counter within current block
|
||||
pc: usize,
|
||||
/// Return value from last execution
|
||||
#[allow(dead_code)]
|
||||
last_result: Option<VMValue>,
|
||||
/// Simple field storage for objects (maps reference -> field -> value)
|
||||
pub(super) object_fields: HashMap<ValueId, HashMap<String, VMValue>>,
|
||||
/// 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
|
||||
|
||||
Reference in New Issue
Block a user