fix(stage-b): Add sh_core using + Stage-1 JSON support

## Fixed Issues

1. compiler_stageb.hako: Added 'using sh_core as StringHelpers'
   - Resolved: call unresolved ParserStringUtilsBox.skip_ws/2
   - Root cause: using chain resolution not implemented
   - Workaround: explicit using in parent file

2. stageb_helpers.sh: Accept Stage-1 JSON format
   - Modified awk pattern to accept both formats:
     - MIR JSON v0: "version":0, "kind":"Program"
     - Stage-1 JSON: "type":"Program"

## Remaining Issues

ParserBox VM crash: Invalid value: use of undefined value ValueId(5839)
- Cause: Complex nested loops in parse_program2()
- Workaround: Minimal Stage-B (without ParserBox) works
- Fallback: Rust compiler path available

## Verification

 Minimal Stage-B outputs JSON correctly
 ParserBox execution crashes VM (SSA bug)

Co-Authored-By: Task先生 (AI Agent)
This commit is contained in:
nyash-codex
2025-11-02 08:23:43 +09:00
parent 91f3d82deb
commit 3aa0c3c875
15 changed files with 326 additions and 119 deletions

View File

@ -311,10 +311,16 @@ impl<'a> LoopBuilder<'a> {
let count = CALL_COUNT.fetch_add(1, Ordering::SeqCst);
let current_vars = self.get_current_variable_map();
// Debug: print current_vars before prepare
eprintln!("[DEBUG] prepare_loop_variables call #{}", count);
eprintln!("[DEBUG] current_vars = {:?}", current_vars);
eprintln!("[DEBUG] preheader_id = {:?}, header_id = {:?}", preheader_id, header_id);
// Debug: print current_vars before prepare (guarded by env)
let dbg = std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1");
if dbg {
eprintln!("[DEBUG] prepare_loop_variables call #{}", count);
eprintln!("[DEBUG] current_vars = {:?}", current_vars);
eprintln!(
"[DEBUG] preheader_id = {:?}, header_id = {:?}",
preheader_id, header_id
);
}
crate::mir::phi_core::loop_phi::save_block_snapshot(
&mut self.block_var_maps,
preheader_id,
@ -417,34 +423,66 @@ impl<'a> LoopBuilder<'a> {
dst: ValueId,
inputs: Vec<(BasicBlockId, ValueId)>,
) -> Result<(), String> {
eprintln!("[DEBUG] LoopBuilder::emit_phi_at_block_start: block={}, dst=%{}, inputs={:?}", block_id, dst.0, inputs);
let dbg = std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1");
if dbg {
eprintln!(
"[DEBUG] LoopBuilder::emit_phi_at_block_start: block={}, dst=%{}, inputs={:?}",
block_id, dst.0, inputs
);
}
// Phi nodeをブロックの先頭に挿入
if let Some(ref mut function) = self.parent_builder.current_function {
if let Some(block) = function.get_block_mut(block_id) {
eprintln!("[DEBUG] Block {} current instructions count: {}", block_id, block.instructions.len());
if dbg {
eprintln!(
"[DEBUG] Block {} current instructions count: {}",
block_id,
block.instructions.len()
);
}
// Phi命令は必ずブロックの先頭に配置
let phi_inst = MirInstruction::Phi { dst, inputs: inputs.clone() };
block.instructions.insert(0, phi_inst);
eprintln!("[DEBUG] ✅ PHI instruction inserted at position 0");
eprintln!("[DEBUG] Block {} after insert instructions count: {}", block_id, block.instructions.len());
if dbg {
eprintln!("[DEBUG] ✅ PHI instruction inserted at position 0");
eprintln!(
"[DEBUG] Block {} after insert instructions count: {}",
block_id,
block.instructions.len()
);
}
// Verify PHI is still there
if let Some(first_inst) = block.instructions.get(0) {
match first_inst {
MirInstruction::Phi { dst: phi_dst, .. } => {
eprintln!("[DEBUG] Verified: First instruction is PHI dst=%{}", phi_dst.0);
if dbg {
eprintln!(
"[DEBUG] Verified: First instruction is PHI dst=%{}",
phi_dst.0
);
}
}
other => {
eprintln!("[DEBUG] ⚠️ WARNING: First instruction is NOT PHI! It's {:?}", other);
if dbg {
eprintln!(
"[DEBUG] ⚠️ WARNING: First instruction is NOT PHI! It's {:?}",
other
);
}
}
}
}
Ok(())
} else {
eprintln!("[DEBUG] ❌ Block {} not found!", block_id);
if dbg {
eprintln!("[DEBUG] ❌ Block {} not found!", block_id);
}
Err(format!("Block {} not found", block_id))
}
} else {
eprintln!("[DEBUG] ❌ No current function!");
if dbg {
eprintln!("[DEBUG] ❌ No current function!");
}
Err("No current function".to_string())
}
}
@ -490,7 +528,12 @@ impl<'a> LoopBuilder<'a> {
}
fn update_variable(&mut self, name: String, value: ValueId) {
eprintln!("[DEBUG] LoopBuilder::update_variable: name={}, value=%{}", name, value.0);
if std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1") {
eprintln!(
"[DEBUG] LoopBuilder::update_variable: name={}, value=%{}",
name, value.0
);
}
self.parent_builder.variable_map.insert(name, value);
}
@ -749,18 +792,30 @@ impl crate::mir::phi_core::loop_phi::LoopPhiOps for LoopBuilder<'_> {
dst: ValueId,
src: ValueId,
) -> Result<(), String> {
eprintln!("[DEBUG] emit_copy_at_preheader: preheader={}, dst=%{}, src=%{}", preheader_id, dst.0, src.0);
let dbg = std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1");
if dbg {
eprintln!(
"[DEBUG] emit_copy_at_preheader: preheader={}, dst=%{}, src=%{}",
preheader_id, dst.0, src.0
);
}
if let Some(ref mut function) = self.parent_builder.current_function {
if let Some(block) = function.get_block_mut(preheader_id) {
eprintln!("[DEBUG] Adding Copy instruction to block {}", preheader_id);
if dbg {
eprintln!("[DEBUG] Adding Copy instruction to block {}", preheader_id);
}
block.add_instruction(MirInstruction::Copy { dst, src });
Ok(())
} else {
eprintln!("[DEBUG] ❌ Preheader block {} not found!", preheader_id);
if dbg {
eprintln!("[DEBUG] ❌ Preheader block {} not found!", preheader_id);
}
Err(format!("Preheader block {} not found", preheader_id))
}
} else {
eprintln!("[DEBUG] ❌ No current function!");
if dbg {
eprintln!("[DEBUG] ❌ No current function!");
}
Err("No current function".to_string())
}
}

View File

@ -254,7 +254,7 @@ pub fn try_parse_v1_to_module(json: &str) -> Result<Option<MirModule>, String> {
}
}
"mir_call" => {
// Minimal v1 mir_call support (Global only; print-family)
// Minimal v1 mir_call support (Global/Method/Constructor/Extern/Value + Closure creation)
// dst: optional
let dst_opt = inst.get("dst").and_then(|d| d.as_u64()).map(|v| ValueId::new(v as u32));
// args: array of value ids
@ -310,6 +310,153 @@ pub fn try_parse_v1_to_module(json: &str) -> Result<Option<MirModule>, String> {
});
if let Some(d) = dst_opt { max_value_id = max_value_id.max(d.as_u32() + 1); }
}
"Method" => {
// receiver: required u64, method: string, box_name: optional
let method = callee_obj
.get("method")
.and_then(Value::as_str)
.ok_or_else(|| format!(
"mir_call callee Method missing method in function '{}'",
func_name
))?
.to_string();
let recv_id = callee_obj
.get("receiver")
.and_then(Value::as_u64)
.ok_or_else(|| format!(
"mir_call callee Method missing receiver in function '{}'",
func_name
))? as u32;
let box_name = callee_obj
.get("box_name")
.and_then(Value::as_str)
.unwrap_or("")
.to_string();
block_ref.add_instruction(MirInstruction::Call {
dst: dst_opt,
func: ValueId::new(0),
callee: Some(crate::mir::definitions::Callee::Method {
box_name,
method,
receiver: Some(ValueId::new(recv_id)),
certainty: crate::mir::definitions::call_unified::TypeCertainty::Known,
}),
args: argv,
effects: EffectMask::PURE,
});
if let Some(d) = dst_opt { max_value_id = max_value_id.max(d.as_u32() + 1); }
}
"Closure" => {
// Closure creation (NewClosure equivalent)
// Requires dst; accepts optional params[], captures[[name, id]...], me_capture
let dst = dst_opt.ok_or_else(|| format!(
"mir_call Closure requires dst in function '{}'",
func_name
))?;
// params: array of strings (optional)
let mut params: Vec<String> = Vec::new();
if let Some(arr) = callee_obj.get("params").and_then(Value::as_array) {
for p in arr {
let s = p.as_str().ok_or_else(|| format!(
"mir_call Closure params must be strings in function '{}'",
func_name
))?;
params.push(s.to_string());
}
}
// captures: array of [name, id]
let mut captures: Vec<(String, ValueId)> = Vec::new();
if let Some(arr) = callee_obj.get("captures").and_then(Value::as_array) {
for e in arr {
let pair = e.as_array().ok_or_else(|| format!(
"mir_call Closure capture entry must be array in function '{}'",
func_name
))?;
if pair.len() != 2 {
return Err("mir_call Closure capture entry must have 2 elements".into());
}
let name = pair[0].as_str().ok_or_else(|| {
"mir_call Closure capture[0] must be string".to_string()
})?;
let id = pair[1].as_u64().ok_or_else(|| {
"mir_call Closure capture[1] must be integer".to_string()
})? as u32;
captures.push((name.to_string(), ValueId::new(id)));
}
}
// me_capture: optional u64
let me_capture = callee_obj
.get("me_capture")
.and_then(Value::as_u64)
.map(|v| ValueId::new(v as u32));
// Body is not carried in v1; create empty body vector as placeholder
block_ref.add_instruction(MirInstruction::NewClosure {
dst,
params,
body: Vec::new(),
captures,
me: me_capture,
});
max_value_id = max_value_id.max(dst.as_u32() + 1);
}
"Constructor" => {
// box_type: string, dst: required
let dst = dst_opt.ok_or_else(|| format!(
"mir_call Constructor requires dst in function '{}'",
func_name
))?;
let bt = callee_obj
.get("box_type")
.and_then(Value::as_str)
.ok_or_else(|| format!(
"mir_call Constructor missing box_type in function '{}'",
func_name
))?
.to_string();
block_ref.add_instruction(MirInstruction::NewBox {
dst,
box_type: bt,
args: argv.clone(),
});
max_value_id = max_value_id.max(dst.as_u32() + 1);
}
"Extern" => {
let name = callee_obj
.get("name")
.and_then(Value::as_str)
.ok_or_else(|| format!(
"mir_call callee Extern missing name in function '{}'",
func_name
))?
.to_string();
block_ref.add_instruction(MirInstruction::Call {
dst: dst_opt,
func: ValueId::new(0),
callee: Some(crate::mir::definitions::Callee::Extern(name)),
args: argv,
effects: EffectMask::IO,
});
if let Some(d) = dst_opt { max_value_id = max_value_id.max(d.as_u32() + 1); }
}
"Value" => {
// dynamic function value id: field 'func' (u64)
let fid = callee_obj
.get("func")
.and_then(Value::as_u64)
.ok_or_else(|| format!(
"mir_call callee Value missing func in function '{}'",
func_name
))? as u32;
block_ref.add_instruction(MirInstruction::Call {
dst: dst_opt,
func: ValueId::new(0),
callee: Some(crate::mir::definitions::Callee::Value(ValueId::new(fid))),
args: argv,
effects: EffectMask::PURE,
});
if let Some(d) = dst_opt { max_value_id = max_value_id.max(d.as_u32() + 1); }
}
other => {
return Err(format!(
"unsupported callee type '{}' in mir_call (Gate-C v1 bridge)",